[NET]: Make NAPI polling independent of struct net_device objects.
[cascardo/linux.git] / drivers / net / tg3.c
index 5ee1476..ef1e3d1 100644 (file)
@@ -64,8 +64,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.78"
-#define DRV_MODULE_RELDATE     "July 11, 2007"
+#define DRV_MODULE_VERSION     "3.81"
+#define DRV_MODULE_RELDATE     "September 5, 2007"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -574,7 +574,7 @@ static void tg3_restart_ints(struct tg3 *tp)
 static inline void tg3_netif_stop(struct tg3 *tp)
 {
        tp->dev->trans_start = jiffies; /* prevent tx timeout */
-       netif_poll_disable(tp->dev);
+       napi_disable(&tp->napi);
        netif_tx_disable(tp->dev);
 }
 
@@ -585,7 +585,7 @@ static inline void tg3_netif_start(struct tg3 *tp)
         * so long as all callers are assured to have free tx slots
         * (such as after tg3_init_hw)
         */
-       netif_poll_enable(tp->dev);
+       napi_enable(&tp->napi);
        tp->hw_status->status |= SD_STATUS_UPDATED;
        tg3_enable_ints(tp);
 }
@@ -3471,11 +3471,12 @@ next_pkt_nopost:
        return received;
 }
 
-static int tg3_poll(struct net_device *netdev, int *budget)
+static int tg3_poll(struct napi_struct *napi, int budget)
 {
-       struct tg3 *tp = netdev_priv(netdev);
+       struct tg3 *tp = container_of(napi, struct tg3, napi);
+       struct net_device *netdev = tp->dev;
        struct tg3_hw_status *sblk = tp->hw_status;
-       int done;
+       int work_done = 0;
 
        /* handle link change and other phy events */
        if (!(tp->tg3_flags &
@@ -3494,7 +3495,7 @@ static int tg3_poll(struct net_device *netdev, int *budget)
        if (sblk->idx[0].tx_consumer != tp->tx_cons) {
                tg3_tx(tp);
                if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) {
-                       netif_rx_complete(netdev);
+                       netif_rx_complete(netdev, napi);
                        schedule_work(&tp->reset_task);
                        return 0;
                }
@@ -3502,20 +3503,10 @@ static int tg3_poll(struct net_device *netdev, int *budget)
 
        /* run RX thread, within the bounds set by NAPI.
         * All RX "locking" is done by ensuring outside
-        * code synchronizes with dev->poll()
+        * code synchronizes with tg3->napi.poll()
         */
-       if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) {
-               int orig_budget = *budget;
-               int work_done;
-
-               if (orig_budget > netdev->quota)
-                       orig_budget = netdev->quota;
-
-               work_done = tg3_rx(tp, orig_budget);
-
-               *budget -= work_done;
-               netdev->quota -= work_done;
-       }
+       if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
+               work_done = tg3_rx(tp, budget);
 
        if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
                tp->last_tag = sblk->status_tag;
@@ -3524,13 +3515,12 @@ static int tg3_poll(struct net_device *netdev, int *budget)
                sblk->status &= ~SD_STATUS_UPDATED;
 
        /* if no more work, tell net stack and NIC we're done */
-       done = !tg3_has_work(tp);
-       if (done) {
-               netif_rx_complete(netdev);
+       if (!tg3_has_work(tp)) {
+               netif_rx_complete(netdev, napi);
                tg3_restart_ints(tp);
        }
 
-       return (done ? 0 : 1);
+       return work_done;
 }
 
 static void tg3_irq_quiesce(struct tg3 *tp)
@@ -3577,7 +3567,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id)
        prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
 
        if (likely(!tg3_irq_sync(tp)))
-               netif_rx_schedule(dev);         /* schedule NAPI poll */
+               netif_rx_schedule(dev, &tp->napi);
 
        return IRQ_HANDLED;
 }
@@ -3602,7 +3592,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id)
         */
        tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
        if (likely(!tg3_irq_sync(tp)))
-               netif_rx_schedule(dev);         /* schedule NAPI poll */
+               netif_rx_schedule(dev, &tp->napi);
 
        return IRQ_RETVAL(1);
 }
@@ -3644,7 +3634,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id)
        sblk->status &= ~SD_STATUS_UPDATED;
        if (likely(tg3_has_work(tp))) {
                prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
-               netif_rx_schedule(dev);         /* schedule NAPI poll */
+               netif_rx_schedule(dev, &tp->napi);
        } else {
                /* No work, shared interrupt perhaps?  re-enable
                 * interrupts, and flush that PCI write
@@ -3690,7 +3680,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
        tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
        if (tg3_irq_sync(tp))
                goto out;
-       if (netif_rx_schedule_prep(dev)) {
+       if (netif_rx_schedule_prep(dev, &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
@@ -3698,7 +3688,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
                 * if tg3_poll() is not scheduled.
                 */
                tp->last_tag = sblk->status_tag;
-               __netif_rx_schedule(dev);
+               __netif_rx_schedule(dev, &tp->napi);
        }
 out:
        return IRQ_RETVAL(handled);
@@ -3737,7 +3727,7 @@ static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
                tg3_full_unlock(tp);
                del_timer_sync(&tp->timer);
                tp->irq_sync = 0;
-               netif_poll_enable(tp->dev);
+               napi_enable(&tp->napi);
                dev_close(tp->dev);
                tg3_full_lock(tp, 0);
        }
@@ -3932,7 +3922,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        len = skb_headlen(skb);
 
        /* We are running in BH disabled context with netif_tx_lock
-        * and TX reclaim runs via tp->poll inside of a software
+        * and TX reclaim runs via tp->napi.poll inside of a software
         * interrupt.  Furthermore, IRQ processing runs lockless so we have
         * no IRQ context deadlocks to worry about either.  Rejoice!
         */
@@ -4087,7 +4077,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
        len = skb_headlen(skb);
 
        /* We are running in BH disabled context with netif_tx_lock
-        * and TX reclaim runs via tp->poll inside of a software
+        * and TX reclaim runs via tp->napi.poll inside of a software
         * interrupt.  Furthermore, IRQ processing runs lockless so we have
         * no IRQ context deadlocks to worry about either.  Rejoice!
         */
@@ -4847,6 +4837,59 @@ static int tg3_poll_fw(struct tg3 *tp)
        return 0;
 }
 
+/* Save PCI command register before chip reset */
+static void tg3_save_pci_state(struct tg3 *tp)
+{
+       u32 val;
+
+       pci_read_config_dword(tp->pdev, TG3PCI_COMMAND, &val);
+       tp->pci_cmd = val;
+}
+
+/* Restore PCI state after chip reset */
+static void tg3_restore_pci_state(struct tg3 *tp)
+{
+       u32 val;
+
+       /* Re-enable indirect register accesses. */
+       pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+                              tp->misc_host_ctrl);
+
+       /* Set MAX PCI retry to zero. */
+       val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
+       if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+           (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
+               val |= PCISTATE_RETRY_SAME_DMA;
+       pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
+
+       pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
+
+       /* Make sure PCI-X relaxed ordering bit is clear. */
+       pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
+       val &= ~PCIX_CAPS_RELAXED_ORDERING;
+       pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
+
+       if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
+               u32 val;
+
+               /* Chip reset on 5780 will reset MSI enable bit,
+                * so need to restore it.
+                */
+               if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+                       u16 ctrl;
+
+                       pci_read_config_word(tp->pdev,
+                                            tp->msi_cap + PCI_MSI_FLAGS,
+                                            &ctrl);
+                       pci_write_config_word(tp->pdev,
+                                             tp->msi_cap + PCI_MSI_FLAGS,
+                                             ctrl | PCI_MSI_FLAGS_ENABLE);
+                       val = tr32(MSGINT_MODE);
+                       tw32(MSGINT_MODE, val | MSGINT_MODE_ENABLE);
+               }
+       }
+}
+
 static void tg3_stop_fw(struct tg3 *);
 
 /* tp->lock is held. */
@@ -4863,6 +4906,12 @@ static int tg3_chip_reset(struct tg3 *tp)
         */
        tp->nvram_lock_cnt = 0;
 
+       /* GRC_MISC_CFG core clock reset will clear the memory
+        * enable bit in PCI register 4 and the MSI enable bit
+        * on some chips, so we save relevant registers here.
+        */
+       tg3_save_pci_state(tp);
+
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
@@ -4961,50 +5010,14 @@ static int tg3_chip_reset(struct tg3 *tp)
                pci_write_config_dword(tp->pdev, 0xd8, 0xf5000);
        }
 
-       /* Re-enable indirect register accesses. */
-       pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
-                              tp->misc_host_ctrl);
-
-       /* Set MAX PCI retry to zero. */
-       val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
-       if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
-           (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
-               val |= PCISTATE_RETRY_SAME_DMA;
-       pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
-
-       pci_restore_state(tp->pdev);
+       tg3_restore_pci_state(tp);
 
        tp->tg3_flags &= ~TG3_FLAG_CHIP_RESETTING;
 
-       /* Make sure PCI-X relaxed ordering bit is clear. */
-       pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
-       val &= ~PCIX_CAPS_RELAXED_ORDERING;
-       pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
-
-       if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
-               u32 val;
-
-               /* Chip reset on 5780 will reset MSI enable bit,
-                * so need to restore it.
-                */
-               if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
-                       u16 ctrl;
-
-                       pci_read_config_word(tp->pdev,
-                                            tp->msi_cap + PCI_MSI_FLAGS,
-                                            &ctrl);
-                       pci_write_config_word(tp->pdev,
-                                             tp->msi_cap + PCI_MSI_FLAGS,
-                                             ctrl | PCI_MSI_FLAGS_ENABLE);
-                       val = tr32(MSGINT_MODE);
-                       tw32(MSGINT_MODE, val | MSGINT_MODE_ENABLE);
-               }
-
+       val = 0;
+       if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
                val = tr32(MEMARB_MODE);
-               tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
-
-       } else
-               tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
+       tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
 
        if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) {
                tg3_stop_fw(tp);
@@ -7104,6 +7117,10 @@ static int tg3_open(struct net_device *dev)
                } else if (pci_enable_msi(tp->pdev) == 0) {
                        u32 msi_mode;
 
+                       /* Hardware bug - MSI won't work if INTX disabled. */
+                       if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
+                               pci_intx(tp->pdev, 1);
+
                        msi_mode = tr32(MSGINT_MODE);
                        tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
                        tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
@@ -7120,6 +7137,8 @@ static int tg3_open(struct net_device *dev)
                return err;
        }
 
+       napi_enable(&tp->napi);
+
        tg3_full_lock(tp, 0);
 
        err = tg3_init_hw(tp, 1);
@@ -7147,6 +7166,7 @@ static int tg3_open(struct net_device *dev)
        tg3_full_unlock(tp);
 
        if (err) {
+               napi_disable(&tp->napi);
                free_irq(tp->pdev->irq, dev);
                if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
                        pci_disable_msi(tp->pdev);
@@ -7172,6 +7192,8 @@ static int tg3_open(struct net_device *dev)
 
                        tg3_full_unlock(tp);
 
+                       napi_disable(&tp->napi);
+
                        return err;
                }
 
@@ -7433,6 +7455,7 @@ static int tg3_close(struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
 
+       napi_disable(&tp->napi);
        cancel_work_sync(&tp->reset_task);
 
        netif_stop_queue(dev);
@@ -9271,7 +9294,6 @@ static const struct ethtool_ops tg3_ethtool_ops = {
        .get_ethtool_stats      = tg3_get_ethtool_stats,
        .get_coalesce           = tg3_get_coalesce,
        .set_coalesce           = tg3_set_coalesce,
-       .get_perm_addr          = ethtool_op_get_perm_addr,
 };
 
 static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
@@ -11874,9 +11896,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        dev->set_mac_address = tg3_set_mac_addr;
        dev->do_ioctl = tg3_ioctl;
        dev->tx_timeout = tg3_tx_timeout;
-       dev->poll = tg3_poll;
+       netif_napi_add(dev, &tp->napi, tg3_poll, 64);
        dev->ethtool_ops = &tg3_ethtool_ops;
-       dev->weight = 64;
        dev->watchdog_timeo = TG3_TX_TIMEOUT;
        dev->change_mtu = tg3_change_mtu;
        dev->irq = pdev->irq;
@@ -11978,7 +11999,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
         */
        if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
            (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
-               pci_save_state(tp->pdev);
                tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
        }
@@ -12007,12 +12027,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        tg3_init_coal(tp);
 
-       /* Now that we have fully setup the chip, save away a snapshot
-        * of the PCI config space.  We need to restore this after
-        * GRC_MISC_CFG core clock resets and some resume events.
-        */
-       pci_save_state(tp->pdev);
-
        pci_set_drvdata(pdev, dev);
 
        err = register_netdev(dev);
@@ -12096,6 +12110,12 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
        struct tg3 *tp = netdev_priv(dev);
        int err;
 
+       /* PCI register 4 needs to be saved whether netif_running() or not.
+        * MSI address and data need to be saved if using MSI and
+        * netif_running().
+        */
+       pci_save_state(pdev);
+
        if (!netif_running(dev))
                return 0;
 
@@ -12115,9 +12135,6 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
        tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
        tg3_full_unlock(tp);
 
-       /* Save MSI address and data for resume.  */
-       pci_save_state(pdev);
-
        err = tg3_set_power_state(tp, pci_choose_state(pdev, state));
        if (err) {
                tg3_full_lock(tp, 0);
@@ -12145,15 +12162,20 @@ static int tg3_resume(struct pci_dev *pdev)
        struct tg3 *tp = netdev_priv(dev);
        int err;
 
+       pci_restore_state(tp->pdev);
+
        if (!netif_running(dev))
                return 0;
 
-       pci_restore_state(tp->pdev);
-
        err = tg3_set_power_state(tp, PCI_D0);
        if (err)
                return err;
 
+       /* Hardware bug - MSI won't work if INTX disabled. */
+       if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) &&
+           (tp->tg3_flags2 & TG3_FLG2_USING_MSI))
+               pci_intx(tp->pdev, 1);
+
        netif_device_attach(dev);
 
        tg3_full_lock(tp, 0);