e1000: fix loss of multicast packets
[safe/jmp/linux-2.6] / drivers / net / forcedeth.c
index 74511f7..a858c6f 100644 (file)
@@ -39,7 +39,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION              "0.63"
+#define FORCEDETH_VERSION              "0.64"
 #define DRV_NAME                       "forcedeth"
 
 #include <linux/module.h>
@@ -128,7 +128,7 @@ enum {
  * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
  */
        NvRegPollingInterval = 0x00c,
-#define NVREG_POLL_DEFAULT_THROUGHPUT  970 /* backup tx cleanup if loop max reached */
+#define NVREG_POLL_DEFAULT_THROUGHPUT  65535 /* backup tx cleanup if loop max reached */
 #define NVREG_POLL_DEFAULT_CPU 13
        NvRegMSIMap0 = 0x020,
        NvRegMSIMap1 = 0x024,
@@ -463,7 +463,7 @@ union ring_type {
 /* General driver defaults */
 #define NV_WATCHDOG_TIMEO      (5*HZ)
 
-#define RX_RING_DEFAULT                128
+#define RX_RING_DEFAULT                512
 #define TX_RING_DEFAULT                256
 #define RX_RING_MIN            128
 #define TX_RING_MIN            64
@@ -593,6 +593,9 @@ union ring_type {
 
 #define NV_TX_LIMIT_COUNT     16
 
+#define NV_DYNAMIC_THRESHOLD        4
+#define NV_DYNAMIC_MAX_QUIET_COUNT  2048
+
 /* statistics */
 struct nv_ethtool_str {
        char name[ETH_GSTRING_LEN];
@@ -750,6 +753,7 @@ struct fe_priv {
        u16 gigabit;
        int intr_test;
        int recover_error;
+       int quiet_count;
 
        /* General data: RO fields */
        dma_addr_t ring_addr;
@@ -832,7 +836,7 @@ struct fe_priv {
  * Maximum number of loops until we assume that a bit in the irq mask
  * is stuck. Overridable with module param.
  */
-static int max_interrupt_work = 15;
+static int max_interrupt_work = 4;
 
 /*
  * Optimization can be either throuput mode or cpu mode
@@ -842,9 +846,10 @@ static int max_interrupt_work = 15;
  */
 enum {
        NV_OPTIMIZATION_MODE_THROUGHPUT,
-       NV_OPTIMIZATION_MODE_CPU
+       NV_OPTIMIZATION_MODE_CPU,
+       NV_OPTIMIZATION_MODE_DYNAMIC
 };
-static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT;
+static int optimization_mode = NV_OPTIMIZATION_MODE_DYNAMIC;
 
 /*
  * Poll interval for timer irq
@@ -2397,14 +2402,16 @@ static inline void nv_tx_flip_ownership(struct net_device *dev)
  *
  * Caller must own np->lock.
  */
-static void nv_tx_done(struct net_device *dev)
+static int nv_tx_done(struct net_device *dev, int limit)
 {
        struct fe_priv *np = netdev_priv(dev);
        u32 flags;
+       int tx_work = 0;
        struct ring_desc* orig_get_tx = np->get_tx.orig;
 
        while ((np->get_tx.orig != np->put_tx.orig) &&
-              !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID)) {
+              !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID) &&
+              (tx_work < limit)) {
 
                dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n",
                                        dev->name, flags);
@@ -2430,6 +2437,7 @@ static void nv_tx_done(struct net_device *dev)
                                }
                                dev_kfree_skb_any(np->get_tx_ctx->skb);
                                np->get_tx_ctx->skb = NULL;
+                               tx_work++;
                        }
                } else {
                        if (flags & NV_TX2_LASTPACKET) {
@@ -2447,6 +2455,7 @@ static void nv_tx_done(struct net_device *dev)
                                }
                                dev_kfree_skb_any(np->get_tx_ctx->skb);
                                np->get_tx_ctx->skb = NULL;
+                               tx_work++;
                        }
                }
                if (unlikely(np->get_tx.orig++ == np->last_tx.orig))
@@ -2458,17 +2467,19 @@ static void nv_tx_done(struct net_device *dev)
                np->tx_stop = 0;
                netif_wake_queue(dev);
        }
+       return tx_work;
 }
 
-static void nv_tx_done_optimized(struct net_device *dev, int limit)
+static int nv_tx_done_optimized(struct net_device *dev, int limit)
 {
        struct fe_priv *np = netdev_priv(dev);
        u32 flags;
+       int tx_work = 0;
        struct ring_desc_ex* orig_get_tx = np->get_tx.ex;
 
        while ((np->get_tx.ex != np->put_tx.ex) &&
               !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) &&
-              (limit-- > 0)) {
+              (tx_work < limit)) {
 
                dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n",
                                        dev->name, flags);
@@ -2492,6 +2503,7 @@ static void nv_tx_done_optimized(struct net_device *dev, int limit)
 
                        dev_kfree_skb_any(np->get_tx_ctx->skb);
                        np->get_tx_ctx->skb = NULL;
+                       tx_work++;
 
                        if (np->tx_limit) {
                                nv_tx_flip_ownership(dev);
@@ -2506,6 +2518,7 @@ static void nv_tx_done_optimized(struct net_device *dev, int limit)
                np->tx_stop = 0;
                netif_wake_queue(dev);
        }
+       return tx_work;
 }
 
 /*
@@ -2578,7 +2591,7 @@ static void nv_tx_timeout(struct net_device *dev)
 
        /* 2) check that the packets were not sent already: */
        if (!nv_optimized(np))
-               nv_tx_done(dev);
+               nv_tx_done(dev, np->tx_ring_size);
        else
                nv_tx_done_optimized(dev, np->tx_ring_size);
 
@@ -3409,49 +3422,71 @@ static void nv_msi_workaround(struct fe_priv *np)
        }
 }
 
+static inline int nv_change_interrupt_mode(struct net_device *dev, int total_work)
+{
+       struct fe_priv *np = netdev_priv(dev);
+
+       if (optimization_mode == NV_OPTIMIZATION_MODE_DYNAMIC) {
+               if (total_work > NV_DYNAMIC_THRESHOLD) {
+                       /* transition to poll based interrupts */
+                       np->quiet_count = 0;
+                       if (np->irqmask != NVREG_IRQMASK_CPU) {
+                               np->irqmask = NVREG_IRQMASK_CPU;
+                               return 1;
+                       }
+               } else {
+                       if (np->quiet_count < NV_DYNAMIC_MAX_QUIET_COUNT) {
+                               np->quiet_count++;
+                       } else {
+                               /* reached a period of low activity, switch
+                                  to per tx/rx packet interrupts */
+                               if (np->irqmask != NVREG_IRQMASK_THROUGHPUT) {
+                                       np->irqmask = NVREG_IRQMASK_THROUGHPUT;
+                                       return 1;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
 static irqreturn_t nv_nic_irq(int foo, void *data)
 {
        struct net_device *dev = (struct net_device *) data;
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
-       int i;
+#ifndef CONFIG_FORCEDETH_NAPI
+       int total_work = 0;
+       int loop_count = 0;
+#endif
 
        dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name);
 
-       for (i=0; ; i++) {
-               if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
-                       np->events = readl(base + NvRegIrqStatus);
-                       writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
-               } else {
-                       np->events = readl(base + NvRegMSIXIrqStatus);
-                       writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
-               }
-               dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events);
-               if (!(np->events & np->irqmask))
-                       break;
-
-               nv_msi_workaround(np);
+       if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+               np->events = readl(base + NvRegIrqStatus);
+               writel(np->events, base + NvRegIrqStatus);
+       } else {
+               np->events = readl(base + NvRegMSIXIrqStatus);
+               writel(np->events, base + NvRegMSIXIrqStatus);
+       }
+       dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events);
+       if (!(np->events & np->irqmask))
+               return IRQ_NONE;
 
-               spin_lock(&np->lock);
-               nv_tx_done(dev);
-               spin_unlock(&np->lock);
+       nv_msi_workaround(np);
 
 #ifdef CONFIG_FORCEDETH_NAPI
-               if (np->events & NVREG_IRQ_RX_ALL) {
-                       spin_lock(&np->lock);
-                       napi_schedule(&np->napi);
+       napi_schedule(&np->napi);
 
-                       /* Disable furthur receive irq's */
-                       np->irqmask &= ~NVREG_IRQ_RX_ALL;
+       /* Disable furthur irq's
+          (msix not enabled with napi) */
+       writel(0, base + NvRegIrqMask);
 
-                       if (np->msi_flags & NV_MSI_X_ENABLED)
-                               writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       spin_unlock(&np->lock);
-               }
 #else
-               if (nv_rx_process(dev, RX_WORK_PER_LOOP)) {
+       do
+       {
+               int work = 0;
+               if ((work = nv_rx_process(dev, RX_WORK_PER_LOOP))) {
                        if (unlikely(nv_alloc_rx(dev))) {
                                spin_lock(&np->lock);
                                if (!np->in_shutdown)
@@ -3459,57 +3494,56 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
                                spin_unlock(&np->lock);
                        }
                }
-#endif
-               if (unlikely(np->events & NVREG_IRQ_LINK)) {
-                       spin_lock(&np->lock);
-                       nv_link_irq(dev);
-                       spin_unlock(&np->lock);
-               }
-               if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
-                       spin_lock(&np->lock);
-                       nv_linkchange(dev);
-                       spin_unlock(&np->lock);
-                       np->link_timeout = jiffies + LINK_TIMEOUT;
-               }
-               if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) {
-                       spin_lock(&np->lock);
-                       /* disable interrupts on the nic */
-                       if (!(np->msi_flags & NV_MSI_X_ENABLED))
-                               writel(0, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       pci_push(base);
 
-                       if (!np->in_shutdown) {
-                               np->nic_poll_irq = np->irqmask;
-                               np->recover_error = 1;
-                               mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
-                       }
-                       spin_unlock(&np->lock);
-                       break;
-               }
-               if (unlikely(i > max_interrupt_work)) {
-                       spin_lock(&np->lock);
-                       /* disable interrupts on the nic */
-                       if (!(np->msi_flags & NV_MSI_X_ENABLED))
-                               writel(0, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       pci_push(base);
+               spin_lock(&np->lock);
+               work += nv_tx_done(dev, TX_WORK_PER_LOOP);
+               spin_unlock(&np->lock);
 
-                       if (!np->in_shutdown) {
-                               np->nic_poll_irq = np->irqmask;
-                               mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
-                       }
-                       spin_unlock(&np->lock);
-                       printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
+               if (!work)
                        break;
-               }
 
+               total_work += work;
+
+               loop_count++;
+       }
+       while (loop_count < max_interrupt_work);
+
+       if (nv_change_interrupt_mode(dev, total_work)) {
+               /* setup new irq mask */
+               writel(np->irqmask, base + NvRegIrqMask);
+       }
+
+       if (unlikely(np->events & NVREG_IRQ_LINK)) {
+               spin_lock(&np->lock);
+               nv_link_irq(dev);
+               spin_unlock(&np->lock);
+       }
+       if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+               spin_lock(&np->lock);
+               nv_linkchange(dev);
+               spin_unlock(&np->lock);
+               np->link_timeout = jiffies + LINK_TIMEOUT;
+       }
+       if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) {
+               spin_lock(&np->lock);
+               /* disable interrupts on the nic */
+               if (!(np->msi_flags & NV_MSI_X_ENABLED))
+                       writel(0, base + NvRegIrqMask);
+               else
+                       writel(np->irqmask, base + NvRegIrqMask);
+               pci_push(base);
+
+               if (!np->in_shutdown) {
+                       np->nic_poll_irq = np->irqmask;
+                       np->recover_error = 1;
+                       mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+               }
+               spin_unlock(&np->lock);
        }
+#endif
        dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
 
-       return IRQ_RETVAL(i);
+       return IRQ_HANDLED;
 }
 
 /**
@@ -3522,44 +3556,38 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
        struct net_device *dev = (struct net_device *) data;
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
-       int i;
+#ifndef CONFIG_FORCEDETH_NAPI
+       int total_work = 0;
+       int loop_count = 0;
+#endif
 
        dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name);
 
-       for (i=0; ; i++) {
-               if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
-                       np->events = readl(base + NvRegIrqStatus);
-                       writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
-               } else {
-                       np->events = readl(base + NvRegMSIXIrqStatus);
-                       writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
-               }
-               dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events);
-               if (!(np->events & np->irqmask))
-                       break;
-
-               nv_msi_workaround(np);
+       if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+               np->events = readl(base + NvRegIrqStatus);
+               writel(np->events, base + NvRegIrqStatus);
+       } else {
+               np->events = readl(base + NvRegMSIXIrqStatus);
+               writel(np->events, base + NvRegMSIXIrqStatus);
+       }
+       dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events);
+       if (!(np->events & np->irqmask))
+               return IRQ_NONE;
 
-               spin_lock(&np->lock);
-               nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
-               spin_unlock(&np->lock);
+       nv_msi_workaround(np);
 
 #ifdef CONFIG_FORCEDETH_NAPI
-               if (np->events & NVREG_IRQ_RX_ALL) {
-                       spin_lock(&np->lock);
-                       napi_schedule(&np->napi);
+       napi_schedule(&np->napi);
 
-                       /* Disable furthur receive irq's */
-                       np->irqmask &= ~NVREG_IRQ_RX_ALL;
+       /* Disable furthur irq's
+          (msix not enabled with napi) */
+       writel(0, base + NvRegIrqMask);
 
-                       if (np->msi_flags & NV_MSI_X_ENABLED)
-                               writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       spin_unlock(&np->lock);
-               }
 #else
-               if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) {
+       do
+       {
+               int work = 0;
+               if ((work = nv_rx_process_optimized(dev, RX_WORK_PER_LOOP))) {
                        if (unlikely(nv_alloc_rx_optimized(dev))) {
                                spin_lock(&np->lock);
                                if (!np->in_shutdown)
@@ -3567,58 +3595,57 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
                                spin_unlock(&np->lock);
                        }
                }
-#endif
-               if (unlikely(np->events & NVREG_IRQ_LINK)) {
-                       spin_lock(&np->lock);
-                       nv_link_irq(dev);
-                       spin_unlock(&np->lock);
-               }
-               if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
-                       spin_lock(&np->lock);
-                       nv_linkchange(dev);
-                       spin_unlock(&np->lock);
-                       np->link_timeout = jiffies + LINK_TIMEOUT;
-               }
-               if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) {
-                       spin_lock(&np->lock);
-                       /* disable interrupts on the nic */
-                       if (!(np->msi_flags & NV_MSI_X_ENABLED))
-                               writel(0, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       pci_push(base);
 
-                       if (!np->in_shutdown) {
-                               np->nic_poll_irq = np->irqmask;
-                               np->recover_error = 1;
-                               mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
-                       }
-                       spin_unlock(&np->lock);
+               spin_lock(&np->lock);
+               work += nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+               spin_unlock(&np->lock);
+
+               if (!work)
                        break;
-               }
 
-               if (unlikely(i > max_interrupt_work)) {
-                       spin_lock(&np->lock);
-                       /* disable interrupts on the nic */
-                       if (!(np->msi_flags & NV_MSI_X_ENABLED))
-                               writel(0, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       pci_push(base);
+               total_work += work;
 
-                       if (!np->in_shutdown) {
-                               np->nic_poll_irq = np->irqmask;
-                               mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
-                       }
-                       spin_unlock(&np->lock);
-                       printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
-                       break;
-               }
+               loop_count++;
+       }
+       while (loop_count < max_interrupt_work);
+
+       if (nv_change_interrupt_mode(dev, total_work)) {
+               /* setup new irq mask */
+               writel(np->irqmask, base + NvRegIrqMask);
+       }
+
+       if (unlikely(np->events & NVREG_IRQ_LINK)) {
+               spin_lock(&np->lock);
+               nv_link_irq(dev);
+               spin_unlock(&np->lock);
+       }
+       if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+               spin_lock(&np->lock);
+               nv_linkchange(dev);
+               spin_unlock(&np->lock);
+               np->link_timeout = jiffies + LINK_TIMEOUT;
+       }
+       if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) {
+               spin_lock(&np->lock);
+               /* disable interrupts on the nic */
+               if (!(np->msi_flags & NV_MSI_X_ENABLED))
+                       writel(0, base + NvRegIrqMask);
+               else
+                       writel(np->irqmask, base + NvRegIrqMask);
+               pci_push(base);
 
+               if (!np->in_shutdown) {
+                       np->nic_poll_irq = np->irqmask;
+                       np->recover_error = 1;
+                       mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+               }
+               spin_unlock(&np->lock);
        }
+
+#endif
        dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name);
 
-       return IRQ_RETVAL(i);
+       return IRQ_HANDLED;
 }
 
 static irqreturn_t nv_nic_irq_tx(int foo, void *data)
@@ -3671,13 +3698,22 @@ static int nv_napi_poll(struct napi_struct *napi, int budget)
        struct net_device *dev = np->dev;
        u8 __iomem *base = get_hwbase(dev);
        unsigned long flags;
-       int pkts, retcode;
+       int retcode;
+       int tx_work, rx_work;
 
        if (!nv_optimized(np)) {
-               pkts = nv_rx_process(dev, budget);
+               spin_lock_irqsave(&np->lock, flags);
+               tx_work = nv_tx_done(dev, np->tx_ring_size);
+               spin_unlock_irqrestore(&np->lock, flags);
+
+               rx_work = nv_rx_process(dev, budget);
                retcode = nv_alloc_rx(dev);
        } else {
-               pkts = nv_rx_process_optimized(dev, budget);
+               spin_lock_irqsave(&np->lock, flags);
+               tx_work = nv_tx_done_optimized(dev, np->tx_ring_size);
+               spin_unlock_irqrestore(&np->lock, flags);
+
+               rx_work = nv_rx_process_optimized(dev, budget);
                retcode = nv_alloc_rx_optimized(dev);
        }
 
@@ -3688,21 +3724,39 @@ static int nv_napi_poll(struct napi_struct *napi, int budget)
                spin_unlock_irqrestore(&np->lock, flags);
        }
 
-       if (pkts < budget) {
-               /* re-enable receive interrupts */
-               spin_lock_irqsave(&np->lock, flags);
+       nv_change_interrupt_mode(dev, tx_work + rx_work);
 
+       if (unlikely(np->events & NVREG_IRQ_LINK)) {
+               spin_lock_irqsave(&np->lock, flags);
+               nv_link_irq(dev);
+               spin_unlock_irqrestore(&np->lock, flags);
+       }
+       if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+               spin_lock_irqsave(&np->lock, flags);
+               nv_linkchange(dev);
+               spin_unlock_irqrestore(&np->lock, flags);
+               np->link_timeout = jiffies + LINK_TIMEOUT;
+       }
+       if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) {
+               spin_lock_irqsave(&np->lock, flags);
+               if (!np->in_shutdown) {
+                       np->nic_poll_irq = np->irqmask;
+                       np->recover_error = 1;
+                       mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+               }
+               spin_unlock_irqrestore(&np->lock, flags);
                __napi_complete(napi);
+               return rx_work;
+       }
 
-               np->irqmask |= NVREG_IRQ_RX_ALL;
-               if (np->msi_flags & NV_MSI_X_ENABLED)
-                       writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
-               else
-                       writel(np->irqmask, base + NvRegIrqMask);
+       if (rx_work < budget) {
+               /* re-enable interrupts
+                  (msix not enabled in napi) */
+               __napi_complete(napi);
 
-               spin_unlock_irqrestore(&np->lock, flags);
+               writel(np->irqmask, base + NvRegIrqMask);
        }
-       return pkts;
+       return rx_work;
 }
 #endif
 
@@ -5615,19 +5669,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX;
        }
 
-       np->msi_flags = 0;
-       if ((id->driver_data & DEV_HAS_MSI) && msi) {
-               np->msi_flags |= NV_MSI_CAPABLE;
-       }
-       if ((id->driver_data & DEV_HAS_MSI_X) && msix) {
-               /* msix has had reported issues when modifying irqmask
-                  as in the case of napi, therefore, disable for now
-               */
-#ifndef CONFIG_FORCEDETH_NAPI
-               np->msi_flags |= NV_MSI_X_CAPABLE;
-#endif
-       }
-
        np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG;
        if ((id->driver_data & DEV_HAS_PAUSEFRAME_TX_V1) ||
            (id->driver_data & DEV_HAS_PAUSEFRAME_TX_V2) ||
@@ -5772,14 +5813,35 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        } else {
                np->tx_flags = NV_TX2_VALID;
        }
-       if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT) {
-               np->irqmask = NVREG_IRQMASK_THROUGHPUT;
-               if (np->msi_flags & NV_MSI_X_CAPABLE) /* set number of vectors */
-                       np->msi_flags |= 0x0003;
-       } else {
+
+       np->msi_flags = 0;
+       if ((id->driver_data & DEV_HAS_MSI) && msi) {
+               np->msi_flags |= NV_MSI_CAPABLE;
+       }
+       if ((id->driver_data & DEV_HAS_MSI_X) && msix) {
+               /* msix has had reported issues when modifying irqmask
+                  as in the case of napi, therefore, disable for now
+               */
+#ifndef CONFIG_FORCEDETH_NAPI
+               np->msi_flags |= NV_MSI_X_CAPABLE;
+#endif
+       }
+
+       if (optimization_mode == NV_OPTIMIZATION_MODE_CPU) {
                np->irqmask = NVREG_IRQMASK_CPU;
                if (np->msi_flags & NV_MSI_X_CAPABLE) /* set number of vectors */
                        np->msi_flags |= 0x0001;
+       } else if (optimization_mode == NV_OPTIMIZATION_MODE_DYNAMIC &&
+                  !(id->driver_data & DEV_NEED_TIMERIRQ)) {
+               /* start off in throughput mode */
+               np->irqmask = NVREG_IRQMASK_THROUGHPUT;
+               /* remove support for msix mode */
+               np->msi_flags &= ~NV_MSI_X_CAPABLE;
+       } else {
+               optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT;
+               np->irqmask = NVREG_IRQMASK_THROUGHPUT;
+               if (np->msi_flags & NV_MSI_X_CAPABLE) /* set number of vectors */
+                       np->msi_flags |= 0x0003;
        }
 
        if (id->driver_data & DEV_NEED_TIMERIRQ)
@@ -6136,19 +6198,19 @@ static struct pci_device_id pci_tbl[] = {
        },
        {       /* MCP04 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT,
        },
        {       /* MCP04 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT,
        },
        {       /* MCP51 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
        },
        {       /* MCP51 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
        },
        {       /* MCP55 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
@@ -6160,83 +6222,83 @@ static struct pci_device_id pci_tbl[] = {
        },
        {       /* MCP61 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP61 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP61 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP61 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP65 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP65 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP65 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP65 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP67 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP67 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP67 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP67 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP73 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP73 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP73 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP73 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP77 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP77 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP77 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP77 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP79 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36),
@@ -6244,15 +6306,15 @@ static struct pci_device_id pci_tbl[] = {
        },
        {       /* MCP79 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP79 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP79 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {0,},
 };
@@ -6280,7 +6342,7 @@ static void __exit exit_nic(void)
 module_param(max_interrupt_work, int, 0);
 MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt");
 module_param(optimization_mode, int, 0);
-MODULE_PARM_DESC(optimization_mode, "In throughput mode (0), every tx & rx packet will generate an interrupt. In CPU mode (1), interrupts are controlled by a timer.");
+MODULE_PARM_DESC(optimization_mode, "In throughput mode (0), every tx & rx packet will generate an interrupt. In CPU mode (1), interrupts are controlled by a timer. In dynamic mode (2), the mode toggles between throughput and CPU mode based on network load.");
 module_param(poll_interval, int, 0);
 MODULE_PARM_DESC(poll_interval, "Interval determines how frequent timer interrupt is generated by [(time_in_micro_secs * 100) / (2^10)]. Min is 0 and Max is 65535.");
 module_param(msi, int, 0);