[PATCH] forcdeth: revised NAPI support
[pandora-kernel.git] / drivers / net / forcedeth.c
index 62b38a4..a2aca92 100644 (file)
  *     0.54: 21 Mar 2006: Fix spin locks for multi irqs and cleanup.
  *     0.55: 22 Mar 2006: Add flow control (pause frame).
  *     0.56: 22 Mar 2006: Additional ethtool config and moduleparam support.
+ *     0.57: 14 May 2006: Mac address set in probe/remove and order corrections.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION              "0.56"
+#ifdef CONFIG_FORCEDETH_NAPI
+#define DRIVERNAPI "-NAPI"
+#else
+#define DRIVERNAPI
+#endif
+#define FORCEDETH_VERSION              "0.57"
 #define DRV_NAME                       "forcedeth"
 
 #include <linux/module.h>
@@ -240,10 +246,12 @@ enum {
 #define NVREG_RNDSEED_FORCE2   0x2d00
 #define NVREG_RNDSEED_FORCE3   0x7400
 
-       NvRegUnknownSetupReg1 = 0xA0,
-#define NVREG_UNKSETUP1_VAL    0x16070f
-       NvRegUnknownSetupReg2 = 0xA4,
-#define NVREG_UNKSETUP2_VAL    0x16
+       NvRegTxDeferral = 0xA0,
+#define NVREG_TX_DEFERRAL_DEFAULT      0x15050f
+#define NVREG_TX_DEFERRAL_RGMII_10_100 0x16070f
+#define NVREG_TX_DEFERRAL_RGMII_1000   0x14050f
+       NvRegRxDeferral = 0xA4,
+#define NVREG_RX_DEFERRAL_DEFAULT      0x16
        NvRegMacAddrA = 0xA8,
        NvRegMacAddrB = 0xAC,
        NvRegMulticastAddrA = 0xB0,
@@ -260,7 +268,8 @@ enum {
        NvRegRingSizes = 0x108,
 #define NVREG_RINGSZ_TXSHIFT 0
 #define NVREG_RINGSZ_RXSHIFT 16
-       NvRegUnknownTransmitterReg = 0x10c,
+       NvRegTransmitPoll = 0x10c,
+#define NVREG_TRANSMITPOLL_MAC_ADDR_REV        0x00008000
        NvRegLinkSpeed = 0x110,
 #define NVREG_LINKSPEED_FORCE 0x10000
 #define NVREG_LINKSPEED_10     1000
@@ -269,8 +278,10 @@ enum {
 #define NVREG_LINKSPEED_MASK   (0xFFF)
        NvRegUnknownSetupReg5 = 0x130,
 #define NVREG_UNKSETUP5_BIT31  (1<<31)
-       NvRegUnknownSetupReg3 = 0x13c,
-#define NVREG_UNKSETUP3_VAL1   0x200010
+       NvRegTxWatermark = 0x13c,
+#define NVREG_TX_WM_DESC1_DEFAULT      0x0200010
+#define NVREG_TX_WM_DESC2_3_DEFAULT    0x1e08000
+#define NVREG_TX_WM_DESC2_3_1000       0xfe08000
        NvRegTxRxControl = 0x144,
 #define NVREG_TXRXCTL_KICK     0x0001
 #define NVREG_TXRXCTL_BIT1     0x0002
@@ -377,21 +388,21 @@ enum {
 
 /* Big endian: should work, but is untested */
 struct ring_desc {
-       u32 PacketBuffer;
-       u32 FlagLen;
+       __le32 buf;
+       __le32 flaglen;
 };
 
 struct ring_desc_ex {
-       u32 PacketBufferHigh;
-       u32 PacketBufferLow;
-       u32 TxVlan;
-       u32 FlagLen;
+       __le32 bufhigh;
+       __le32 buflow;
+       __le32 txvlan;
+       __le32 flaglen;
 };
 
-typedef union _ring_type {
+union ring_type {
        struct ring_desc* orig;
        struct ring_desc_ex* ex;
-} ring_type;
+};
 
 #define FLAG_MASK_V1 0xffff0000
 #define FLAG_MASK_V2 0xffffc000
@@ -649,8 +660,8 @@ static const struct nv_ethtool_str nv_etests_str[] = {
 };
 
 struct register_test {
-       u32 reg;
-       u32 mask;
+       __le32 reg;
+       __le32 mask;
 };
 
 static const struct register_test nv_registers_test[] = {
@@ -658,7 +669,7 @@ static const struct register_test nv_registers_test[] = {
        { NvRegMisc1, 0x03c },
        { NvRegOffloadConfig, 0x03ff },
        { NvRegMulticastAddrA, 0xffffffff },
-       { NvRegUnknownSetupReg3, 0x0ff },
+       { NvRegTxWatermark, 0x0ff },
        { NvRegWakeUpFlags, 0x07777 },
        { 0,0 }
 };
@@ -709,7 +720,7 @@ struct fe_priv {
        /* rx specific fields.
         * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
         */
-       ring_type rx_ring;
+       union ring_type rx_ring;
        unsigned int cur_rx, refill_rx;
        struct sk_buff **rx_skbuff;
        dma_addr_t *rx_dma;
@@ -729,7 +740,7 @@ struct fe_priv {
        /*
         * tx specific fields.
         */
-       ring_type tx_ring;
+       union ring_type tx_ring;
        unsigned int next_tx, nic_tx;
        struct sk_buff **tx_skbuff;
        dma_addr_t *tx_dma;
@@ -822,13 +833,13 @@ static inline void pci_push(u8 __iomem *base)
 
 static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
 {
-       return le32_to_cpu(prd->FlagLen)
+       return le32_to_cpu(prd->flaglen)
                & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
 }
 
 static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v)
 {
-       return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2;
+       return le32_to_cpu(prd->flaglen) & LEN_MASK_V2;
 }
 
 static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
@@ -881,7 +892,7 @@ static void free_rings(struct net_device *dev)
        struct fe_priv *np = get_nvpriv(dev);
 
        if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-               if(np->rx_ring.orig)
+               if (np->rx_ring.orig)
                        pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (np->rx_ring_size + np->tx_ring_size),
                                            np->rx_ring.orig, np->ring_addr);
        } else {
@@ -1174,7 +1185,7 @@ static void nv_stop_tx(struct net_device *dev)
                        KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");
 
        udelay(NV_TXSTOP_DELAY2);
-       writel(0, base + NvRegUnknownTransmitterReg);
+       writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
 }
 
 static void nv_txrx_reset(struct net_device *dev)
@@ -1254,14 +1265,14 @@ static int nv_alloc_rx(struct net_device *dev)
                np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data,
                                        skb->end-skb->data, PCI_DMA_FROMDEVICE);
                if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-                       np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
+                       np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]);
                        wmb();
-                       np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+                       np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
                } else {
-                       np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
-                       np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
+                       np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
+                       np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
                        wmb();
-                       np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+                       np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
                }
                dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
                                        dev->name, refill_rx);
@@ -1273,6 +1284,16 @@ static int nv_alloc_rx(struct net_device *dev)
        return 0;
 }
 
+/* If rx bufs are exhausted called after 50ms to attempt to refresh */
+#ifdef CONFIG_FORCEDETH_NAPI
+static void nv_do_rx_refill(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *) data;
+
+       /* Just reschedule NAPI rx processing */
+       netif_rx_schedule(dev);
+}
+#else
 static void nv_do_rx_refill(unsigned long data)
 {
        struct net_device *dev = (struct net_device *) data;
@@ -1301,6 +1322,7 @@ static void nv_do_rx_refill(unsigned long data)
                enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
        }
 }
+#endif
 
 static void nv_init_rx(struct net_device *dev)
 {
@@ -1311,9 +1333,9 @@ static void nv_init_rx(struct net_device *dev)
        np->refill_rx = 0;
        for (i = 0; i < np->rx_ring_size; i++)
                if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-                       np->rx_ring.orig[i].FlagLen = 0;
+                       np->rx_ring.orig[i].flaglen = 0;
                else
-                       np->rx_ring.ex[i].FlagLen = 0;
+                       np->rx_ring.ex[i].flaglen = 0;
 }
 
 static void nv_init_tx(struct net_device *dev)
@@ -1324,9 +1346,9 @@ static void nv_init_tx(struct net_device *dev)
        np->next_tx = np->nic_tx = 0;
        for (i = 0; i < np->tx_ring_size; i++) {
                if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-                       np->tx_ring.orig[i].FlagLen = 0;
+                       np->tx_ring.orig[i].flaglen = 0;
                else
-                       np->tx_ring.ex[i].FlagLen = 0;
+                       np->tx_ring.ex[i].flaglen = 0;
                np->tx_skbuff[i] = NULL;
                np->tx_dma[i] = 0;
        }
@@ -1369,9 +1391,9 @@ static void nv_drain_tx(struct net_device *dev)
 
        for (i = 0; i < np->tx_ring_size; i++) {
                if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-                       np->tx_ring.orig[i].FlagLen = 0;
+                       np->tx_ring.orig[i].flaglen = 0;
                else
-                       np->tx_ring.ex[i].FlagLen = 0;
+                       np->tx_ring.ex[i].flaglen = 0;
                if (nv_release_txskb(dev, i))
                        np->stats.tx_dropped++;
        }
@@ -1383,9 +1405,9 @@ static void nv_drain_rx(struct net_device *dev)
        int i;
        for (i = 0; i < np->rx_ring_size; i++) {
                if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-                       np->rx_ring.orig[i].FlagLen = 0;
+                       np->rx_ring.orig[i].flaglen = 0;
                else
-                       np->rx_ring.ex[i].FlagLen = 0;
+                       np->rx_ring.ex[i].flaglen = 0;
                wmb();
                if (np->rx_skbuff[i]) {
                        pci_unmap_single(np->pci_dev, np->rx_dma[i],
@@ -1446,17 +1468,17 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                np->tx_dma_len[nr] = bcnt;
 
                if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-                       np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
-                       np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+                       np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
+                       np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
                } else {
-                       np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
-                       np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-                       np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+                       np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+                       np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+                       np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
                }
                tx_flags = np->tx_flags;
                offset += bcnt;
                size -= bcnt;
-       } while(size);
+       } while (size);
 
        /* setup the fragments */
        for (i = 0; i < fragments; i++) {
@@ -1473,12 +1495,12 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        np->tx_dma_len[nr] = bcnt;
 
                        if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-                               np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
-                               np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+                               np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
+                               np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
                        } else {
-                               np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
-                               np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-                               np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+                               np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+                               np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+                               np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
                        }
                        offset += bcnt;
                        size -= bcnt;
@@ -1487,16 +1509,16 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* set last fragment flag  */
        if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-               np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+               np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra);
        } else {
-               np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+               np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra);
        }
 
        np->tx_skbuff[nr] = skb;
 
 #ifdef NETIF_F_TSO
-       if (skb_shinfo(skb)->tso_size)
-               tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
+       if (skb_is_gso(skb))
+               tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
        else
 #endif
        tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
@@ -1508,10 +1530,10 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* set tx flags */
        if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-               np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
+               np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
        } else {
-               np->tx_ring.ex[start_nr].TxVlan = cpu_to_le32(tx_flags_vlan);
-               np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
+               np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan);
+               np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
        }
 
        dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
@@ -1543,7 +1565,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
 static void nv_tx_done(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
-       u32 Flags;
+       u32 flags;
        unsigned int i;
        struct sk_buff *skb;
 
@@ -1551,22 +1573,22 @@ static void nv_tx_done(struct net_device *dev)
                i = np->nic_tx % np->tx_ring_size;
 
                if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-                       Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen);
+                       flags = le32_to_cpu(np->tx_ring.orig[i].flaglen);
                else
-                       Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen);
+                       flags = le32_to_cpu(np->tx_ring.ex[i].flaglen);
 
-               dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
-                                       dev->name, np->nic_tx, Flags);
-               if (Flags & NV_TX_VALID)
+               dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n",
+                                       dev->name, np->nic_tx, flags);
+               if (flags & NV_TX_VALID)
                        break;
                if (np->desc_ver == DESC_VER_1) {
-                       if (Flags & NV_TX_LASTPACKET) {
+                       if (flags & NV_TX_LASTPACKET) {
                                skb = np->tx_skbuff[i];
-                               if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
+                               if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
                                             NV_TX_UNDERFLOW|NV_TX_ERROR)) {
-                                       if (Flags & NV_TX_UNDERFLOW)
+                                       if (flags & NV_TX_UNDERFLOW)
                                                np->stats.tx_fifo_errors++;
-                                       if (Flags & NV_TX_CARRIERLOST)
+                                       if (flags & NV_TX_CARRIERLOST)
                                                np->stats.tx_carrier_errors++;
                                        np->stats.tx_errors++;
                                } else {
@@ -1575,13 +1597,13 @@ static void nv_tx_done(struct net_device *dev)
                                }
                        }
                } else {
-                       if (Flags & NV_TX2_LASTPACKET) {
+                       if (flags & NV_TX2_LASTPACKET) {
                                skb = np->tx_skbuff[i];
-                               if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
+                               if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
                                             NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
-                                       if (Flags & NV_TX2_UNDERFLOW)
+                                       if (flags & NV_TX2_UNDERFLOW)
                                                np->stats.tx_fifo_errors++;
-                                       if (Flags & NV_TX2_CARRIERLOST)
+                                       if (flags & NV_TX2_CARRIERLOST)
                                                np->stats.tx_carrier_errors++;
                                        np->stats.tx_errors++;
                                } else {
@@ -1634,29 +1656,29 @@ static void nv_tx_timeout(struct net_device *dev)
                        if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
                                printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
                                       i,
-                                      le32_to_cpu(np->tx_ring.orig[i].PacketBuffer),
-                                      le32_to_cpu(np->tx_ring.orig[i].FlagLen),
-                                      le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer),
-                                      le32_to_cpu(np->tx_ring.orig[i+1].FlagLen),
-                                      le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer),
-                                      le32_to_cpu(np->tx_ring.orig[i+2].FlagLen),
-                                      le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer),
-                                      le32_to_cpu(np->tx_ring.orig[i+3].FlagLen));
+                                      le32_to_cpu(np->tx_ring.orig[i].buf),
+                                      le32_to_cpu(np->tx_ring.orig[i].flaglen),
+                                      le32_to_cpu(np->tx_ring.orig[i+1].buf),
+                                      le32_to_cpu(np->tx_ring.orig[i+1].flaglen),
+                                      le32_to_cpu(np->tx_ring.orig[i+2].buf),
+                                      le32_to_cpu(np->tx_ring.orig[i+2].flaglen),
+                                      le32_to_cpu(np->tx_ring.orig[i+3].buf),
+                                      le32_to_cpu(np->tx_ring.orig[i+3].flaglen));
                        } else {
                                printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
                                       i,
-                                      le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh),
-                                      le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow),
-                                      le32_to_cpu(np->tx_ring.ex[i].FlagLen),
-                                      le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh),
-                                      le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow),
-                                      le32_to_cpu(np->tx_ring.ex[i+1].FlagLen),
-                                      le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh),
-                                      le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow),
-                                      le32_to_cpu(np->tx_ring.ex[i+2].FlagLen),
-                                      le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh),
-                                      le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow),
-                                      le32_to_cpu(np->tx_ring.ex[i+3].FlagLen));
+                                      le32_to_cpu(np->tx_ring.ex[i].bufhigh),
+                                      le32_to_cpu(np->tx_ring.ex[i].buflow),
+                                      le32_to_cpu(np->tx_ring.ex[i].flaglen),
+                                      le32_to_cpu(np->tx_ring.ex[i+1].bufhigh),
+                                      le32_to_cpu(np->tx_ring.ex[i+1].buflow),
+                                      le32_to_cpu(np->tx_ring.ex[i+1].flaglen),
+                                      le32_to_cpu(np->tx_ring.ex[i+2].bufhigh),
+                                      le32_to_cpu(np->tx_ring.ex[i+2].buflow),
+                                      le32_to_cpu(np->tx_ring.ex[i+2].flaglen),
+                                      le32_to_cpu(np->tx_ring.ex[i+3].bufhigh),
+                                      le32_to_cpu(np->tx_ring.ex[i+3].buflow),
+                                      le32_to_cpu(np->tx_ring.ex[i+3].flaglen));
                        }
                }
        }
@@ -1693,7 +1715,7 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
        int protolen;   /* length as stored in the proto field */
 
        /* 1) calculate len according to header */
-       if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) {
+       if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == htons(ETH_P_8021Q)) {
                protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto );
                hdrlen = VLAN_HLEN;
        } else {
@@ -1736,13 +1758,14 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
        }
 }
 
-static void nv_rx_process(struct net_device *dev)
+static int nv_rx_process(struct net_device *dev, int limit)
 {
        struct fe_priv *np = netdev_priv(dev);
-       u32 Flags;
+       u32 flags;
        u32 vlanflags = 0;
+       int count;
 
-       for (;;) {
+       for (count = 0; count < limit; ++count) {
                struct sk_buff *skb;
                int len;
                int i;
@@ -1751,18 +1774,18 @@ static void nv_rx_process(struct net_device *dev)
 
                i = np->cur_rx % np->rx_ring_size;
                if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-                       Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen);
+                       flags = le32_to_cpu(np->rx_ring.orig[i].flaglen);
                        len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
                } else {
-                       Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen);
+                       flags = le32_to_cpu(np->rx_ring.ex[i].flaglen);
                        len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
-                       vlanflags = le32_to_cpu(np->rx_ring.ex[i].PacketBufferLow);
+                       vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow);
                }
 
-               dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n",
-                                       dev->name, np->cur_rx, Flags);
+               dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n",
+                                       dev->name, np->cur_rx, flags);
 
-               if (Flags & NV_RX_AVAIL)
+               if (flags & NV_RX_AVAIL)
                        break;  /* still owned by hardware, */
 
                /*
@@ -1776,7 +1799,7 @@ static void nv_rx_process(struct net_device *dev)
 
                {
                        int j;
-                       dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",Flags);
+                       dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
                        for (j=0; j<64; j++) {
                                if ((j%16) == 0)
                                        dprintk("\n%03x:", j);
@@ -1786,30 +1809,30 @@ static void nv_rx_process(struct net_device *dev)
                }
                /* look at what we actually got: */
                if (np->desc_ver == DESC_VER_1) {
-                       if (!(Flags & NV_RX_DESCRIPTORVALID))
+                       if (!(flags & NV_RX_DESCRIPTORVALID))
                                goto next_pkt;
 
-                       if (Flags & NV_RX_ERROR) {
-                               if (Flags & NV_RX_MISSEDFRAME) {
+                       if (flags & NV_RX_ERROR) {
+                               if (flags & NV_RX_MISSEDFRAME) {
                                        np->stats.rx_missed_errors++;
                                        np->stats.rx_errors++;
                                        goto next_pkt;
                                }
-                               if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
+                               if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
                                        np->stats.rx_errors++;
                                        goto next_pkt;
                                }
-                               if (Flags & NV_RX_CRCERR) {
+                               if (flags & NV_RX_CRCERR) {
                                        np->stats.rx_crc_errors++;
                                        np->stats.rx_errors++;
                                        goto next_pkt;
                                }
-                               if (Flags & NV_RX_OVERFLOW) {
+                               if (flags & NV_RX_OVERFLOW) {
                                        np->stats.rx_over_errors++;
                                        np->stats.rx_errors++;
                                        goto next_pkt;
                                }
-                               if (Flags & NV_RX_ERROR4) {
+                               if (flags & NV_RX_ERROR4) {
                                        len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
                                        if (len < 0) {
                                                np->stats.rx_errors++;
@@ -1817,32 +1840,32 @@ static void nv_rx_process(struct net_device *dev)
                                        }
                                }
                                /* framing errors are soft errors. */
-                               if (Flags & NV_RX_FRAMINGERR) {
-                                       if (Flags & NV_RX_SUBSTRACT1) {
+                               if (flags & NV_RX_FRAMINGERR) {
+                                       if (flags & NV_RX_SUBSTRACT1) {
                                                len--;
                                        }
                                }
                        }
                } else {
-                       if (!(Flags & NV_RX2_DESCRIPTORVALID))
+                       if (!(flags & NV_RX2_DESCRIPTORVALID))
                                goto next_pkt;
 
-                       if (Flags & NV_RX2_ERROR) {
-                               if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
+                       if (flags & NV_RX2_ERROR) {
+                               if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
                                        np->stats.rx_errors++;
                                        goto next_pkt;
                                }
-                               if (Flags & NV_RX2_CRCERR) {
+                               if (flags & NV_RX2_CRCERR) {
                                        np->stats.rx_crc_errors++;
                                        np->stats.rx_errors++;
                                        goto next_pkt;
                                }
-                               if (Flags & NV_RX2_OVERFLOW) {
+                               if (flags & NV_RX2_OVERFLOW) {
                                        np->stats.rx_over_errors++;
                                        np->stats.rx_errors++;
                                        goto next_pkt;
                                }
-                               if (Flags & NV_RX2_ERROR4) {
+                               if (flags & NV_RX2_ERROR4) {
                                        len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
                                        if (len < 0) {
                                                np->stats.rx_errors++;
@@ -1850,17 +1873,17 @@ static void nv_rx_process(struct net_device *dev)
                                        }
                                }
                                /* framing errors are soft errors */
-                               if (Flags & NV_RX2_FRAMINGERR) {
-                                       if (Flags & NV_RX2_SUBSTRACT1) {
+                               if (flags & NV_RX2_FRAMINGERR) {
+                                       if (flags & NV_RX2_SUBSTRACT1) {
                                                len--;
                                        }
                                }
                        }
                        if (np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) {
-                               Flags &= NV_RX2_CHECKSUMMASK;
-                               if (Flags == NV_RX2_CHECKSUMOK1 ||
-                                   Flags == NV_RX2_CHECKSUMOK2 ||
-                                   Flags == NV_RX2_CHECKSUMOK3) {
+                               flags &= NV_RX2_CHECKSUMMASK;
+                               if (flags == NV_RX2_CHECKSUMOK1 ||
+                                   flags == NV_RX2_CHECKSUMOK2 ||
+                                   flags == NV_RX2_CHECKSUMOK3) {
                                        dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
                                        np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
                                } else {
@@ -1876,17 +1899,27 @@ static void nv_rx_process(struct net_device *dev)
                skb->protocol = eth_type_trans(skb, dev);
                dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
                                        dev->name, np->cur_rx, len, skb->protocol);
-               if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) {
-                       vlan_hwaccel_rx(skb, np->vlangrp, vlanflags & NV_RX3_VLAN_TAG_MASK);
-               } else {
+#ifdef CONFIG_FORCEDETH_NAPI
+               if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
+                       vlan_hwaccel_receive_skb(skb, np->vlangrp,
+                                                vlanflags & NV_RX3_VLAN_TAG_MASK);
+               else
+                       netif_receive_skb(skb);
+#else
+               if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
+                       vlan_hwaccel_rx(skb, np->vlangrp,
+                                       vlanflags & NV_RX3_VLAN_TAG_MASK);
+               else
                        netif_rx(skb);
-               }
+#endif
                dev->last_rx = jiffies;
                np->stats.rx_packets++;
                np->stats.rx_bytes += len;
 next_pkt:
                np->cur_rx++;
        }
+
+       return count;
 }
 
 static void set_bufsize(struct net_device *dev)
@@ -1986,7 +2019,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)
        struct fe_priv *np = netdev_priv(dev);
        struct sockaddr *macaddr = (struct sockaddr*)addr;
 
-       if(!is_valid_ether_addr(macaddr->sa_data))
+       if (!is_valid_ether_addr(macaddr->sa_data))
                return -EADDRNOTAVAIL;
 
        /* synchronized against open : rtnl_lock() held by caller */
@@ -2076,7 +2109,7 @@ static void nv_set_multicast(struct net_device *dev)
        spin_unlock_irq(&np->lock);
 }
 
-void nv_update_pause(struct net_device *dev, u32 pause_flags)
+static void nv_update_pause(struct net_device *dev, u32 pause_flags)
 {
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
@@ -2127,7 +2160,7 @@ static int nv_update_linkspeed(struct net_device *dev)
        int newdup = np->duplex;
        int mii_status;
        int retval = 0;
-       u32 control_1000, status_1000, phyreg, pause_flags;
+       u32 control_1000, status_1000, phyreg, pause_flags, txreg;
 
        /* BMSR_LSTATUS is latched, read it twice:
         * we want the current value.
@@ -2245,6 +2278,26 @@ set_speed:
                phyreg |= PHY_1000;
        writel(phyreg, base + NvRegPhyInterface);
 
+       if (phyreg & PHY_RGMII) {
+               if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_1000)
+                       txreg = NVREG_TX_DEFERRAL_RGMII_1000;
+               else
+                       txreg = NVREG_TX_DEFERRAL_RGMII_10_100;
+       } else {
+               txreg = NVREG_TX_DEFERRAL_DEFAULT;
+       }
+       writel(txreg, base + NvRegTxDeferral);
+
+       if (np->desc_ver == DESC_VER_1) {
+               txreg = NVREG_TX_WM_DESC1_DEFAULT;
+       } else {
+               if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_1000)
+                       txreg = NVREG_TX_WM_DESC2_3_1000;
+               else
+                       txreg = NVREG_TX_WM_DESC2_3_DEFAULT;
+       }
+       writel(txreg, base + NvRegTxWatermark);
+
        writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD),
                base + NvRegMisc1);
        pci_push(base);
@@ -2259,20 +2312,20 @@ set_speed:
                        lpa_pause = lpa & (LPA_PAUSE_CAP| LPA_PAUSE_ASYM);
 
                        switch (adv_pause) {
-                       case (ADVERTISE_PAUSE_CAP):
+                       case ADVERTISE_PAUSE_CAP:
                                if (lpa_pause & LPA_PAUSE_CAP) {
                                        pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
                                        if (np->pause_flags & NV_PAUSEFRAME_TX_REQ)
                                                pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
                                }
                                break;
-                       case (ADVERTISE_PAUSE_ASYM):
+                       case ADVERTISE_PAUSE_ASYM:
                                if (lpa_pause == (LPA_PAUSE_CAP| LPA_PAUSE_ASYM))
                                {
                                        pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
                                }
                                break;
-                       case (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM):
+                       case ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM:
                                if (lpa_pause & LPA_PAUSE_CAP)
                                {
                                        pause_flags |=  NV_PAUSEFRAME_RX_ENABLE;
@@ -2352,14 +2405,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
                nv_tx_done(dev);
                spin_unlock(&np->lock);
 
-               nv_rx_process(dev);
-               if (nv_alloc_rx(dev)) {
-                       spin_lock(&np->lock);
-                       if (!np->in_shutdown)
-                               mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
-                       spin_unlock(&np->lock);
-               }
-
                if (events & NVREG_IRQ_LINK) {
                        spin_lock(&np->lock);
                        nv_link_irq(dev);
@@ -2379,6 +2424,29 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
                        printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
                                                dev->name, events);
                }
+#ifdef CONFIG_FORCEDETH_NAPI
+               if (events & NVREG_IRQ_RX_ALL) {
+                       netif_rx_schedule(dev);
+
+                       /* Disable furthur receive irq's */
+                       spin_lock(&np->lock);
+                       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);
+                       spin_unlock(&np->lock);
+               }
+#else
+               nv_rx_process(dev, dev->weight);
+               if (nv_alloc_rx(dev)) {
+                       spin_lock(&np->lock);
+                       if (!np->in_shutdown)
+                               mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+                       spin_unlock(&np->lock);
+               }
+#endif
                if (i > max_interrupt_work) {
                        spin_lock(&np->lock);
                        /* disable interrupts on the nic */
@@ -2450,6 +2518,63 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs)
        return IRQ_RETVAL(i);
 }
 
+#ifdef CONFIG_FORCEDETH_NAPI
+static int nv_napi_poll(struct net_device *dev, int *budget)
+{
+       int pkts, limit = min(*budget, dev->quota);
+       struct fe_priv *np = netdev_priv(dev);
+       u8 __iomem *base = get_hwbase(dev);
+
+       pkts = nv_rx_process(dev, limit);
+
+       if (nv_alloc_rx(dev)) {
+               spin_lock_irq(&np->lock);
+               if (!np->in_shutdown)
+                       mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+               spin_unlock_irq(&np->lock);
+       }
+
+       if (pkts < limit) {
+               /* all done, no more packets present */
+               netif_rx_complete(dev);
+
+               /* re-enable receive interrupts */
+               spin_lock_irq(&np->lock);
+               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);
+               spin_unlock_irq(&np->lock);
+               return 0;
+       } else {
+               /* used up our quantum, so reschedule */
+               dev->quota -= pkts;
+               *budget -= pkts;
+               return 1;
+       }
+}
+#endif
+
+#ifdef CONFIG_FORCEDETH_NAPI
+static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
+{
+       struct net_device *dev = (struct net_device *) data;
+       u8 __iomem *base = get_hwbase(dev);
+       u32 events;
+
+       events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
+       writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
+
+       if (events) {
+               netif_rx_schedule(dev);
+               /* disable receive interrupts on the nic */
+               writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+               pci_push(base);
+       }
+       return IRQ_HANDLED;
+}
+#else
 static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
 {
        struct net_device *dev = (struct net_device *) data;
@@ -2468,7 +2593,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
                if (!(events & np->irqmask))
                        break;
 
-               nv_rx_process(dev);
+               nv_rx_process(dev, dev->weight);
                if (nv_alloc_rx(dev)) {
                        spin_lock_irq(&np->lock);
                        if (!np->in_shutdown)
@@ -2490,12 +2615,12 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
                        spin_unlock_irq(&np->lock);
                        break;
                }
-
        }
        dprintk(KERN_DEBUG "%s: nv_nic_irq_rx completed\n", dev->name);
 
        return IRQ_RETVAL(i);
 }
+#endif
 
 static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
 {
@@ -2622,21 +2747,21 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                        np->msi_flags |= NV_MSI_X_ENABLED;
                        if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT && !intr_test) {
                                /* Request irq for rx handling */
-                               if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, &nv_nic_irq_rx, SA_SHIRQ, dev->name, dev) != 0) {
+                               if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, &nv_nic_irq_rx, IRQF_SHARED, dev->name, dev) != 0) {
                                        printk(KERN_INFO "forcedeth: request_irq failed for rx %d\n", ret);
                                        pci_disable_msix(np->pci_dev);
                                        np->msi_flags &= ~NV_MSI_X_ENABLED;
                                        goto out_err;
                                }
                                /* Request irq for tx handling */
-                               if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, &nv_nic_irq_tx, SA_SHIRQ, dev->name, dev) != 0) {
+                               if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, &nv_nic_irq_tx, IRQF_SHARED, dev->name, dev) != 0) {
                                        printk(KERN_INFO "forcedeth: request_irq failed for tx %d\n", ret);
                                        pci_disable_msix(np->pci_dev);
                                        np->msi_flags &= ~NV_MSI_X_ENABLED;
                                        goto out_free_rx;
                                }
                                /* Request irq for link and timer handling */
-                               if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, &nv_nic_irq_other, SA_SHIRQ, dev->name, dev) != 0) {
+                               if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, &nv_nic_irq_other, IRQF_SHARED, dev->name, dev) != 0) {
                                        printk(KERN_INFO "forcedeth: request_irq failed for link %d\n", ret);
                                        pci_disable_msix(np->pci_dev);
                                        np->msi_flags &= ~NV_MSI_X_ENABLED;
@@ -2651,9 +2776,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                        } else {
                                /* Request irq for all interrupts */
                                if ((!intr_test &&
-                                    request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) ||
+                                    request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
                                    (intr_test &&
-                                    request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq_test, SA_SHIRQ, dev->name, dev) != 0)) {
+                                    request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
                                        printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
                                        pci_disable_msix(np->pci_dev);
                                        np->msi_flags &= ~NV_MSI_X_ENABLED;
@@ -2669,8 +2794,8 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
        if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
                if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
                        np->msi_flags |= NV_MSI_ENABLED;
-                       if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) ||
-                           (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, SA_SHIRQ, dev->name, dev) != 0)) {
+                       if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
+                           (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
                                printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
                                pci_disable_msi(np->pci_dev);
                                np->msi_flags &= ~NV_MSI_ENABLED;
@@ -2685,8 +2810,8 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                }
        }
        if (ret != 0) {
-               if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) ||
-                   (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, SA_SHIRQ, dev->name, dev) != 0))
+               if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
+                   (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0))
                        goto out_err;
 
        }
@@ -2735,21 +2860,21 @@ static void nv_do_nic_poll(unsigned long data)
 
        if (!using_multi_irqs(dev)) {
                if (np->msi_flags & NV_MSI_X_ENABLED)
-                       disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+                       disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
                else
-                       disable_irq(dev->irq);
+                       disable_irq_lockdep(dev->irq);
                mask = np->irqmask;
        } else {
                if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
-                       disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
+                       disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
                        mask |= NVREG_IRQ_RX_ALL;
                }
                if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) {
-                       disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
+                       disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
                        mask |= NVREG_IRQ_TX_ALL;
                }
                if (np->nic_poll_irq & NVREG_IRQ_OTHER) {
-                       disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
+                       disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
                        mask |= NVREG_IRQ_OTHER;
                }
        }
@@ -2761,23 +2886,23 @@ static void nv_do_nic_poll(unsigned long data)
        pci_push(base);
 
        if (!using_multi_irqs(dev)) {
-               nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL);
+               nv_nic_irq(0, dev, NULL);
                if (np->msi_flags & NV_MSI_X_ENABLED)
-                       enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+                       enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
                else
-                       enable_irq(dev->irq);
+                       enable_irq_lockdep(dev->irq);
        } else {
                if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
-                       nv_nic_irq_rx((int) 0, (void *) data, (struct pt_regs *) NULL);
-                       enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
+                       nv_nic_irq_rx(0, dev, NULL);
+                       enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
                }
                if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) {
-                       nv_nic_irq_tx((int) 0, (void *) data, (struct pt_regs *) NULL);
-                       enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
+                       nv_nic_irq_tx(0, dev, NULL);
+                       enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
                }
                if (np->nic_poll_irq & NVREG_IRQ_OTHER) {
-                       nv_nic_irq_other((int) 0, (void *) data, (struct pt_regs *) NULL);
-                       enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
+                       nv_nic_irq_other(0, dev, NULL);
+                       enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
                }
        }
 }
@@ -3221,7 +3346,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
        if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) {
                /* fall back to old rings */
                if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-                       if(rxtx_ring)
+                       if (rxtx_ring)
                                pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (ring->rx_pending + ring->tx_pending),
                                                    rxtx_ring, ring_addr);
                } else {
@@ -3457,7 +3582,7 @@ static int nv_get_stats_count(struct net_device *dev)
        struct fe_priv *np = netdev_priv(dev);
 
        if (np->driver_data & DEV_HAS_STATISTICS)
-               return (sizeof(struct nv_ethtool_stats)/sizeof(u64));
+               return sizeof(struct nv_ethtool_stats)/sizeof(u64);
        else
                return 0;
 }
@@ -3595,7 +3720,7 @@ static int nv_loopback_test(struct net_device *dev)
        struct sk_buff *tx_skb, *rx_skb;
        dma_addr_t test_dma_addr;
        u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
-       u32 Flags;
+       u32 flags;
        int len, i, pkt_len;
        u8 *pkt_data;
        u32 filter_flags = 0;
@@ -3639,12 +3764,12 @@ static int nv_loopback_test(struct net_device *dev)
                                       tx_skb->end-tx_skb->data, PCI_DMA_FROMDEVICE);
 
        if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-               np->tx_ring.orig[0].PacketBuffer = cpu_to_le32(test_dma_addr);
-               np->tx_ring.orig[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
+               np->tx_ring.orig[0].buf = cpu_to_le32(test_dma_addr);
+               np->tx_ring.orig[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
        } else {
-               np->tx_ring.ex[0].PacketBufferHigh = cpu_to_le64(test_dma_addr) >> 32;
-               np->tx_ring.ex[0].PacketBufferLow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF;
-               np->tx_ring.ex[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
+               np->tx_ring.ex[0].bufhigh = cpu_to_le64(test_dma_addr) >> 32;
+               np->tx_ring.ex[0].buflow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF;
+               np->tx_ring.ex[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
        }
        writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
        pci_push(get_hwbase(dev));
@@ -3653,21 +3778,21 @@ static int nv_loopback_test(struct net_device *dev)
 
        /* check for rx of the packet */
        if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-               Flags = le32_to_cpu(np->rx_ring.orig[0].FlagLen);
+               flags = le32_to_cpu(np->rx_ring.orig[0].flaglen);
                len = nv_descr_getlength(&np->rx_ring.orig[0], np->desc_ver);
 
        } else {
-               Flags = le32_to_cpu(np->rx_ring.ex[0].FlagLen);
+               flags = le32_to_cpu(np->rx_ring.ex[0].flaglen);
                len = nv_descr_getlength_ex(&np->rx_ring.ex[0], np->desc_ver);
        }
 
-       if (Flags & NV_RX_AVAIL) {
+       if (flags & NV_RX_AVAIL) {
                ret = 0;
        } else if (np->desc_ver == DESC_VER_1) {
-               if (Flags & NV_RX_ERROR)
+               if (flags & NV_RX_ERROR)
                        ret = 0;
        } else {
-               if (Flags & NV_RX2_ERROR) {
+               if (flags & NV_RX2_ERROR) {
                        ret = 0;
                }
        }
@@ -3729,6 +3854,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
        if (test->flags & ETH_TEST_FL_OFFLINE) {
                if (netif_running(dev)) {
                        netif_stop_queue(dev);
+                       netif_poll_disable(dev);
                        netif_tx_lock_bh(dev);
                        spin_lock_irq(&np->lock);
                        nv_disable_hw_interrupts(dev, np->irqmask);
@@ -3787,6 +3913,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
                        nv_start_rx(dev);
                        nv_start_tx(dev);
                        netif_start_queue(dev);
+                       netif_poll_enable(dev);
                        nv_enable_hw_interrupts(dev, np->irqmask);
                }
        }
@@ -3871,10 +3998,9 @@ static int nv_open(struct net_device *dev)
 
        dprintk(KERN_DEBUG "nv_open: begin\n");
 
-       /* 1) erase previous misconfiguration */
+       /* erase previous misconfiguration */
        if (np->driver_data & DEV_HAS_POWER_CNTRL)
                nv_mac_reset(dev);
-       /* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */
        writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
        writel(0, base + NvRegMulticastAddrB);
        writel(0, base + NvRegMulticastMaskA);
@@ -3889,28 +4015,27 @@ static int nv_open(struct net_device *dev)
        if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE)
                writel(NVREG_TX_PAUSEFRAME_DISABLE,  base + NvRegTxPauseFrame);
 
-       /* 2) initialize descriptor rings */
+       /* initialize descriptor rings */
        set_bufsize(dev);
        oom = nv_init_ring(dev);
 
        writel(0, base + NvRegLinkSpeed);
-       writel(0, base + NvRegUnknownTransmitterReg);
+       writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
        nv_txrx_reset(dev);
        writel(0, base + NvRegUnknownSetupReg6);
 
        np->in_shutdown = 0;
 
-       /* 3) set mac address */
-       nv_copy_mac_to_hw(dev);
-
-       /* 4) give hw rings */
+       /* give hw rings */
        setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
        writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
                base + NvRegRingSizes);
 
-       /* 5) continue setup */
        writel(np->linkspeed, base + NvRegLinkSpeed);
-       writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3);
+       if (np->desc_ver == DESC_VER_1)
+               writel(NVREG_TX_WM_DESC1_DEFAULT, base + NvRegTxWatermark);
+       else
+               writel(NVREG_TX_WM_DESC2_3_DEFAULT, base + NvRegTxWatermark);
        writel(np->txrxctl_bits, base + NvRegTxRxControl);
        writel(np->vlanctl_bits, base + NvRegVlanControl);
        pci_push(base);
@@ -3923,7 +4048,6 @@ static int nv_open(struct net_device *dev)
        writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
        writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
 
-       /* 6) continue setup */
        writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
        writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus);
        writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags);
@@ -3932,8 +4056,8 @@ static int nv_open(struct net_device *dev)
        writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus);
        get_random_bytes(&i, sizeof(i));
        writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed);
-       writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1);
-       writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2);
+       writel(NVREG_TX_DEFERRAL_DEFAULT, base + NvRegTxDeferral);
+       writel(NVREG_RX_DEFERRAL_DEFAULT, base + NvRegRxDeferral);
        if (poll_interval == -1) {
                if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT)
                        writel(NVREG_POLL_DEFAULT_THROUGHPUT, base + NvRegPollingInterval);
@@ -3993,6 +4117,8 @@ static int nv_open(struct net_device *dev)
        nv_start_rx(dev);
        nv_start_tx(dev);
        netif_start_queue(dev);
+       netif_poll_enable(dev);
+
        if (ret) {
                netif_carrier_on(dev);
        } else {
@@ -4022,6 +4148,7 @@ static int nv_close(struct net_device *dev)
        spin_lock_irq(&np->lock);
        np->in_shutdown = 1;
        spin_unlock_irq(&np->lock);
+       netif_poll_disable(dev);
        synchronize_irq(dev->irq);
 
        del_timer_sync(&np->oom_kick);
@@ -4049,12 +4176,6 @@ static int nv_close(struct net_device *dev)
        if (np->wolenabled)
                nv_start_rx(dev);
 
-       /* special op: write back the misordered MAC address - otherwise
-        * the next nv_probe would see a wrong address.
-        */
-       writel(np->orig_mac[0], base + NvRegMacAddrA);
-       writel(np->orig_mac[1], base + NvRegMacAddrB);
-
        /* FIXME: power down nic */
 
        return 0;
@@ -4067,7 +4188,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        unsigned long addr;
        u8 __iomem *base;
        int err, i;
-       u32 powerstate;
+       u32 powerstate, txreg;
 
        dev = alloc_etherdev(sizeof(struct fe_priv));
        err = -ENOMEM;
@@ -4242,6 +4363,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        dev->set_multicast_list = nv_set_multicast;
 #ifdef CONFIG_NET_POLL_CONTROLLER
        dev->poll_controller = nv_poll_controller;
+#endif
+       dev->weight = 64;
+#ifdef CONFIG_FORCEDETH_NAPI
+       dev->poll = nv_napi_poll;
 #endif
        SET_ETHTOOL_OPS(dev, &ops);
        dev->tx_timeout = nv_tx_timeout;
@@ -4254,12 +4379,30 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        np->orig_mac[0] = readl(base + NvRegMacAddrA);
        np->orig_mac[1] = readl(base + NvRegMacAddrB);
 
-       dev->dev_addr[0] = (np->orig_mac[1] >>  8) & 0xff;
-       dev->dev_addr[1] = (np->orig_mac[1] >>  0) & 0xff;
-       dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff;
-       dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
-       dev->dev_addr[4] = (np->orig_mac[0] >>  8) & 0xff;
-       dev->dev_addr[5] = (np->orig_mac[0] >>  0) & 0xff;
+       /* check the workaround bit for correct mac address order */
+       txreg = readl(base + NvRegTransmitPoll);
+       if (txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) {
+               /* mac address is already in correct order */
+               dev->dev_addr[0] = (np->orig_mac[0] >>  0) & 0xff;
+               dev->dev_addr[1] = (np->orig_mac[0] >>  8) & 0xff;
+               dev->dev_addr[2] = (np->orig_mac[0] >> 16) & 0xff;
+               dev->dev_addr[3] = (np->orig_mac[0] >> 24) & 0xff;
+               dev->dev_addr[4] = (np->orig_mac[1] >>  0) & 0xff;
+               dev->dev_addr[5] = (np->orig_mac[1] >>  8) & 0xff;
+       } else {
+               /* need to reverse mac address to correct order */
+               dev->dev_addr[0] = (np->orig_mac[1] >>  8) & 0xff;
+               dev->dev_addr[1] = (np->orig_mac[1] >>  0) & 0xff;
+               dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff;
+               dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
+               dev->dev_addr[4] = (np->orig_mac[0] >>  8) & 0xff;
+               dev->dev_addr[5] = (np->orig_mac[0] >>  0) & 0xff;
+               /* set permanent address to be correct aswell */
+               np->orig_mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
+                       (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
+               np->orig_mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
+               writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
+       }
        memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
        if (!is_valid_ether_addr(dev->perm_addr)) {
@@ -4282,6 +4425,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                        dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
                        dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
 
+       /* set mac address */
+       nv_copy_mac_to_hw(dev);
+
        /* disable WOL */
        writel(0, base + NvRegWakeUpFlags);
        np->wolenabled = 0;
@@ -4394,9 +4540,17 @@ out:
 static void __devexit nv_remove(struct pci_dev *pci_dev)
 {
        struct net_device *dev = pci_get_drvdata(pci_dev);
+       struct fe_priv *np = netdev_priv(dev);
+       u8 __iomem *base = get_hwbase(dev);
 
        unregister_netdev(dev);
 
+       /* special op: write back the misordered MAC address - otherwise
+        * the next nv_probe would see a wrong address.
+        */
+       writel(np->orig_mac[0], base + NvRegMacAddrA);
+       writel(np->orig_mac[1], base + NvRegMacAddrB);
+
        /* free all structures */
        free_rings(dev);
        iounmap(get_hwbase(dev));