X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fforcedeth.c;h=d04214e4e5814ad9fd0007d323f93ebf64cd807f;hb=c01003c20563d1e75ec9828d21743919d2b43977;hp=75906ade76f5fc050c57a4f11fc72e5c809dc06d;hpb=aaa37d2d099f97ced415546e285ac901e47a2437;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 75906ad..d04214e 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -111,6 +111,7 @@ * 0.57: 14 May 2006: Mac address set in probe/remove and order corrections. * 0.58: 30 Oct 2006: Added support for sideband management unit. * 0.59: 30 Oct 2006: Added support for recoverable error. + * 0.60: 20 Jan 2007: Code optimizations for rings, rx & tx data paths, and stats. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -127,7 +128,7 @@ #else #define DRIVERNAPI #endif -#define FORCEDETH_VERSION "0.59" +#define FORCEDETH_VERSION "0.60" #define DRV_NAME "forcedeth" #include @@ -173,9 +174,10 @@ #define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */ #define DEV_HAS_POWER_CNTRL 0x0100 /* device supports power savings */ #define DEV_HAS_PAUSEFRAME_TX 0x0200 /* device supports tx pause frames */ -#define DEV_HAS_STATISTICS 0x0400 /* device supports hw statistics */ -#define DEV_HAS_TEST_EXTENDED 0x0800 /* device supports extended diagnostic test */ -#define DEV_HAS_MGMT_UNIT 0x1000 /* device supports management unit */ +#define DEV_HAS_STATISTICS_V1 0x0400 /* device supports hw statistics version 1 */ +#define DEV_HAS_STATISTICS_V2 0x0800 /* device supports hw statistics version 2 */ +#define DEV_HAS_TEST_EXTENDED 0x1000 /* device supports extended diagnostic test */ +#define DEV_HAS_MGMT_UNIT 0x2000 /* device supports management unit */ enum { NvRegIrqStatus = 0x000, @@ -210,7 +212,7 @@ enum { * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms */ NvRegPollingInterval = 0x00c, -#define NVREG_POLL_DEFAULT_THROUGHPUT 970 +#define NVREG_POLL_DEFAULT_THROUGHPUT 970 /* backup tx cleanup if loop max reached */ #define NVREG_POLL_DEFAULT_CPU 13 NvRegMSIMap0 = 0x020, NvRegMSIMap1 = 0x024, @@ -487,7 +489,8 @@ union ring_type { /* Miscelaneous hardware related defines: */ #define NV_PCI_REGSZ_VER1 0x270 -#define NV_PCI_REGSZ_VER2 0x604 +#define NV_PCI_REGSZ_VER2 0x2d4 +#define NV_PCI_REGSZ_VER3 0x604 /* various timeout delays: all in usec */ #define NV_TXRX_RESET_DELAY 4 @@ -605,9 +608,6 @@ static const struct nv_ethtool_str nv_estats_str[] = { { "tx_carrier_errors" }, { "tx_excess_deferral" }, { "tx_retry_error" }, - { "tx_deferral" }, - { "tx_packets" }, - { "tx_pause" }, { "rx_frame_error" }, { "rx_extra_byte" }, { "rx_late_collision" }, @@ -620,11 +620,17 @@ static const struct nv_ethtool_str nv_estats_str[] = { { "rx_unicast" }, { "rx_multicast" }, { "rx_broadcast" }, + { "rx_packets" }, + { "rx_errors_total" }, + { "tx_errors_total" }, + + /* version 2 stats */ + { "tx_deferral" }, + { "tx_packets" }, { "rx_bytes" }, + { "tx_pause" }, { "rx_pause" }, - { "rx_drop_frame" }, - { "rx_packets" }, - { "rx_errors_total" } + { "rx_drop_frame" } }; struct nv_ethtool_stats { @@ -637,9 +643,6 @@ struct nv_ethtool_stats { u64 tx_carrier_errors; u64 tx_excess_deferral; u64 tx_retry_error; - u64 tx_deferral; - u64 tx_packets; - u64 tx_pause; u64 rx_frame_error; u64 rx_extra_byte; u64 rx_late_collision; @@ -652,13 +655,22 @@ struct nv_ethtool_stats { u64 rx_unicast; u64 rx_multicast; u64 rx_broadcast; + u64 rx_packets; + u64 rx_errors_total; + u64 tx_errors_total; + + /* version 2 stats */ + u64 tx_deferral; + u64 tx_packets; u64 rx_bytes; + u64 tx_pause; u64 rx_pause; u64 rx_drop_frame; - u64 rx_packets; - u64 rx_errors_total; }; +#define NV_DEV_STATISTICS_V2_COUNT (sizeof(struct nv_ethtool_stats)/sizeof(u64)) +#define NV_DEV_STATISTICS_V1_COUNT (NV_DEV_STATISTICS_V2_COUNT - 6) + /* diagnostics */ #define NV_TEST_COUNT_BASE 3 #define NV_TEST_COUNT_EXTENDED 4 @@ -827,7 +839,7 @@ enum { NV_MSIX_INT_DISABLED, NV_MSIX_INT_ENABLED }; -static int msix = NV_MSIX_INT_ENABLED; +static int msix = NV_MSIX_INT_DISABLED; /* * DMA 64bit @@ -1275,6 +1287,61 @@ static void nv_mac_reset(struct net_device *dev) pci_push(base); } +static void nv_get_hw_stats(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + + np->estats.tx_bytes += readl(base + NvRegTxCnt); + np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt); + np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt); + np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt); + np->estats.tx_late_collision += readl(base + NvRegTxLateCol); + np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow); + np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier); + np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef); + np->estats.tx_retry_error += readl(base + NvRegTxRetryErr); + np->estats.rx_frame_error += readl(base + NvRegRxFrameErr); + np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte); + np->estats.rx_late_collision += readl(base + NvRegRxLateCol); + np->estats.rx_runt += readl(base + NvRegRxRunt); + np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong); + np->estats.rx_over_errors += readl(base + NvRegRxOverflow); + np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr); + np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr); + np->estats.rx_length_error += readl(base + NvRegRxLenErr); + np->estats.rx_unicast += readl(base + NvRegRxUnicast); + np->estats.rx_multicast += readl(base + NvRegRxMulticast); + np->estats.rx_broadcast += readl(base + NvRegRxBroadcast); + np->estats.rx_packets = + np->estats.rx_unicast + + np->estats.rx_multicast + + np->estats.rx_broadcast; + np->estats.rx_errors_total = + np->estats.rx_crc_errors + + np->estats.rx_over_errors + + np->estats.rx_frame_error + + (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) + + np->estats.rx_late_collision + + np->estats.rx_runt + + np->estats.rx_frame_too_long; + np->estats.tx_errors_total = + np->estats.tx_late_collision + + np->estats.tx_fifo_errors + + np->estats.tx_carrier_errors + + np->estats.tx_excess_deferral + + np->estats.tx_retry_error; + + if (np->driver_data & DEV_HAS_STATISTICS_V2) { + np->estats.tx_deferral += readl(base + NvRegTxDef); + np->estats.tx_packets += readl(base + NvRegTxFrame); + np->estats.rx_bytes += readl(base + NvRegRxCnt); + np->estats.tx_pause += readl(base + NvRegTxPause); + np->estats.rx_pause += readl(base + NvRegRxPause); + np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame); + } +} + /* * nv_get_stats: dev->get_stats function * Get latest stats value from the nic. @@ -1285,10 +1352,19 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); - /* It seems that the nic always generates interrupts and doesn't - * accumulate errors internally. Thus the current values in np->stats - * are already up to date. - */ + /* If the nic supports hw counters then retrieve latest values */ + if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2)) { + nv_get_hw_stats(dev); + + /* copy to net_device stats */ + np->stats.tx_bytes = np->estats.tx_bytes; + np->stats.tx_fifo_errors = np->estats.tx_fifo_errors; + np->stats.tx_carrier_errors = np->estats.tx_carrier_errors; + np->stats.rx_crc_errors = np->estats.rx_crc_errors; + np->stats.rx_over_errors = np->estats.rx_over_errors; + np->stats.rx_errors = np->estats.rx_errors_total; + np->stats.tx_errors = np->estats.tx_errors_total; + } return &np->stats; } @@ -1317,9 +1393,9 @@ static int nv_alloc_rx(struct net_device *dev) np->put_rx.orig->buf = cpu_to_le32(np->put_rx_ctx->dma); wmb(); np->put_rx.orig->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL); - if (np->put_rx.orig++ == np->last_rx.orig) + if (unlikely(np->put_rx.orig++ == np->last_rx.orig)) np->put_rx.orig = np->first_rx.orig; - if (np->put_rx_ctx++ == np->last_rx_ctx) + if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx)) np->put_rx_ctx = np->first_rx_ctx; } else { return 1; @@ -1349,9 +1425,9 @@ static int nv_alloc_rx_optimized(struct net_device *dev) np->put_rx.ex->buflow = cpu_to_le64(np->put_rx_ctx->dma) & 0x0FFFFFFFF; wmb(); np->put_rx.ex->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL); - if (np->put_rx.ex++ == np->last_rx.ex) + if (unlikely(np->put_rx.ex++ == np->last_rx.ex)) np->put_rx.ex = np->first_rx.ex; - if (np->put_rx_ctx++ == np->last_rx_ctx) + if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx)) np->put_rx_ctx = np->first_rx_ctx; } else { return 1; @@ -1563,7 +1639,6 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 size = skb->len-skb->data_len; u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); u32 empty_slots; - u32 tx_flags_vlan = 0; struct ring_desc* put_tx; struct ring_desc* start_tx; struct ring_desc* prev_tx; @@ -1576,7 +1651,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) } empty_slots = nv_get_empty_tx_slots(np); - if (empty_slots <= entries) { + if (unlikely(empty_slots <= entries)) { spin_lock_irq(&np->lock); netif_stop_queue(dev); np->tx_stop = 1; @@ -1596,12 +1671,13 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) np->put_tx_ctx->dma_len = bcnt; put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma); put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); + tx_flags = np->tx_flags; offset += bcnt; size -= bcnt; - if (put_tx++ == np->last_tx.orig) + if (unlikely(put_tx++ == np->last_tx.orig)) put_tx = np->first_tx.orig; - if (np->put_tx_ctx++ == np->last_tx_ctx) + if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) np->put_tx_ctx = np->first_tx_ctx; } while (size); @@ -1618,14 +1694,14 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, PCI_DMA_TODEVICE); np->put_tx_ctx->dma_len = bcnt; - put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma); put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); + offset += bcnt; size -= bcnt; - if (put_tx++ == np->last_tx.orig) + if (unlikely(put_tx++ == np->last_tx.orig)) put_tx = np->first_tx.orig; - if (np->put_tx_ctx++ == np->last_tx_ctx) + if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) np->put_tx_ctx = np->first_tx_ctx; } while (size); } @@ -1642,11 +1718,6 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ? NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0; - /* vlan tag */ - if (np->vlangrp && vlan_tx_tag_present(skb)) { - tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb); - } - spin_lock_irq(&np->lock); /* set tx flags */ @@ -1669,7 +1740,6 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); - pci_push(get_hwbase(dev)); return NETDEV_TX_OK; } @@ -1677,7 +1747,7 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u32 tx_flags = 0; - u32 tx_flags_extra = NV_TX2_LASTPACKET; + u32 tx_flags_extra; unsigned int fragments = skb_shinfo(skb)->nr_frags; unsigned int i; u32 offset = 0; @@ -1685,7 +1755,6 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) u32 size = skb->len-skb->data_len; u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); u32 empty_slots; - u32 tx_flags_vlan = 0; struct ring_desc_ex* put_tx; struct ring_desc_ex* start_tx; struct ring_desc_ex* prev_tx; @@ -1698,7 +1767,7 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) } empty_slots = nv_get_empty_tx_slots(np); - if (empty_slots <= entries) { + if (unlikely(empty_slots <= entries)) { spin_lock_irq(&np->lock); netif_stop_queue(dev); np->tx_stop = 1; @@ -1719,12 +1788,13 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32; put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF; put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); - tx_flags = np->tx_flags; + + tx_flags = NV_TX2_VALID; offset += bcnt; size -= bcnt; - if (put_tx++ == np->last_tx.ex) + if (unlikely(put_tx++ == np->last_tx.ex)) put_tx = np->first_tx.ex; - if (np->put_tx_ctx++ == np->last_tx_ctx) + if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) np->put_tx_ctx = np->first_tx_ctx; } while (size); @@ -1741,21 +1811,21 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, PCI_DMA_TODEVICE); np->put_tx_ctx->dma_len = bcnt; - put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32; put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF; put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); + offset += bcnt; size -= bcnt; - if (put_tx++ == np->last_tx.ex) + if (unlikely(put_tx++ == np->last_tx.ex)) put_tx = np->first_tx.ex; - if (np->put_tx_ctx++ == np->last_tx_ctx) + if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) np->put_tx_ctx = np->first_tx_ctx; } while (size); } /* set last fragment flag */ - prev_tx->flaglen |= cpu_to_le32(tx_flags_extra); + prev_tx->flaglen |= cpu_to_le32(NV_TX2_LASTPACKET); /* save skb in this slot's context area */ prev_tx_ctx->skb = skb; @@ -1767,14 +1837,18 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0; /* vlan tag */ - if (np->vlangrp && vlan_tx_tag_present(skb)) { - tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb); + if (likely(!np->vlangrp)) { + start_tx->txvlan = 0; + } else { + if (vlan_tx_tag_present(skb)) + start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb)); + else + start_tx->txvlan = 0; } spin_lock_irq(&np->lock); /* set tx flags */ - start_tx->txvlan = cpu_to_le32(tx_flags_vlan); start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); np->put_tx.ex = put_tx; @@ -1794,7 +1868,6 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); - pci_push(get_hwbase(dev)); return NETDEV_TX_OK; } @@ -1807,21 +1880,22 @@ static void nv_tx_done(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u32 flags; - struct sk_buff *skb; 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); + while ((np->get_tx.orig != np->put_tx.orig) && + !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID)) { dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n", dev->name, flags); - if (flags & NV_TX_VALID) - break; + + pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma, + np->get_tx_ctx->dma_len, + PCI_DMA_TODEVICE); + np->get_tx_ctx->dma = 0; + if (np->desc_ver == DESC_VER_1) { if (flags & NV_TX_LASTPACKET) { - skb = np->get_tx_ctx->skb; - if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| - NV_TX_UNDERFLOW|NV_TX_ERROR)) { + if (flags & NV_TX_ERROR) { if (flags & NV_TX_UNDERFLOW) np->stats.tx_fifo_errors++; if (flags & NV_TX_CARRIERLOST) @@ -1829,14 +1903,14 @@ static void nv_tx_done(struct net_device *dev) np->stats.tx_errors++; } else { np->stats.tx_packets++; - np->stats.tx_bytes += skb->len; + np->stats.tx_bytes += np->get_tx_ctx->skb->len; } + dev_kfree_skb_any(np->get_tx_ctx->skb); + np->get_tx_ctx->skb = NULL; } } else { if (flags & NV_TX2_LASTPACKET) { - skb = np->get_tx_ctx->skb; - if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| - NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { + if (flags & NV_TX2_ERROR) { if (flags & NV_TX2_UNDERFLOW) np->stats.tx_fifo_errors++; if (flags & NV_TX2_CARRIERLOST) @@ -1844,57 +1918,53 @@ static void nv_tx_done(struct net_device *dev) np->stats.tx_errors++; } else { np->stats.tx_packets++; - np->stats.tx_bytes += skb->len; + np->stats.tx_bytes += np->get_tx_ctx->skb->len; } + dev_kfree_skb_any(np->get_tx_ctx->skb); + np->get_tx_ctx->skb = NULL; } } - nv_release_txskb(dev, np->get_tx_ctx); - if (np->get_tx.orig++ == np->last_tx.orig) + if (unlikely(np->get_tx.orig++ == np->last_tx.orig)) np->get_tx.orig = np->first_tx.orig; - if (np->get_tx_ctx++ == np->last_tx_ctx) + if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx)) np->get_tx_ctx = np->first_tx_ctx; } - if ((np->tx_stop == 1) && (np->get_tx.orig != orig_get_tx)) { + if (unlikely((np->tx_stop == 1) && (np->get_tx.orig != orig_get_tx))) { np->tx_stop = 0; netif_wake_queue(dev); } } -static void nv_tx_done_optimized(struct net_device *dev) +static void nv_tx_done_optimized(struct net_device *dev, int limit) { struct fe_priv *np = netdev_priv(dev); u32 flags; - struct sk_buff *skb; 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); + while ((np->get_tx.ex != np->put_tx.ex) && + !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) && + (limit-- > 0)) { dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n", dev->name, flags); - if (flags & NV_TX_VALID) - break; + + pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma, + np->get_tx_ctx->dma_len, + PCI_DMA_TODEVICE); + np->get_tx_ctx->dma = 0; + if (flags & NV_TX2_LASTPACKET) { - skb = np->get_tx_ctx->skb; - if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| - NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { - if (flags & NV_TX2_UNDERFLOW) - np->stats.tx_fifo_errors++; - if (flags & NV_TX2_CARRIERLOST) - np->stats.tx_carrier_errors++; - np->stats.tx_errors++; - } else { + if (!(flags & NV_TX2_ERROR)) np->stats.tx_packets++; - np->stats.tx_bytes += skb->len; - } + dev_kfree_skb_any(np->get_tx_ctx->skb); + np->get_tx_ctx->skb = NULL; } - nv_release_txskb(dev, np->get_tx_ctx); - if (np->get_tx.ex++ == np->last_tx.ex) + if (unlikely(np->get_tx.ex++ == np->last_tx.ex)) np->get_tx.ex = np->first_tx.ex; - if (np->get_tx_ctx++ == np->last_tx_ctx) + if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx)) np->get_tx_ctx = np->first_tx_ctx; } - if ((np->tx_stop == 1) && (np->get_tx.ex != orig_get_tx)) { + if (unlikely((np->tx_stop == 1) && (np->get_tx.ex != orig_get_tx))) { np->tx_stop = 0; netif_wake_queue(dev); } @@ -1972,7 +2042,7 @@ static void nv_tx_timeout(struct net_device *dev) if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) nv_tx_done(dev); else - nv_tx_done_optimized(dev); + nv_tx_done_optimized(dev, np->tx_ring_size); /* 3) if there are dead entries: clear everything */ if (np->get_tx_ctx != np->put_tx_ctx) { @@ -1980,9 +2050,10 @@ static void nv_tx_timeout(struct net_device *dev) nv_drain_tx(dev); nv_init_tx(dev); setup_hw_rings(dev, NV_SETUP_TX_RING); - netif_wake_queue(dev); } + netif_wake_queue(dev); + /* 4) restart tx engine */ nv_start_tx(dev); spin_unlock_irq(&np->lock); @@ -2045,24 +2116,17 @@ static int nv_rx_process(struct net_device *dev, int limit) { struct fe_priv *np = netdev_priv(dev); u32 flags; - u32 vlanflags = 0; - int count; - - for (count = 0; count < limit; ++count) { - struct sk_buff *skb; - int len; + u32 rx_processed_cnt = 0; + struct sk_buff *skb; + int len; - if (np->get_rx.orig == np->put_rx.orig) - break; /* we scanned the whole ring - do not continue */ - flags = le32_to_cpu(np->get_rx.orig->flaglen); - len = nv_descr_getlength(np->get_rx.orig, np->desc_ver); + while((np->get_rx.orig != np->put_rx.orig) && + !((flags = le32_to_cpu(np->get_rx.orig->flaglen)) & NV_RX_AVAIL) && + (rx_processed_cnt++ < limit)) { dprintk(KERN_DEBUG "%s: nv_rx_process: flags 0x%x.\n", dev->name, flags); - if (flags & NV_RX_AVAIL) - break; /* still owned by hardware, */ - /* * the packet is for us - immediately tear down the pci mapping. * TODO: check if a prefetch of the first cacheline improves @@ -2086,99 +2150,80 @@ static int nv_rx_process(struct net_device *dev, int limit) } /* look at what we actually got: */ if (np->desc_ver == DESC_VER_1) { - if (!(flags & NV_RX_DESCRIPTORVALID)) { - dev_kfree_skb(skb); - goto next_pkt; - } - - if (flags & NV_RX_ERROR) { - if (flags & NV_RX_MISSEDFRAME) { - np->stats.rx_missed_errors++; - np->stats.rx_errors++; - dev_kfree_skb(skb); - goto next_pkt; - } - if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) { - np->stats.rx_errors++; - dev_kfree_skb(skb); - goto next_pkt; - } - if (flags & NV_RX_CRCERR) { - np->stats.rx_crc_errors++; - np->stats.rx_errors++; - dev_kfree_skb(skb); - goto next_pkt; - } - if (flags & NV_RX_OVERFLOW) { - np->stats.rx_over_errors++; - np->stats.rx_errors++; - dev_kfree_skb(skb); - goto next_pkt; - } - if (flags & NV_RX_ERROR4) { - len = nv_getlen(dev, skb->data, len); - if (len < 0) { + if (likely(flags & NV_RX_DESCRIPTORVALID)) { + len = flags & LEN_MASK_V1; + if (unlikely(flags & NV_RX_ERROR)) { + if (flags & NV_RX_ERROR4) { + len = nv_getlen(dev, skb->data, len); + if (len < 0) { + np->stats.rx_errors++; + dev_kfree_skb(skb); + goto next_pkt; + } + } + /* framing errors are soft errors */ + else if (flags & NV_RX_FRAMINGERR) { + if (flags & NV_RX_SUBSTRACT1) { + len--; + } + } + /* the rest are hard errors */ + else { + if (flags & NV_RX_MISSEDFRAME) + np->stats.rx_missed_errors++; + if (flags & NV_RX_CRCERR) + np->stats.rx_crc_errors++; + if (flags & NV_RX_OVERFLOW) + np->stats.rx_over_errors++; np->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } } - /* framing errors are soft errors. */ - if (flags & NV_RX_FRAMINGERR) { - if (flags & NV_RX_SUBSTRACT1) { - len--; - } - } - } - } else { - if (!(flags & NV_RX2_DESCRIPTORVALID)) { + } else { dev_kfree_skb(skb); goto next_pkt; } - - if (flags & NV_RX2_ERROR) { - if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) { - np->stats.rx_errors++; - dev_kfree_skb(skb); - goto next_pkt; - } - if (flags & NV_RX2_CRCERR) { - np->stats.rx_crc_errors++; - np->stats.rx_errors++; - dev_kfree_skb(skb); - goto next_pkt; - } - if (flags & NV_RX2_OVERFLOW) { - np->stats.rx_over_errors++; - np->stats.rx_errors++; - dev_kfree_skb(skb); - goto next_pkt; - } - if (flags & NV_RX2_ERROR4) { - len = nv_getlen(dev, skb->data, len); - if (len < 0) { + } else { + if (likely(flags & NV_RX2_DESCRIPTORVALID)) { + len = flags & LEN_MASK_V2; + if (unlikely(flags & NV_RX2_ERROR)) { + if (flags & NV_RX2_ERROR4) { + len = nv_getlen(dev, skb->data, len); + if (len < 0) { + np->stats.rx_errors++; + dev_kfree_skb(skb); + goto next_pkt; + } + } + /* framing errors are soft errors */ + else if (flags & NV_RX2_FRAMINGERR) { + if (flags & NV_RX2_SUBSTRACT1) { + len--; + } + } + /* the rest are hard errors */ + else { + if (flags & NV_RX2_CRCERR) + np->stats.rx_crc_errors++; + if (flags & NV_RX2_OVERFLOW) + np->stats.rx_over_errors++; np->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } } - /* framing errors are soft errors */ - if (flags & NV_RX2_FRAMINGERR) { - if (flags & NV_RX2_SUBSTRACT1) { - len--; - } - } - } - if (np->rx_csum) { - 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); + if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ { skb->ip_summed = CHECKSUM_UNNECESSARY; } else { - dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name); + if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 || + (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } } + } else { + dev_kfree_skb(skb); + goto next_pkt; } } /* got a valid packet - forward it to the network core */ @@ -2187,29 +2232,21 @@ static int nv_rx_process(struct net_device *dev, int limit) dprintk(KERN_DEBUG "%s: nv_rx_process: %d bytes, proto %d accepted.\n", dev->name, len, skb->protocol); #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); + 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); + netif_rx(skb); #endif dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += len; next_pkt: - if (np->get_rx.orig++ == np->last_rx.orig) + if (unlikely(np->get_rx.orig++ == np->last_rx.orig)) np->get_rx.orig = np->first_rx.orig; - if (np->get_rx_ctx++ == np->last_rx_ctx) + if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx)) np->get_rx_ctx = np->first_rx_ctx; } - return count; + return rx_processed_cnt; } static int nv_rx_process_optimized(struct net_device *dev, int limit) @@ -2217,24 +2254,17 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit) struct fe_priv *np = netdev_priv(dev); u32 flags; u32 vlanflags = 0; - int count; - - for (count = 0; count < limit; ++count) { - struct sk_buff *skb; - int len; + u32 rx_processed_cnt = 0; + struct sk_buff *skb; + int len; - if (np->get_rx.ex == np->put_rx.ex) - break; /* we scanned the whole ring - do not continue */ - flags = le32_to_cpu(np->get_rx.ex->flaglen); - len = nv_descr_getlength_ex(np->get_rx.ex, np->desc_ver); - vlanflags = le32_to_cpu(np->get_rx.ex->buflow); + while((np->get_rx.ex != np->put_rx.ex) && + !((flags = le32_to_cpu(np->get_rx.ex->flaglen)) & NV_RX2_AVAIL) && + (rx_processed_cnt++ < limit)) { dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: flags 0x%x.\n", dev->name, flags); - if (flags & NV_RX_AVAIL) - break; /* still owned by hardware, */ - /* * the packet is for us - immediately tear down the pci mapping. * TODO: check if a prefetch of the first cacheline improves @@ -2257,84 +2287,85 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit) dprintk("\n"); } /* look at what we actually got: */ - if (!(flags & NV_RX2_DESCRIPTORVALID)) { - dev_kfree_skb(skb); - goto next_pkt; - } - - if (flags & NV_RX2_ERROR) { - if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) { - np->stats.rx_errors++; - dev_kfree_skb(skb); - goto next_pkt; - } - if (flags & NV_RX2_CRCERR) { - np->stats.rx_crc_errors++; - np->stats.rx_errors++; - dev_kfree_skb(skb); - goto next_pkt; - } - if (flags & NV_RX2_OVERFLOW) { - np->stats.rx_over_errors++; - np->stats.rx_errors++; - dev_kfree_skb(skb); - goto next_pkt; - } - if (flags & NV_RX2_ERROR4) { - len = nv_getlen(dev, skb->data, len); - if (len < 0) { - np->stats.rx_errors++; + if (likely(flags & NV_RX2_DESCRIPTORVALID)) { + len = flags & LEN_MASK_V2; + if (unlikely(flags & NV_RX2_ERROR)) { + if (flags & NV_RX2_ERROR4) { + len = nv_getlen(dev, skb->data, len); + if (len < 0) { + dev_kfree_skb(skb); + goto next_pkt; + } + } + /* framing errors are soft errors */ + else if (flags & NV_RX2_FRAMINGERR) { + if (flags & NV_RX2_SUBSTRACT1) { + len--; + } + } + /* the rest are hard errors */ + else { dev_kfree_skb(skb); goto next_pkt; } } - /* framing errors are soft errors */ - if (flags & NV_RX2_FRAMINGERR) { - if (flags & NV_RX2_SUBSTRACT1) { - len--; - } - } - } - if (np->rx_csum) { - 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); + + if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ { skb->ip_summed = CHECKSUM_UNNECESSARY; } else { - dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name); + if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 || + (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } } - } - /* got a valid packet - forward it to the network core */ - skb_put(skb, len); - skb->protocol = eth_type_trans(skb, dev); - dprintk(KERN_DEBUG "%s: nv_rx_process: %d bytes, proto %d accepted.\n", - dev->name, len, skb->protocol); + + /* got a valid packet - forward it to the network core */ + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, dev); + prefetch(skb->data); + + dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: %d bytes, proto %d accepted.\n", + dev->name, len, skb->protocol); + + if (likely(!np->vlangrp)) { #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); + 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); + netif_rx(skb); #endif - dev->last_rx = jiffies; - np->stats.rx_packets++; - np->stats.rx_bytes += len; + } else { + vlanflags = le32_to_cpu(np->get_rx.ex->buflow); + if (vlanflags & NV_RX3_VLAN_TAG_PRESENT) { +#ifdef CONFIG_FORCEDETH_NAPI + vlan_hwaccel_receive_skb(skb, np->vlangrp, + vlanflags & NV_RX3_VLAN_TAG_MASK); +#else + vlan_hwaccel_rx(skb, np->vlangrp, + vlanflags & NV_RX3_VLAN_TAG_MASK); +#endif + } else { +#ifdef CONFIG_FORCEDETH_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif + } + } + + dev->last_rx = jiffies; + np->stats.rx_packets++; + np->stats.rx_bytes += len; + } else { + dev_kfree_skb(skb); + } next_pkt: - if (np->get_rx.ex++ == np->last_rx.ex) + if (unlikely(np->get_rx.ex++ == np->last_rx.ex)) np->get_rx.ex = np->first_rx.ex; - if (np->get_rx_ctx++ == np->last_rx_ctx) + if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx)) np->get_rx_ctx = np->first_rx_ctx; } - return count; + return rx_processed_cnt; } static void set_bufsize(struct net_device *dev) @@ -2810,7 +2841,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data) events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); } - pci_push(base); dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; @@ -2819,22 +2849,46 @@ static irqreturn_t nv_nic_irq(int foo, void *data) nv_tx_done(dev); spin_unlock(&np->lock); - if (events & NVREG_IRQ_LINK) { +#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 + if (nv_rx_process(dev, dev->weight)) { + if (unlikely(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 (unlikely(events & NVREG_IRQ_LINK)) { spin_lock(&np->lock); nv_link_irq(dev); spin_unlock(&np->lock); } - if (np->need_linktimer && time_after(jiffies, np->link_timeout)) { + 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 (events & (NVREG_IRQ_TX_ERR)) { + if (unlikely(events & (NVREG_IRQ_TX_ERR))) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); } - if (events & (NVREG_IRQ_UNKNOWN)) { + if (unlikely(events & (NVREG_IRQ_UNKNOWN))) { printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", dev->name, events); } @@ -2855,30 +2909,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) spin_unlock(&np->lock); break; } -#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) { + if (unlikely(i > max_interrupt_work)) { spin_lock(&np->lock); /* disable interrupts on the nic */ if (!(np->msi_flags & NV_MSI_X_ENABLED)) @@ -2902,6 +2933,13 @@ static irqreturn_t nv_nic_irq(int foo, void *data) return IRQ_RETVAL(i); } +#define TX_WORK_PER_LOOP 64 +#define RX_WORK_PER_LOOP 64 +/** + * All _optimized functions are used to help increase performance + * (reduce CPU and increase throughput). They use descripter version 3, + * compiler directives, and reduce memory accesses. + */ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) { struct net_device *dev = (struct net_device *) data; @@ -2920,31 +2958,54 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); } - pci_push(base); dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; spin_lock(&np->lock); - nv_tx_done_optimized(dev); + nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); spin_unlock(&np->lock); - if (events & NVREG_IRQ_LINK) { +#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 + if (nv_rx_process_optimized(dev, dev->weight)) { + if (unlikely(nv_alloc_rx_optimized(dev))) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } + } +#endif + if (unlikely(events & NVREG_IRQ_LINK)) { spin_lock(&np->lock); nv_link_irq(dev); spin_unlock(&np->lock); } - if (np->need_linktimer && time_after(jiffies, np->link_timeout)) { + 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 (events & (NVREG_IRQ_TX_ERR)) { + if (unlikely(events & (NVREG_IRQ_TX_ERR))) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); } - if (events & (NVREG_IRQ_UNKNOWN)) { + if (unlikely(events & (NVREG_IRQ_UNKNOWN))) { printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", dev->name, events); } @@ -2966,30 +3027,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) break; } -#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_optimized(dev, dev->weight); - if (nv_alloc_rx_optimized(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) { + if (unlikely(i > max_interrupt_work)) { spin_lock(&np->lock); /* disable interrupts on the nic */ if (!(np->msi_flags & NV_MSI_X_ENABLED)) @@ -3027,20 +3065,19 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data) for (i=0; ; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL; writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus); - pci_push(base); dprintk(KERN_DEBUG "%s: tx irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; spin_lock_irqsave(&np->lock, flags); - nv_tx_done_optimized(dev); + nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); spin_unlock_irqrestore(&np->lock, flags); - if (events & (NVREG_IRQ_TX_ERR)) { + if (unlikely(events & (NVREG_IRQ_TX_ERR))) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); } - if (i > max_interrupt_work) { + if (unlikely(i > max_interrupt_work)) { spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask); @@ -3068,13 +3105,17 @@ static int nv_napi_poll(struct net_device *dev, int *budget) struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); unsigned long flags; + int retcode; - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { pkts = nv_rx_process(dev, limit); - else + retcode = nv_alloc_rx(dev); + } else { pkts = nv_rx_process_optimized(dev, limit); + retcode = nv_alloc_rx_optimized(dev); + } - if (nv_alloc_rx(dev)) { + if (retcode) { spin_lock_irqsave(&np->lock, flags); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); @@ -3138,20 +3179,20 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) for (i=0; ; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL; writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); - pci_push(base); dprintk(KERN_DEBUG "%s: rx irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; - nv_rx_process_optimized(dev, dev->weight); - if (nv_alloc_rx_optimized(dev)) { - spin_lock_irqsave(&np->lock, flags); - if (!np->in_shutdown) - mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock_irqrestore(&np->lock, flags); + if (nv_rx_process_optimized(dev, dev->weight)) { + if (unlikely(nv_alloc_rx_optimized(dev))) { + spin_lock_irqsave(&np->lock, flags); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock_irqrestore(&np->lock, flags); + } } - if (i > max_interrupt_work) { + if (unlikely(i > max_interrupt_work)) { spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); @@ -3186,11 +3227,15 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data) for (i=0; ; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER; writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus); - pci_push(base); dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; + /* check tx in case we reached max loop limit in tx isr */ + spin_lock_irqsave(&np->lock, flags); + nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); + spin_unlock_irqrestore(&np->lock, flags); + if (events & NVREG_IRQ_LINK) { spin_lock_irqsave(&np->lock, flags); nv_link_irq(dev); @@ -3220,7 +3265,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data) printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", dev->name, events); } - if (i > max_interrupt_work) { + if (unlikely(i > max_interrupt_work)) { spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_OTHER, base + NvRegIrqMask); @@ -3492,7 +3537,10 @@ static void nv_do_nic_poll(unsigned long data) pci_push(base); if (!using_multi_irqs(dev)) { - nv_nic_irq(0, dev); + if (np->desc_ver == DESC_VER_3) + nv_nic_irq_optimized(0, dev); + else + nv_nic_irq(0, dev); if (np->msi_flags & NV_MSI_X_ENABLED) enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); else @@ -3524,47 +3572,8 @@ static void nv_do_stats_poll(unsigned long data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); - u8 __iomem *base = get_hwbase(dev); - np->estats.tx_bytes += readl(base + NvRegTxCnt); - np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt); - np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt); - np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt); - np->estats.tx_late_collision += readl(base + NvRegTxLateCol); - np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow); - np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier); - np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef); - np->estats.tx_retry_error += readl(base + NvRegTxRetryErr); - np->estats.tx_deferral += readl(base + NvRegTxDef); - np->estats.tx_packets += readl(base + NvRegTxFrame); - np->estats.tx_pause += readl(base + NvRegTxPause); - np->estats.rx_frame_error += readl(base + NvRegRxFrameErr); - np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte); - np->estats.rx_late_collision += readl(base + NvRegRxLateCol); - np->estats.rx_runt += readl(base + NvRegRxRunt); - np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong); - np->estats.rx_over_errors += readl(base + NvRegRxOverflow); - np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr); - np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr); - np->estats.rx_length_error += readl(base + NvRegRxLenErr); - np->estats.rx_unicast += readl(base + NvRegRxUnicast); - np->estats.rx_multicast += readl(base + NvRegRxMulticast); - np->estats.rx_broadcast += readl(base + NvRegRxBroadcast); - np->estats.rx_bytes += readl(base + NvRegRxCnt); - np->estats.rx_pause += readl(base + NvRegRxPause); - np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame); - np->estats.rx_packets = - np->estats.rx_unicast + - np->estats.rx_multicast + - np->estats.rx_broadcast; - np->estats.rx_errors_total = - np->estats.rx_crc_errors + - np->estats.rx_over_errors + - np->estats.rx_frame_error + - (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) + - np->estats.rx_late_collision + - np->estats.rx_runt + - np->estats.rx_frame_too_long; + nv_get_hw_stats(dev); if (!np->in_shutdown) mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL); @@ -4183,8 +4192,10 @@ 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); + if (np->driver_data & DEV_HAS_STATISTICS_V1) + return NV_DEV_STATISTICS_V1_COUNT; + else if (np->driver_data & DEV_HAS_STATISTICS_V2) + return NV_DEV_STATISTICS_V2_COUNT; else return 0; } @@ -4771,7 +4782,7 @@ static int nv_open(struct net_device *dev) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); /* start statistics timer */ - if (np->driver_data & DEV_HAS_STATISTICS) + if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2)) mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL); spin_unlock_irq(&np->lock); @@ -4868,7 +4879,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (err < 0) goto out_disable; - if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS)) + if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V2)) + np->register_size = NV_PCI_REGSZ_VER3; + else if (id->driver_data & DEV_HAS_STATISTICS_V1) np->register_size = NV_PCI_REGSZ_VER2; else np->register_size = NV_PCI_REGSZ_VER1; @@ -4932,7 +4945,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; dev->features |= NETIF_F_TSO; - } + } np->vlanctl_bits = 0; if (id->driver_data & DEV_HAS_VLAN) { @@ -5002,7 +5015,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = nv_poll_controller; #endif - dev->weight = 64; + dev->weight = RX_WORK_PER_LOOP; #ifdef CONFIG_FORCEDETH_NAPI dev->poll = nv_napi_poll; #endif @@ -5317,83 +5330,83 @@ static struct pci_device_id pci_tbl[] = { }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, }, { /* 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, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, }, { /* 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, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, }, { /* 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, + .driver_data = DEV_NEED_TIMERIRQ|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, + .driver_data = DEV_NEED_TIMERIRQ|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), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* 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|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* 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|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* 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|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* 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|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* 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_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .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|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* 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_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .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|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* 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_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .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|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* 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_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .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|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* 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|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* 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|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* 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|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* 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|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, {0,}, };