]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/tg3.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6-omap-h63xx.git] / drivers / net / tg3.c
index eb86b059809b6ac4242bbf91d16d258e7e9a7ab5..e8e92c853e89dbc867c34c701f86a011ce969517 100644 (file)
@@ -69,8 +69,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.47"
-#define DRV_MODULE_RELDATE     "Dec 28, 2005"
+#define DRV_MODULE_VERSION     "3.49"
+#define DRV_MODULE_RELDATE     "Feb 2, 2006"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -1325,10 +1325,12 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
                val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1);
                tw32(0x7d00, val);
                if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
-                       tg3_nvram_lock(tp);
+                       int err;
+
+                       err = tg3_nvram_lock(tp);
                        tg3_halt_cpu(tp, RX_CPU_BASE);
-                       tw32_f(NVRAM_SWARB, SWARB_REQ_CLR0);
-                       tg3_nvram_unlock(tp);
+                       if (!err)
+                               tg3_nvram_unlock(tp);
                }
        }
 
@@ -3480,6 +3482,17 @@ static void tg3_reset_task(void *_data)
        struct tg3 *tp = _data;
        unsigned int restart_timer;
 
+       tg3_full_lock(tp, 0);
+       tp->tg3_flags |= TG3_FLAG_IN_RESET_TASK;
+
+       if (!netif_running(tp->dev)) {
+               tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
+               tg3_full_unlock(tp);
+               return;
+       }
+
+       tg3_full_unlock(tp);
+
        tg3_netif_stop(tp);
 
        tg3_full_lock(tp, 1);
@@ -3492,10 +3505,12 @@ static void tg3_reset_task(void *_data)
 
        tg3_netif_start(tp);
 
-       tg3_full_unlock(tp);
-
        if (restart_timer)
                mod_timer(&tp->timer, jiffies + 1);
+
+       tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
+
+       tg3_full_unlock(tp);
 }
 
 static void tg3_tx_timeout(struct net_device *dev)
@@ -4193,14 +4208,19 @@ static int tg3_nvram_lock(struct tg3 *tp)
        if (tp->tg3_flags & TG3_FLAG_NVRAM) {
                int i;
 
-               tw32(NVRAM_SWARB, SWARB_REQ_SET1);
-               for (i = 0; i < 8000; i++) {
-                       if (tr32(NVRAM_SWARB) & SWARB_GNT1)
-                               break;
-                       udelay(20);
+               if (tp->nvram_lock_cnt == 0) {
+                       tw32(NVRAM_SWARB, SWARB_REQ_SET1);
+                       for (i = 0; i < 8000; i++) {
+                               if (tr32(NVRAM_SWARB) & SWARB_GNT1)
+                                       break;
+                               udelay(20);
+                       }
+                       if (i == 8000) {
+                               tw32(NVRAM_SWARB, SWARB_REQ_CLR1);
+                               return -ENODEV;
+                       }
                }
-               if (i == 8000)
-                       return -ENODEV;
+               tp->nvram_lock_cnt++;
        }
        return 0;
 }
@@ -4208,8 +4228,12 @@ static int tg3_nvram_lock(struct tg3 *tp)
 /* tp->lock is held. */
 static void tg3_nvram_unlock(struct tg3 *tp)
 {
-       if (tp->tg3_flags & TG3_FLAG_NVRAM)
-               tw32_f(NVRAM_SWARB, SWARB_REQ_CLR1);
+       if (tp->tg3_flags & TG3_FLAG_NVRAM) {
+               if (tp->nvram_lock_cnt > 0)
+                       tp->nvram_lock_cnt--;
+               if (tp->nvram_lock_cnt == 0)
+                       tw32_f(NVRAM_SWARB, SWARB_REQ_CLR1);
+       }
 }
 
 /* tp->lock is held. */
@@ -4320,8 +4344,13 @@ static int tg3_chip_reset(struct tg3 *tp)
        void (*write_op)(struct tg3 *, u32, u32);
        int i;
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X))
+       if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) {
                tg3_nvram_lock(tp);
+               /* No matching tg3_nvram_unlock() after this because
+                * chip reset below will undo the nvram lock.
+                */
+               tp->nvram_lock_cnt = 0;
+       }
 
        /*
         * We must avoid the readl() that normally takes place.
@@ -4717,6 +4746,10 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
                       (offset == RX_CPU_BASE ? "RX" : "TX"));
                return -ENODEV;
        }
+
+       /* Clear firmware's nvram arbitration. */
+       if (tp->tg3_flags & TG3_FLAG_NVRAM)
+               tw32(NVRAM_SWARB, SWARB_REQ_CLR0);
        return 0;
 }
 
@@ -4736,7 +4769,7 @@ struct fw_info {
 static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_base,
                                 int cpu_scratch_size, struct fw_info *info)
 {
-       int err, i;
+       int err, lock_err, i;
        void (*write_op)(struct tg3 *, u32, u32);
 
        if (cpu_base == TX_CPU_BASE &&
@@ -4755,9 +4788,10 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b
        /* It is possible that bootcode is still loading at this point.
         * Get the nvram lock first before halting the cpu.
         */
-       tg3_nvram_lock(tp);
+       lock_err = tg3_nvram_lock(tp);
        err = tg3_halt_cpu(tp, cpu_base);
-       tg3_nvram_unlock(tp);
+       if (!lock_err)
+               tg3_nvram_unlock(tp);
        if (err)
                goto out;
 
@@ -6765,6 +6799,13 @@ static int tg3_close(struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
 
+       /* Calling flush_scheduled_work() may deadlock because
+        * linkwatch_event() may be on the workqueue and it will try to get
+        * the rtnl_lock which we are holding.
+        */
+       while (tp->tg3_flags & TG3_FLAG_IN_RESET_TASK)
+               msleep(1);
+
        netif_stop_queue(dev);
 
        del_timer_sync(&tp->timer);
@@ -8182,7 +8223,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                data[1] = 1;
        }
        if (etest->flags & ETH_TEST_FL_OFFLINE) {
-               int irq_sync = 0;
+               int err, irq_sync = 0;
 
                if (netif_running(dev)) {
                        tg3_netif_stop(tp);
@@ -8192,11 +8233,12 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                tg3_full_lock(tp, irq_sync);
 
                tg3_halt(tp, RESET_KIND_SUSPEND, 1);
-               tg3_nvram_lock(tp);
+               err = tg3_nvram_lock(tp);
                tg3_halt_cpu(tp, RX_CPU_BASE);
                if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
                        tg3_halt_cpu(tp, TX_CPU_BASE);
-               tg3_nvram_unlock(tp);
+               if (!err)
+                       tg3_nvram_unlock(tp);
 
                if (tg3_test_registers(tp) != 0) {
                        etest->flags |= ETH_TEST_FL_FAILED;
@@ -8588,7 +8630,11 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
                tp->tg3_flags |= TG3_FLAG_NVRAM;
 
-               tg3_nvram_lock(tp);
+               if (tg3_nvram_lock(tp)) {
+                       printk(KERN_WARNING PFX "%s: Cannot get nvarm lock, "
+                              "tg3_nvram_init failed.\n", tp->dev->name);
+                       return;
+               }
                tg3_enable_nvram_access(tp);
 
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
@@ -8686,7 +8732,9 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
        if (offset > NVRAM_ADDR_MSK)
                return -EINVAL;
 
-       tg3_nvram_lock(tp);
+       ret = tg3_nvram_lock(tp);
+       if (ret)
+               return ret;
 
        tg3_enable_nvram_access(tp);
 
@@ -8785,10 +8833,6 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
 
                offset = offset + (pagesize - page_off);
 
-               /* Nvram lock released by tg3_nvram_read() above,
-                * so need to get it again.
-                */
-               tg3_nvram_lock(tp);
                tg3_enable_nvram_access(tp);
 
                /*
@@ -8925,7 +8969,9 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
        else {
                u32 grc_mode;
 
-               tg3_nvram_lock(tp);
+               ret = tg3_nvram_lock(tp);
+               if (ret)
+                       return ret;
 
                tg3_enable_nvram_access(tp);
                if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
@@ -9362,6 +9408,15 @@ static int __devinit tg3_is_sun_570X(struct tg3 *tp)
                        return 0;
                if (venid == PCI_VENDOR_ID_SUN)
                        return 1;
+
+               /* TG3 chips onboard the SunBlade-2500 don't have the
+                * subsystem-vendor-id set to PCI_VENDOR_ID_SUN but they
+                * are distinguishable from non-Sun variants by being
+                * named "network" by the firmware.  Non-Sun cards will
+                * show up as being named "ethernet".
+                */
+               if (!strcmp(pcp->prom_name, "network"))
+                       return 1;
        }
        return 0;
 }
@@ -10854,6 +10909,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
        if (dev) {
                struct tg3 *tp = netdev_priv(dev);
 
+               flush_scheduled_work();
                unregister_netdev(dev);
                if (tp->regs) {
                        iounmap(tp->regs);
@@ -10875,6 +10931,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
        if (!netif_running(dev))
                return 0;
 
+       flush_scheduled_work();
        tg3_netif_stop(tp);
 
        del_timer_sync(&tp->timer);