Clean up duplicate includes in drivers/net/
[cascardo/linux.git] / drivers / net / netxen / netxen_nic_main.c
index 6167b58..af16553 100644 (file)
 #include "netxen_nic_phan_reg.h"
 
 #include <linux/dma-mapping.h>
-#include <linux/vmalloc.h>
 #include <net/ip.h>
 
 MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID);
 
-char netxen_nic_driver_name[] = "netxen-nic";
+char netxen_nic_driver_name[] = "netxen_nic";
 static char netxen_nic_driver_string[] = "NetXen Network Driver version "
     NETXEN_NIC_LINUX_VERSIONID;
 
@@ -54,8 +53,6 @@ static char netxen_nic_driver_string[] = "NetXen Network Driver version "
 #define NETXEN_ADAPTER_UP_MAGIC 777
 #define NETXEN_NIC_PEG_TUNE 0
 
-u8 nx_p2_id = NX_P2_C0;
-
 #define DMA_32BIT_MASK 0x00000000ffffffffULL
 #define DMA_35BIT_MASK 0x00000007ffffffffULL
 
@@ -70,7 +67,7 @@ static void netxen_tx_timeout(struct net_device *netdev);
 static void netxen_tx_timeout_task(struct work_struct *work);
 static void netxen_watchdog(unsigned long);
 static int netxen_handle_int(struct netxen_adapter *, struct net_device *);
-static int netxen_nic_poll(struct net_device *dev, int *budget);
+static int netxen_nic_poll(struct napi_struct *napi, int budget);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void netxen_nic_poll_controller(struct net_device *netdev);
 #endif
@@ -156,6 +153,103 @@ static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter
 #define        ADAPTER_LIST_SIZE 12
 int netxen_cards_found;
 
+static void netxen_nic_disable_int(struct netxen_adapter *adapter)
+{
+       uint32_t        mask = 0x7ff;
+       int retries = 32;
+
+       DPRINTK(1, INFO, "Entered ISR Disable \n");
+
+       switch (adapter->portnum) {
+       case 0:
+               writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_0));
+               break;
+       case 1:
+               writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_1));
+               break;
+       case 2:
+               writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_2));
+               break;
+       case 3:
+               writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_3));
+               break;
+       }
+
+       if (adapter->intr_scheme != -1 &&
+           adapter->intr_scheme != INTR_SCHEME_PERPORT)
+               writel(mask,PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_MASK));
+
+       /* Window = 0 or 1 */
+       if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
+               do {
+                       writel(0xffffffff,
+                              PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_TARGET_STATUS));
+                       mask = readl(pci_base_offset(adapter, ISR_INT_VECTOR));
+                       if (!(mask & 0x80))
+                               break;
+                       udelay(10);
+               } while (--retries);
+
+               if (!retries) {
+                       printk(KERN_NOTICE "%s: Failed to disable interrupt completely\n",
+                                       netxen_nic_driver_name);
+               }
+       }
+
+       DPRINTK(1, INFO, "Done with Disable Int\n");
+}
+
+static void netxen_nic_enable_int(struct netxen_adapter *adapter)
+{
+       u32 mask;
+
+       DPRINTK(1, INFO, "Entered ISR Enable \n");
+
+       if (adapter->intr_scheme != -1 &&
+               adapter->intr_scheme != INTR_SCHEME_PERPORT) {
+               switch (adapter->ahw.board_type) {
+               case NETXEN_NIC_GBE:
+                       mask  =  0x77b;
+                       break;
+               case NETXEN_NIC_XGBE:
+                       mask  =  0x77f;
+                       break;
+               default:
+                       mask  =  0x7ff;
+                       break;
+               }
+
+               writel(mask, PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_MASK));
+       }
+
+       switch (adapter->portnum) {
+       case 0:
+               writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_0));
+               break;
+       case 1:
+               writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_1));
+               break;
+       case 2:
+               writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_2));
+               break;
+       case 3:
+               writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_3));
+               break;
+       }
+
+       if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
+               mask = 0xbff;
+               if (adapter->intr_scheme != -1 &&
+                       adapter->intr_scheme != INTR_SCHEME_PERPORT) {
+                       writel(0X0, NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
+               }
+               writel(mask,
+                      PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_TARGET_MASK));
+       }
+
+       DPRINTK(1, INFO, "Done with enable Int\n");
+}
+
 /*
  * netxen_nic_probe()
  *
@@ -210,8 +304,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_disable_pdev;
 
        pci_set_master(pdev);
-       pci_read_config_byte(pdev, PCI_REVISION_ID, &nx_p2_id);
-       if (nx_p2_id == NX_P2_C1 &&
+       if (pdev->revision == NX_P2_C1 &&
            (pci_set_dma_mask(pdev, DMA_35BIT_MASK) == 0) &&
            (pci_set_consistent_dma_mask(pdev, DMA_35BIT_MASK) == 0)) {
                pci_using_dac = 1;
@@ -241,7 +334,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter->ahw.pdev = pdev;
        adapter->ahw.pci_func  = pci_func_id;
        spin_lock_init(&adapter->tx_lock);
-       spin_lock_init(&adapter->lock);
 
        /* remap phys address */
        mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
@@ -308,7 +400,16 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        adapter->netdev  = netdev;
        adapter->pdev    = pdev;
+
+       netif_napi_add(netdev, &adapter->napi,
+                      netxen_nic_poll, NETXEN_NETDEV_WEIGHT);
+
+       /* this will be read from FW later */
+       adapter->intr_scheme = -1;
+
+       /* This will be reset for mezz cards  */
        adapter->portnum = pci_func_id;
+       adapter->status   &= ~NETXEN_NETDEV_STATUS;
 
        netdev->open               = netxen_nic_open;
        netdev->stop               = netxen_nic_close;
@@ -323,8 +424,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        netxen_nic_change_mtu(netdev, netdev->mtu);
 
        SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
-       netdev->poll = netxen_nic_poll;
-       netdev->weight = NETXEN_NETDEV_WEIGHT;
 #ifdef CONFIG_NET_POLL_CONTROLLER
        netdev->poll_controller = netxen_nic_poll_controller;
 #endif
@@ -336,11 +435,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (pci_using_dac)
                netdev->features |= NETIF_F_HIGHDMA;
 
-       if (pci_enable_msi(pdev)) {
+       if (pci_enable_msi(pdev))
                adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;
-               printk(KERN_WARNING "%s: unable to allocate MSI interrupt"
-                      " error\n", netxen_nic_driver_name);
-       } else
+       else
                adapter->flags |= NETXEN_NIC_MSI_ENABLED;
 
        netdev->irq = pdev->irq;
@@ -355,13 +452,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* initialize the adapter */
        netxen_initialize_adapter_hw(adapter);
 
-#ifdef CONFIG_PPC
-       if ((adapter->ahw.boardcfg.board_type ==
-               NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) &&
-                       (pci_func_id == 2))
-                   goto err_out_free_adapter;
-#endif /* CONFIG_PPC */
-
        /*
         *  Adapter in our case is quad port so initialize it before
         *  initializing the ports
@@ -458,7 +548,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task);
        adapter->ahw.pdev = pdev;
        adapter->proc_cmd_buf_counter = 0;
-       adapter->ahw.revision_id = nx_p2_id;
+       adapter->ahw.revision_id = pdev->revision;
 
        /* make sure Window == 1 */
        netxen_nic_pci_change_crbwindow(adapter, 1);
@@ -509,22 +599,30 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                                        NETXEN_CAM_RAM(0x1fc)));
                if (val == 0x55555555) {
                    /* This is the first boot after power up */
+                   netxen_nic_read_w0(adapter, NETXEN_PCIE_REG(0x4), &val);
+                       if (!(val & 0x4)) {
+                               val |= 0x4;
+                               netxen_nic_write_w0(adapter, NETXEN_PCIE_REG(0x4), val);
+                               netxen_nic_read_w0(adapter, NETXEN_PCIE_REG(0x4), &val);
+                               if (!(val & 0x4))
+                                       printk(KERN_ERR "%s: failed to set MSI bit in PCI-e reg\n",
+                                                       netxen_nic_driver_name);
+                       }
                    val = readl(NETXEN_CRB_NORMALIZE(adapter,
                                        NETXEN_ROMUSB_GLB_SW_RESET));
                    printk(KERN_INFO"NetXen: read 0x%08x for reset reg.\n",val);
                    if (val != 0x80000f) {
                        /* clear the register for future unloads/loads */
-                       writel(0, NETXEN_CRB_NORMALIZE(adapter,
-                                               NETXEN_CAM_RAM(0x1fc)));
-                       printk(KERN_ERR "ERROR in NetXen HW init sequence.\n");
-                       err = -ENODEV;
-                       goto err_out_free_dev;
+                               writel(0, NETXEN_CRB_NORMALIZE(adapter,
+                                                       NETXEN_CAM_RAM(0x1fc)));
+                               printk(KERN_ERR "ERROR in NetXen HW init sequence.\n");
+                               err = -ENODEV;
+                               goto err_out_free_dev;
                    }
-
-                   /* clear the register for future unloads/loads */
-                   writel(0, NETXEN_CRB_NORMALIZE(adapter, 
-                                           NETXEN_CAM_RAM(0x1fc)));
                }
+
+               /* clear the register for future unloads/loads */
+               writel(0, NETXEN_CRB_NORMALIZE(adapter, NETXEN_CAM_RAM(0x1fc)));
                printk(KERN_INFO "State: 0x%0x\n",
                        readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)));
 
@@ -542,13 +640,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                                NETXEN_ROMUSB_GLB_PEGTUNE_DONE));
                /* Handshake with the card before we register the devices. */
                netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
-
-              /* leave the hw in the same state as reboot */
-              writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
-              netxen_pinit_from_rom(adapter, 0);
-              udelay(500);
-              netxen_load_firmware(adapter);
-              netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
        }
 
        /*
@@ -639,8 +730,8 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
        struct netxen_rx_buffer *buffer;
        struct netxen_recv_context *recv_ctx;
        struct netxen_rcv_desc_ctx *rcv_desc;
-       int i;
-       int ctxid, ring;
+       int i, ctxid, ring;
+       static int init_firmware_done = 0;
 
        adapter = pci_get_drvdata(pdev);
        if (adapter == NULL)
@@ -648,30 +739,17 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
 
        netdev = adapter->netdev;
 
-       netxen_nic_disable_int(adapter);
-       if (adapter->irq)
-               free_irq(adapter->irq, adapter);
-       
+       unregister_netdev(netdev);
+
        if (adapter->stop_port)
                adapter->stop_port(adapter);
 
-       if ((adapter->flags & NETXEN_NIC_MSI_ENABLED))
-               pci_disable_msi(pdev);
-
-       if (adapter->portnum == 0)
-               netxen_free_adapter_offload(adapter);
-
-       if(adapter->portnum == 0) {
-               /* leave the hw in the same state as reboot */
-               writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
-               netxen_pinit_from_rom(adapter, 0);
-               udelay(500);
-               netxen_load_firmware(adapter);
-               netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
-       }
+       netxen_nic_disable_int(adapter);
 
-       if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
+       if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
+               init_firmware_done++;
                netxen_free_hw_resources(adapter);
+       }
 
        for (ctxid = 0; ctxid < MAX_RCV_CTX; ++ctxid) {
                recv_ctx = &adapter->recv_ctx[ctxid];
@@ -691,10 +769,64 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
                }
        }
 
-       unregister_netdev(netdev);
-
        vfree(adapter->cmd_buf_arr);
 
+       if (adapter->portnum == 0) {
+               if (init_firmware_done) {
+                       i = 100;
+                       do {
+                               if (dma_watchdog_shutdown_request(adapter) == 1)
+                                       break;
+                               msleep(100);
+                               if (dma_watchdog_shutdown_poll_result(adapter) == 1)
+                                       break;
+                       } while (--i);
+
+                       if (i == 0)
+                               printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
+                                               netdev->name);
+
+                       /* clear the register for future unloads/loads */
+                       writel(0, NETXEN_CRB_NORMALIZE(adapter, NETXEN_CAM_RAM(0x1fc)));
+                       printk(KERN_INFO "State: 0x%0x\n",
+                               readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)));
+
+                       /* leave the hw in the same state as reboot */
+                       writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
+                       netxen_pinit_from_rom(adapter, 0);
+                       msleep(1);
+                       netxen_load_firmware(adapter);
+                       netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+               }
+
+               /* clear the register for future unloads/loads */
+               writel(0, NETXEN_CRB_NORMALIZE(adapter, NETXEN_CAM_RAM(0x1fc)));
+               printk(KERN_INFO "State: 0x%0x\n",
+                       readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)));
+
+               i = 100;
+               do {
+                       if (dma_watchdog_shutdown_request(adapter) == 1)
+                               break;
+                       msleep(100);
+                       if (dma_watchdog_shutdown_poll_result(adapter) == 1)
+                               break;
+               } while (--i);
+
+               if (i) {
+                       netxen_free_adapter_offload(adapter);
+               } else {
+                       printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
+                                       netdev->name);
+               }
+       }
+
+       if (adapter->irq)
+               free_irq(adapter->irq, adapter);
+
+       if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
+               pci_disable_msi(pdev);
+
        iounmap(adapter->ahw.db_base);
        iounmap(adapter->ahw.pci_base0);
        iounmap(adapter->ahw.pci_base1);
@@ -753,19 +885,22 @@ static int netxen_nic_open(struct net_device *netdev)
        if (!adapter->driver_mismatch)
                mod_timer(&adapter->watchdog_timer, jiffies);
 
+       napi_enable(&adapter->napi);
+
        netxen_nic_enable_int(adapter);
 
        /* Done here again so that even if phantom sw overwrote it,
         * we set it */
-       if (adapter->macaddr_set)
-               adapter->macaddr_set(adapter, netdev->dev_addr);
        if (adapter->init_port
            && adapter->init_port(adapter, adapter->portnum) != 0) {
            del_timer_sync(&adapter->watchdog_timer);
                printk(KERN_ERR "%s: Failed to initialize port %d\n",
                                netxen_nic_driver_name, adapter->portnum);
+               napi_disable(&adapter->napi);
                return -EIO;
        }
+       if (adapter->macaddr_set)
+               adapter->macaddr_set(adapter, netdev->dev_addr);
 
        netxen_nic_set_link_parameters(adapter);
 
@@ -791,6 +926,9 @@ static int netxen_nic_close(struct net_device *netdev)
 
        netif_carrier_off(netdev);
        netif_stop_queue(netdev);
+       napi_disable(&adapter->napi);
+
+       netxen_nic_disable_int(adapter);
 
        cmd_buff = adapter->cmd_buf_arr;
        for (i = 0; i < adapter->max_tx_desc_count; i++) {
@@ -798,7 +936,7 @@ static int netxen_nic_close(struct net_device *netdev)
                if (buffrag->dma) {
                        pci_unmap_single(adapter->pdev, buffrag->dma,
                                         buffrag->length, PCI_DMA_TODEVICE);
-                       buffrag->dma = (u64) NULL;
+                       buffrag->dma = 0ULL;
                }
                for (j = 0; j < cmd_buff->frag_count; j++) {
                        buffrag++;
@@ -806,7 +944,7 @@ static int netxen_nic_close(struct net_device *netdev)
                                pci_unmap_page(adapter->pdev, buffrag->dma,
                                               buffrag->length, 
                                               PCI_DMA_TODEVICE);
-                               buffrag->dma = (u64) NULL;
+                               buffrag->dma = 0ULL;
                        }
                }
                /* Free the skb we received in netxen_nic_xmit_frame */
@@ -816,8 +954,10 @@ static int netxen_nic_close(struct net_device *netdev)
                }
                cmd_buff++;
        }
-       FLUSH_SCHEDULED_WORK();
-       del_timer_sync(&adapter->watchdog_timer);
+       if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
+               FLUSH_SCHEDULED_WORK();
+               del_timer_sync(&adapter->watchdog_timer);
+       }
 
        return 0;
 }
@@ -1086,15 +1226,12 @@ static void netxen_tx_timeout_task(struct work_struct *work)
 {
        struct netxen_adapter *adapter = 
                container_of(work, struct netxen_adapter, tx_timeout_task);
-       unsigned long flags;
 
        printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
               netxen_nic_driver_name, adapter->netdev->name);
 
-       spin_lock_irqsave(&adapter->lock, flags);
        netxen_nic_close(adapter->netdev);
        netxen_nic_open(adapter->netdev);
-       spin_unlock_irqrestore(&adapter->lock, flags);
        adapter->netdev->trans_start = jiffies;
        netif_wake_queue(adapter->netdev);
 }
@@ -1107,36 +1244,18 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
        DPRINTK(INFO, "Entered handle ISR\n");
        adapter->stats.ints++;
 
-       if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
-               int count = 0;
-               u32 mask;
-               u32 our_int = 0;
-               our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
-               /* not our interrupt */
-               if ((our_int & (0x80 << adapter->portnum)) == 0)
-                       return ret;
-               netxen_nic_disable_int(adapter);
-               /* Window = 0 or 1 */
-               do {
-                       writel(0xffffffff, PCI_OFFSET_SECOND_RANGE(adapter,
-                                               ISR_INT_TARGET_STATUS));
-                       mask = readl(pci_base_offset(adapter, ISR_INT_VECTOR));
-               } while (((mask & 0x80) != 0) && (++count < 32));
-               if ((mask & 0x80) != 0)
-                       printk("Could not disable interrupt completely\n");
-
-       }
+       netxen_nic_disable_int(adapter);
 
        if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) {
-               if (netif_rx_schedule_prep(netdev)) {
+               if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
                        /*
                         * Interrupts are already disabled.
                         */
-                       __netif_rx_schedule(netdev);
+                       __netif_rx_schedule(netdev, &adapter->napi);
                } else {
                        static unsigned int intcount = 0;
                        if ((++intcount & 0xfff) == 0xfff)
-                               printk(KERN_ERR
+                               DPRINTK(KERN_ERR
                                       "%s: %s interrupt %d while in poll\n",
                                       netxen_nic_driver_name, netdev->name,
                                       intcount);
@@ -1160,6 +1279,7 @@ irqreturn_t netxen_intr(int irq, void *data)
 {
        struct netxen_adapter *adapter;
        struct net_device *netdev;
+       u32 our_int = 0;
 
        if (unlikely(!irq)) {
                return IRQ_NONE;        /* Not our interrupt */
@@ -1167,21 +1287,35 @@ irqreturn_t netxen_intr(int irq, void *data)
 
        adapter = (struct netxen_adapter *)data;
        netdev  = adapter->netdev;
-       /* process our status queue (for all 4 ports) */
+
+       if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
+               our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
+               /* not our interrupt */
+               if ((our_int & (0x80 << adapter->portnum)) == 0)
+                       return IRQ_NONE;
+       }
+
+       if (adapter->intr_scheme == INTR_SCHEME_PERPORT) {
+               /* claim interrupt */
+               if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
+                       writel(our_int & ~((u32)(0x80 << adapter->portnum)),
+                       NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
+               }
+       }
+
        if (netif_running(netdev))
                netxen_handle_int(adapter, netdev);
 
        return IRQ_HANDLED;
 }
 
-static int netxen_nic_poll(struct net_device *netdev, int *budget)
+static int netxen_nic_poll(struct napi_struct *napi, int budget)
 {
-       struct netxen_adapter *adapter = netdev_priv(netdev);
-       int work_to_do = min(*budget, netdev->quota);
+       struct netxen_adapter *adapter = container_of(napi, struct netxen_adapter, napi);
+       struct net_device *netdev = adapter->netdev;
        int done = 1;
        int ctx;
-       int this_work_done;
-       int work_done = 0;
+       int work_done;
 
        DPRINTK(INFO, "polling for %d descriptors\n", *budget);
 
@@ -1199,16 +1333,11 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget)
                 * packets are on one context, it gets only half of the quota,
                 * and ends up not processing it.
                 */
-               this_work_done = netxen_process_rcv_ring(adapter, ctx,
-                                                        work_to_do /
-                                                        MAX_RCV_CTX);
-               work_done += this_work_done;
+               work_done += netxen_process_rcv_ring(adapter, ctx,
+                                                    budget / MAX_RCV_CTX);
        }
 
-       netdev->quota -= work_done;
-       *budget -= work_done;
-
-       if (work_done >= work_to_do && netxen_nic_rx_has_work(adapter) != 0)
+       if (work_done >= budget && netxen_nic_rx_has_work(adapter) != 0)
                done = 0;
 
        if (netxen_process_cmd_ring((unsigned long)adapter) == 0)
@@ -1217,11 +1346,11 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget)
        DPRINTK(INFO, "new work_done: %d work_to_do: %d\n",
                work_done, work_to_do);
        if (done) {
-               netif_rx_complete(netdev);
+               netif_rx_complete(netdev, napi);
                netxen_nic_enable_int(adapter);
        }
 
-       return !done;
+       return work_done;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1258,6 +1387,7 @@ static void __exit netxen_exit_module(void)
        /*
         * Wait for some time to allow the dma to drain, if any.
         */
+       msleep(100);
        pci_unregister_driver(&netxen_driver);
        destroy_workqueue(netxen_workq);
 }