* 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.
#else
#define DRIVERNAPI
#endif
-#define FORCEDETH_VERSION "0.59"
+#define FORCEDETH_VERSION "0.60"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
#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,
* 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,
/* 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
#define TX_RING_MIN 64
#define RING_MAX_DESC_VER_1 1024
#define RING_MAX_DESC_VER_2_3 16384
-/*
- * Difference between the get and put pointers for the tx ring.
- * This is used to throttle the amount of data outstanding in the
- * tx ring.
- */
-#define TX_LIMIT_DIFFERENCE 1
/* rx/tx mac addr + type + vlan + align + slack*/
#define NV_RX_HEADERS (64)
{ "tx_carrier_errors" },
{ "tx_excess_deferral" },
{ "tx_retry_error" },
- { "tx_deferral" },
- { "tx_packets" },
- { "tx_pause" },
{ "rx_frame_error" },
{ "rx_extra_byte" },
{ "rx_late_collision" },
{ "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 {
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;
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
union ring_type tx_ring;
u32 tx_flags;
int tx_ring_size;
- int tx_limit_start;
- int tx_limit_stop;
+ int tx_stop;
/* vlan fields */
struct vlan_group *vlangrp;
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.
{
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;
}
static int nv_alloc_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- union ring_type less_rx;
-
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- less_rx.orig = np->get_rx.orig;
- if (less_rx.orig-- == np->first_rx.orig)
- less_rx.orig = np->last_rx.orig;
- } else {
- less_rx.ex = np->get_rx.ex;
- if (less_rx.ex-- == np->first_rx.ex)
- less_rx.ex = np->last_rx.ex;
- }
+ struct ring_desc* less_rx;
- while (1) {
- struct sk_buff *skb;
-
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- if (np->put_rx.orig == less_rx.orig)
- break;
- } else {
- if (np->put_rx.ex == less_rx.ex)
- break;
- }
-
- if (np->put_rx_ctx->skb == NULL) {
-
- skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
- if (!skb)
- return 1;
+ less_rx = np->get_rx.orig;
+ if (less_rx-- == np->first_rx.orig)
+ less_rx = np->last_rx.orig;
+ while (np->put_rx.orig != less_rx) {
+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
+ if (skb) {
skb->dev = dev;
np->put_rx_ctx->skb = skb;
- } else {
- skb = np->put_rx_ctx->skb;
- }
- np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
- skb->end-skb->data, PCI_DMA_FROMDEVICE);
- np->put_rx_ctx->dma_len = skb->end-skb->data;
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
+ skb->end-skb->data, PCI_DMA_FROMDEVICE);
+ np->put_rx_ctx->dma_len = skb->end-skb->data;
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 (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
+ np->put_rx_ctx = np->first_rx_ctx;
} else {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int nv_alloc_rx_optimized(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ struct ring_desc_ex* less_rx;
+
+ less_rx = np->get_rx.ex;
+ if (less_rx-- == np->first_rx.ex)
+ less_rx = np->last_rx.ex;
+
+ while (np->put_rx.ex != less_rx) {
+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
+ if (skb) {
+ skb->dev = dev;
+ np->put_rx_ctx->skb = skb;
+ np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
+ skb->end-skb->data, PCI_DMA_FROMDEVICE);
+ np->put_rx_ctx->dma_len = skb->end-skb->data;
np->put_rx.ex->bufhigh = cpu_to_le64(np->put_rx_ctx->dma) >> 32;
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 (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
+ np->put_rx_ctx = np->first_rx_ctx;
+ } else {
+ return 1;
}
- if (np->put_rx_ctx++ == np->last_rx_ctx)
- np->put_rx_ctx = np->first_rx_ctx;
}
return 0;
}
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
+ int retcode;
if (!using_multi_irqs(dev)) {
if (np->msi_flags & NV_MSI_X_ENABLED)
} else {
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
}
- if (nv_alloc_rx(dev)) {
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ retcode = nv_alloc_rx(dev);
+ else
+ retcode = nv_alloc_rx_optimized(dev);
+ if (retcode) {
spin_lock_irq(&np->lock);
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
static int nv_init_ring(struct net_device *dev)
{
+ struct fe_priv *np = netdev_priv(dev);
+
nv_init_tx(dev);
nv_init_rx(dev);
- return nv_alloc_rx(dev);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ return nv_alloc_rx(dev);
+ else
+ return nv_alloc_rx_optimized(dev);
}
static int nv_release_txskb(struct net_device *dev, struct nv_skb_map* tx_skb)
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;
- union ring_type put_tx;
- union ring_type start_tx;
- union ring_type prev_tx;
+ struct ring_desc* put_tx;
+ struct ring_desc* start_tx;
+ struct ring_desc* prev_tx;
struct nv_skb_map* prev_tx_ctx;
/* add fragments to entries count */
((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
}
- spin_lock_irq(&np->lock);
-
empty_slots = nv_get_empty_tx_slots(np);
- if ((empty_slots - np->tx_limit_stop) <= entries) {
- spin_unlock_irq(&np->lock);
+ if (unlikely(empty_slots <= entries)) {
+ spin_lock_irq(&np->lock);
netif_stop_queue(dev);
+ np->tx_stop = 1;
+ spin_unlock_irq(&np->lock);
return NETDEV_TX_BUSY;
}
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- start_tx.orig = put_tx.orig = np->put_tx.orig;
- else
- start_tx.ex = put_tx.ex = np->put_tx.ex;
+ start_tx = put_tx = np->put_tx.orig;
/* setup the header buffer */
do {
np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
PCI_DMA_TODEVICE);
np->put_tx_ctx->dma_len = bcnt;
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- put_tx.orig->buf = cpu_to_le32(np->put_tx_ctx->dma);
- put_tx.orig->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- } else {
- put_tx.ex->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
- put_tx.ex->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
- put_tx.ex->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- }
+ 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 (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- if (put_tx.orig++ == np->last_tx.orig)
- put_tx.orig = np->first_tx.orig;
- } else {
- if (put_tx.ex++ == np->last_tx.ex)
- put_tx.ex = np->first_tx.ex;
- }
- if (np->put_tx_ctx++ == np->last_tx_ctx)
+ if (unlikely(put_tx++ == np->last_tx.orig))
+ put_tx = np->first_tx.orig;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
np->put_tx_ctx = np->first_tx_ctx;
} while (size);
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);
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- put_tx.orig->buf = cpu_to_le32(np->put_tx_ctx->dma);
- put_tx.orig->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- } else {
- put_tx.ex->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
- put_tx.ex->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
- put_tx.ex->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- }
offset += bcnt;
size -= bcnt;
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- if (put_tx.orig++ == np->last_tx.orig)
- put_tx.orig = np->first_tx.orig;
- } else {
- if (put_tx.ex++ == np->last_tx.ex)
- put_tx.ex = np->first_tx.ex;
- }
- if (np->put_tx_ctx++ == np->last_tx_ctx)
+ if (unlikely(put_tx++ == np->last_tx.orig))
+ put_tx = np->first_tx.orig;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
np->put_tx_ctx = np->first_tx_ctx;
} while (size);
}
/* set last fragment flag */
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- prev_tx.orig->flaglen |= cpu_to_le32(tx_flags_extra);
+ prev_tx->flaglen |= cpu_to_le32(tx_flags_extra);
+
+ /* save skb in this slot's context area */
+ prev_tx_ctx->skb = skb;
+
+ if (skb_is_gso(skb))
+ tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
else
- prev_tx.ex->flaglen |= cpu_to_le32(tx_flags_extra);
+ tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
+ NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
+
+ spin_lock_irq(&np->lock);
+
+ /* set tx flags */
+ start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ np->put_tx.orig = put_tx;
+
+ spin_unlock_irq(&np->lock);
+
+ dprintk(KERN_DEBUG "%s: nv_start_xmit: entries %d queued for transmission. tx_flags_extra: %x\n",
+ dev->name, entries, tx_flags_extra);
+ {
+ int j;
+ for (j=0; j<64; j++) {
+ if ((j%16) == 0)
+ dprintk("\n%03x:", j);
+ dprintk(" %02x", ((unsigned char*)skb->data)[j]);
+ }
+ dprintk("\n");
+ }
+
+ dev->trans_start = jiffies;
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+ return NETDEV_TX_OK;
+}
+
+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;
+ unsigned int fragments = skb_shinfo(skb)->nr_frags;
+ unsigned int i;
+ u32 offset = 0;
+ u32 bcnt;
+ 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;
+ struct ring_desc_ex* put_tx;
+ struct ring_desc_ex* start_tx;
+ struct ring_desc_ex* prev_tx;
+ struct nv_skb_map* prev_tx_ctx;
+
+ /* add fragments to entries count */
+ for (i = 0; i < fragments; i++) {
+ entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) +
+ ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+ }
+
+ empty_slots = nv_get_empty_tx_slots(np);
+ if (unlikely(empty_slots <= entries)) {
+ spin_lock_irq(&np->lock);
+ netif_stop_queue(dev);
+ np->tx_stop = 1;
+ spin_unlock_irq(&np->lock);
+ return NETDEV_TX_BUSY;
+ }
+
+ start_tx = put_tx = np->put_tx.ex;
+
+ /* setup the header buffer */
+ do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
+ bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+ np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + 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);
+
+ tx_flags = NV_TX2_VALID;
+ offset += bcnt;
+ size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.ex))
+ put_tx = np->first_tx.ex;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
+ } while (size);
+
+ /* setup the fragments */
+ for (i = 0; i < fragments; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ u32 size = frag->size;
+ offset = 0;
+
+ do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
+ bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+ 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 (unlikely(put_tx++ == np->last_tx.ex))
+ put_tx = np->first_tx.ex;
+ 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(NV_TX2_LASTPACKET);
/* save skb in this slot's context area */
prev_tx_ctx->skb = skb;
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 */
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- start_tx.orig->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
- np->put_tx.orig = put_tx.orig;
- } else {
- start_tx.ex->txvlan = cpu_to_le32(tx_flags_vlan);
- start_tx.ex->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
- np->put_tx.ex = put_tx.ex;
- }
+ start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ np->put_tx.ex = put_tx;
+ spin_unlock_irq(&np->lock);
- dprintk(KERN_DEBUG "%s: nv_start_xmit: entries %d queued for transmission. tx_flags_extra: %x\n",
+ dprintk(KERN_DEBUG "%s: nv_start_xmit_optimized: entries %d queued for transmission. tx_flags_extra: %x\n",
dev->name, entries, tx_flags_extra);
{
int j;
}
dev->trans_start = jiffies;
- spin_unlock_irq(&np->lock);
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
- pci_push(get_hwbase(dev));
return NETDEV_TX_OK;
}
{
struct fe_priv *np = netdev_priv(dev);
u32 flags;
- struct sk_buff *skb;
+ struct ring_desc* orig_get_tx = np->get_tx.orig;
- while (1) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- if (np->get_tx.orig == np->put_tx.orig)
- break;
- flags = le32_to_cpu(np->get_tx.orig->flaglen);
- } else {
- if (np->get_tx.ex == np->put_tx.ex)
- break;
- flags = le32_to_cpu(np->get_tx.ex->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)
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)
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->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- if (np->get_tx.orig++ == np->last_tx.orig)
- np->get_tx.orig = np->first_tx.orig;
- } else {
- if (np->get_tx.ex++ == np->last_tx.ex)
- np->get_tx.ex = np->first_tx.ex;
+ if (unlikely(np->get_tx.orig++ == np->last_tx.orig))
+ np->get_tx.orig = np->first_tx.orig;
+ if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
+ np->get_tx_ctx = np->first_tx_ctx;
+ }
+ 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, int limit)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u32 flags;
+ struct ring_desc_ex* orig_get_tx = np->get_tx.ex;
+
+ while ((np->get_tx.ex != np->put_tx.ex) &&
+ !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) &&
+ (limit-- > 0)) {
+
+ dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n",
+ dev->name, flags);
+
+ 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) {
+ if (!(flags & NV_TX2_ERROR))
+ np->stats.tx_packets++;
+ dev_kfree_skb_any(np->get_tx_ctx->skb);
+ np->get_tx_ctx->skb = NULL;
}
- if (np->get_tx_ctx++ == np->last_tx_ctx)
+ if (unlikely(np->get_tx.ex++ == np->last_tx.ex))
+ np->get_tx.ex = np->first_tx.ex;
+ if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
np->get_tx_ctx = np->first_tx_ctx;
}
- if (nv_get_empty_tx_slots(np) > np->tx_limit_start)
+ if (unlikely((np->tx_stop == 1) && (np->get_tx.ex != orig_get_tx))) {
+ np->tx_stop = 0;
netif_wake_queue(dev);
+ }
}
/*
nv_stop_tx(dev);
/* 2) check that the packets were not sent already: */
- nv_tx_done(dev);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ nv_tx_done(dev);
+ else
+ 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) {
}
}
-static int nv_rx_process(struct net_device *dev, int limit)
+static int nv_rx_process(struct net_device *dev, int limit)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u32 flags;
+ u32 rx_processed_cnt = 0;
+ struct sk_buff *skb;
+ int len;
+
+ 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);
+
+ /*
+ * the packet is for us - immediately tear down the pci mapping.
+ * TODO: check if a prefetch of the first cacheline improves
+ * the performance.
+ */
+ pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma,
+ np->get_rx_ctx->dma_len,
+ PCI_DMA_FROMDEVICE);
+ skb = np->get_rx_ctx->skb;
+ np->get_rx_ctx->skb = NULL;
+
+ {
+ int j;
+ dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
+ for (j=0; j<64; j++) {
+ if ((j%16) == 0)
+ dprintk("\n%03x:", j);
+ dprintk(" %02x", ((unsigned char*)skb->data)[j]);
+ }
+ dprintk("\n");
+ }
+ /* look at what we actually got: */
+ if (np->desc_ver == DESC_VER_1) {
+ 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;
+ }
+ }
+ } else {
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
+ } 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;
+ }
+ }
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ 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 */
+ 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);
+#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;
+next_pkt:
+ if (unlikely(np->get_rx.orig++ == np->last_rx.orig))
+ np->get_rx.orig = np->first_rx.orig;
+ if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
+ np->get_rx_ctx = np->first_rx_ctx;
+ }
+
+ return rx_processed_cnt;
+}
+
+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->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- 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);
- } else {
- 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: flags 0x%x.\n",
+ 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
pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma,
np->get_rx_ctx->dma_len,
PCI_DMA_FROMDEVICE);
+ skb = np->get_rx_ctx->skb;
+ np->get_rx_ctx->skb = NULL;
{
int j;
for (j=0; j<64; j++) {
if ((j%16) == 0)
dprintk("\n%03x:", j);
- dprintk(" %02x", ((unsigned char*)np->get_rx_ctx->skb->data)[j]);
+ dprintk(" %02x", ((unsigned char*)skb->data)[j]);
}
dprintk("\n");
}
/* look at what we actually got: */
- if (np->desc_ver == DESC_VER_1) {
- if (!(flags & NV_RX_DESCRIPTORVALID))
- goto next_pkt;
-
- 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)) {
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX_CRCERR) {
- np->stats.rx_crc_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX_OVERFLOW) {
- np->stats.rx_over_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX_ERROR4) {
- len = nv_getlen(dev, np->get_rx_ctx->skb->data, len);
- if (len < 0) {
- np->stats.rx_errors++;
- 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))
- goto next_pkt;
-
- 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) {
- np->stats.rx_crc_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX2_OVERFLOW) {
- np->stats.rx_over_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
+ 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, np->get_rx_ctx->skb->data, len);
+ 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 */
- if (flags & NV_RX2_FRAMINGERR) {
+ 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;
+ }
}
- 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);
- np->get_rx_ctx->skb->ip_summed = CHECKSUM_UNNECESSARY;
- } else {
- dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name);
+
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ 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 = np->get_rx_ctx->skb;
- np->get_rx_ctx->skb = NULL;
- 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;
-next_pkt:
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- if (np->get_rx.orig++ == np->last_rx.orig)
- np->get_rx.orig = np->first_rx.orig;
+ } 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 {
- if (np->get_rx.ex++ == np->last_rx.ex)
- np->get_rx.ex = np->first_rx.ex;
+ dev_kfree_skb(skb);
}
- if (np->get_rx_ctx++ == np->last_rx_ctx)
+next_pkt:
+ if (unlikely(np->get_rx.ex++ == np->last_rx.ex))
+ np->get_rx.ex = np->first_rx.ex;
+ 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)
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;
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);
}
spin_unlock(&np->lock);
break;
}
+ if (unlikely(i > max_interrupt_work)) {
+ spin_lock(&np->lock);
+ /* disable interrupts on the nic */
+ if (!(np->msi_flags & NV_MSI_X_ENABLED))
+ writel(0, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ pci_push(base);
+
+ if (!np->in_shutdown) {
+ np->nic_poll_irq = np->irqmask;
+ mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+ }
+ printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
+ spin_unlock(&np->lock);
+ break;
+ }
+
+ }
+ dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
+
+ 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;
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ u32 events;
+ int i;
+
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name);
+
+ for (i=0; ; i++) {
+ if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+ events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
+ writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
+ } else {
+ events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
+ writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
+ }
+ dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
+ if (!(events & np->irqmask))
+ break;
+
+ spin_lock(&np->lock);
+ nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+ spin_unlock(&np->lock);
+
#ifdef CONFIG_FORCEDETH_NAPI
if (events & NVREG_IRQ_RX_ALL) {
netif_rx_schedule(dev);
spin_unlock(&np->lock);
}
#else
- nv_rx_process(dev, dev->weight);
- if (nv_alloc_rx(dev)) {
+ 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);
- if (!np->in_shutdown)
- mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ nv_link_irq(dev);
spin_unlock(&np->lock);
}
-#endif
- if (i > max_interrupt_work) {
+ if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+ spin_lock(&np->lock);
+ nv_linkchange(dev);
+ spin_unlock(&np->lock);
+ np->link_timeout = jiffies + LINK_TIMEOUT;
+ }
+ if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
+ dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
+ dev->name, events);
+ }
+ if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
+ printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
+ dev->name, events);
+ }
+ if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) {
+ spin_lock(&np->lock);
+ /* disable interrupts on the nic */
+ if (!(np->msi_flags & NV_MSI_X_ENABLED))
+ writel(0, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ pci_push(base);
+
+ if (!np->in_shutdown) {
+ np->nic_poll_irq = np->irqmask;
+ np->recover_error = 1;
+ mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+ }
+ spin_unlock(&np->lock);
+ break;
+ }
+
+ if (unlikely(i > max_interrupt_work)) {
spin_lock(&np->lock);
/* disable interrupts on the nic */
if (!(np->msi_flags & NV_MSI_X_ENABLED))
}
}
- dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name);
return IRQ_RETVAL(i);
}
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(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);
u8 __iomem *base = get_hwbase(dev);
unsigned long flags;
- pkts = nv_rx_process(dev, limit);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ pkts = nv_rx_process(dev, limit);
+ else
+ pkts = nv_rx_process_optimized(dev, limit);
if (nv_alloc_rx(dev)) {
spin_lock_irqsave(&np->lock, flags);
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(dev, dev->weight);
- if (nv_alloc_rx(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);
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);
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);
u8 __iomem *base = get_hwbase(dev);
int ret = 1;
int i;
+ irqreturn_t (*handler)(int foo, void *data);
+
+ if (intr_test) {
+ handler = nv_nic_irq_test;
+ } else {
+ if (np->desc_ver == DESC_VER_3)
+ handler = nv_nic_irq_optimized;
+ else
+ handler = nv_nic_irq;
+ }
if (np->msi_flags & NV_MSI_X_CAPABLE) {
for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) {
set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER);
} else {
/* Request irq for all interrupts */
- if ((!intr_test &&
- 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, IRQF_SHARED, dev->name, dev) != 0)) {
+ if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, handler, 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;
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, IRQF_SHARED, dev->name, dev) != 0) ||
- (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
+ if (request_irq(np->pci_dev->irq, handler, 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;
}
}
if (ret != 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))
+ if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0)
goto out_err;
}
{
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);
/* set new values */
np->rx_ring_size = ring->rx_pending;
np->tx_ring_size = ring->tx_pending;
- np->tx_limit_stop = TX_LIMIT_DIFFERENCE;
- np->tx_limit_start = TX_LIMIT_DIFFERENCE;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig = (struct ring_desc*)rxtx_ring;
np->tx_ring.orig = &np->rx_ring.orig[np->rx_ring_size];
{
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;
}
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);
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;
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) {
np->rx_ring_size = RX_RING_DEFAULT;
np->tx_ring_size = TX_RING_DEFAULT;
- np->tx_limit_stop = TX_LIMIT_DIFFERENCE;
- np->tx_limit_start = TX_LIMIT_DIFFERENCE;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig = pci_alloc_consistent(pci_dev,
dev->open = nv_open;
dev->stop = nv_close;
- dev->hard_start_xmit = nv_start_xmit;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ dev->hard_start_xmit = nv_start_xmit;
+ else
+ dev->hard_start_xmit = nv_start_xmit_optimized;
dev->get_stats = nv_get_stats;
dev->change_mtu = nv_change_mtu;
dev->set_mac_address = nv_set_mac_address;
#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
},
{ /* 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_CHECKSUM|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_CHECKSUM|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_CHECKSUM|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_CHECKSUM|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,},
};