]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/net/tg3.c
tg3: Handle NVRAM absent cases
[net-next-2.6.git] / drivers / net / tg3.c
index 6a736dda3ee2e199ef176b2f4ae7ec96fdbc8d25..9b04954b6943ffe3ff73e90c8ba8bf0054b9e7e9 100644 (file)
@@ -2190,7 +2190,14 @@ static int tg3_nvram_read_using_eeprom(struct tg3 *tp,
        if (!(tmp & EEPROM_ADDR_COMPLETE))
                return -EBUSY;
 
-       *val = tr32(GRC_EEPROM_DATA);
+       tmp = tr32(GRC_EEPROM_DATA);
+
+       /*
+        * The data will always be opposite the native endian
+        * format.  Perform a blind byteswap to compensate.
+        */
+       *val = swab32(tmp);
+
        return 0;
 }
 
@@ -4649,6 +4656,7 @@ static int tg3_poll(struct napi_struct *napi, int budget)
                         * so we must read it before checking for more work.
                         */
                        tp->last_tag = sblk->status_tag;
+                       tp->last_irq_tag = tp->last_tag;
                        rmb();
                } else
                        sblk->status &= ~SD_STATUS_UPDATED;
@@ -4804,7 +4812,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
         * Reading the PCI State register will confirm whether the
         * interrupt is ours and will flush the status block.
         */
-       if (unlikely(sblk->status_tag == tp->last_tag)) {
+       if (unlikely(sblk->status_tag == tp->last_irq_tag)) {
                if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) ||
                    (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
                        handled = 0;
@@ -4824,18 +4832,22 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
         * excessive spurious interrupts can be worse in some cases.
         */
        tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
+
+       /*
+        * In a shared interrupt configuration, sometimes other devices'
+        * interrupts will scream.  We record the current status tag here
+        * so that the above check can report that the screaming interrupts
+        * are unhandled.  Eventually they will be silenced.
+        */
+       tp->last_irq_tag = sblk->status_tag;
+
        if (tg3_irq_sync(tp))
                goto out;
-       if (napi_schedule_prep(&tp->napi)) {
-               prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
-               /* Update last_tag to mark that this status has been
-                * seen. Because interrupt may be shared, we may be
-                * racing with tg3_poll(), so only update last_tag
-                * if tg3_poll() is not scheduled.
-                */
-               tp->last_tag = sblk->status_tag;
-               __napi_schedule(&tp->napi);
-       }
+
+       prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
+
+       napi_schedule(&tp->napi);
+
 out:
        return IRQ_RETVAL(handled);
 }
@@ -6149,6 +6161,7 @@ static int tg3_chip_reset(struct tg3 *tp)
                tp->hw_status->status_tag = 0;
        }
        tp->last_tag = 0;
+       tp->last_irq_tag = 0;
        smp_mb();
        synchronize_irq(tp->pdev->irq);
 
@@ -7131,7 +7144,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        udelay(100);
 
        tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0);
-       tp->last_tag = 0;
 
        if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
                tw32_f(DMAC_MODE, DMAC_MODE_ENABLE);
@@ -8532,6 +8544,9 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        u32 i, offset, len, b_offset, b_count;
        __be32 val;
 
+       if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM)
+               return -EINVAL;
+
        if (tp->link_config.phy_is_low_power)
                return -EAGAIN;
 
@@ -8597,7 +8612,8 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        if (tp->link_config.phy_is_low_power)
                return -EAGAIN;
 
-       if (eeprom->magic != TG3_EEPROM_MAGIC)
+       if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
+           eeprom->magic != TG3_EEPROM_MAGIC)
                return -EINVAL;
 
        offset = eeprom->offset;
@@ -9194,6 +9210,9 @@ static int tg3_test_nvram(struct tg3 *tp)
        __be32 *buf;
        int i, j, k, err = 0, size;
 
+       if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM)
+               return 0;
+
        if (tg3_nvram_read(tp, 0, &magic) != 0)
                return -EIO;
 
@@ -10176,7 +10195,8 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp)
 {
        u32 val;
 
-       if (tg3_nvram_read(tp, 0, &val) != 0)
+       if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
+           tg3_nvram_read(tp, 0, &val) != 0)
                return;
 
        /* Selfboot format */
@@ -10558,6 +10578,7 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp)
                }
                break;
        default:
+               tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM;
                return;
        }
 
@@ -10663,7 +10684,13 @@ static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
 
                memcpy(&data, buf + i, 4);
 
-               tw32(GRC_EEPROM_DATA, be32_to_cpu(data));
+               /*
+                * The SEEPROM interface expects the data to always be opposite
+                * the native endian format.  We accomplish this by reversing
+                * all the operations that would have been performed on the
+                * data from a call to tg3_nvram_read_be32().
+                */
+               tw32(GRC_EEPROM_DATA, swab32(be32_to_cpu(data)));
 
                val = tr32(GRC_EEPROM_ADDR);
                tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE);
@@ -11352,7 +11379,8 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
        unsigned int i;
        u32 magic;
 
-       if (tg3_nvram_read(tp, 0x0, &magic))
+       if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
+           tg3_nvram_read(tp, 0x0, &magic))
                goto out_not_found;
 
        if (magic == TG3_EEPROM_MAGIC) {
@@ -11444,6 +11472,15 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
 out_not_found:
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
                strcpy(tp->board_part_number, "BCM95906");
+       else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 &&
+                tp->pdev->device == TG3PCI_DEVICE_TIGON3_57780)
+               strcpy(tp->board_part_number, "BCM57780");
+       else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 &&
+                tp->pdev->device == TG3PCI_DEVICE_TIGON3_57760)
+               strcpy(tp->board_part_number, "BCM57760");
+       else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 &&
+                tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790)
+               strcpy(tp->board_part_number, "BCM57790");
        else
                strcpy(tp->board_part_number, "none");
 }
@@ -11654,6 +11691,14 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
 {
        u32 val;
 
+       if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) {
+               tp->fw_ver[0] = 's';
+               tp->fw_ver[1] = 'b';
+               tp->fw_ver[2] = '\0';
+
+               return;
+       }
+
        if (tg3_nvram_read(tp, 0, &val))
                return;
 
@@ -12441,7 +12486,8 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
        }
        if (!addr_ok) {
                /* Next, try NVRAM. */
-               if (!tg3_nvram_read_be32(tp, mac_offset + 0, &hi) &&
+               if (!(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) &&
+                   !tg3_nvram_read_be32(tp, mac_offset + 0, &hi) &&
                    !tg3_nvram_read_be32(tp, mac_offset + 4, &lo)) {
                        memcpy(&dev->dev_addr[0], ((char *)&hi) + 2, 2);
                        memcpy(&dev->dev_addr[2], (char *)&lo, sizeof(lo));