[PATCH] forcedeth config: ring sizes
This patch allows for configurable ring size through ethtool support. Signed-Off-By: Ayaz Abdulla <aabdulla@nvidia.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
Родитель
6a78814f6c
Коммит
eafa59f6bc
|
@ -456,16 +456,18 @@ typedef union _ring_type {
|
|||
/* General driver defaults */
|
||||
#define NV_WATCHDOG_TIMEO (5*HZ)
|
||||
|
||||
#define RX_RING 128
|
||||
#define TX_RING 256
|
||||
#define RX_RING_DEFAULT 128
|
||||
#define TX_RING_DEFAULT 256
|
||||
#define RX_RING_MIN 128
|
||||
#define TX_RING_MIN 64
|
||||
#define RING_MAX_DESC_VER_1 1024
|
||||
#define RING_MAX_DESC_VER_2_3 16384
|
||||
/*
|
||||
* If your nic mysteriously hangs then try to reduce the limits
|
||||
* to 1/0: It might be required to set NV_TX_LASTPACKET in the
|
||||
* last valid ring entry. But this would be impossible to
|
||||
* implement - probably a disassembly error.
|
||||
* 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_STOP 255
|
||||
#define TX_LIMIT_START 254
|
||||
#define TX_LIMIT_DIFFERENCE 1
|
||||
|
||||
/* rx/tx mac addr + type + vlan + align + slack*/
|
||||
#define NV_RX_HEADERS (64)
|
||||
|
@ -577,13 +579,14 @@ struct fe_priv {
|
|||
*/
|
||||
ring_type rx_ring;
|
||||
unsigned int cur_rx, refill_rx;
|
||||
struct sk_buff *rx_skbuff[RX_RING];
|
||||
dma_addr_t rx_dma[RX_RING];
|
||||
struct sk_buff **rx_skbuff;
|
||||
dma_addr_t *rx_dma;
|
||||
unsigned int rx_buf_sz;
|
||||
unsigned int pkt_limit;
|
||||
struct timer_list oom_kick;
|
||||
struct timer_list nic_poll;
|
||||
u32 nic_poll_irq;
|
||||
int rx_ring_size;
|
||||
|
||||
/* media detection workaround.
|
||||
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
|
||||
|
@ -595,10 +598,13 @@ struct fe_priv {
|
|||
*/
|
||||
ring_type tx_ring;
|
||||
unsigned int next_tx, nic_tx;
|
||||
struct sk_buff *tx_skbuff[TX_RING];
|
||||
dma_addr_t tx_dma[TX_RING];
|
||||
unsigned int tx_dma_len[TX_RING];
|
||||
struct sk_buff **tx_skbuff;
|
||||
dma_addr_t *tx_dma;
|
||||
unsigned int *tx_dma_len;
|
||||
u32 tx_flags;
|
||||
int tx_ring_size;
|
||||
int tx_limit_start;
|
||||
int tx_limit_stop;
|
||||
|
||||
/* vlan fields */
|
||||
struct vlan_group *vlangrp;
|
||||
|
@ -704,7 +710,7 @@ static void setup_hw_rings(struct net_device *dev, int rxtx_flags)
|
|||
writel((u32) cpu_to_le64(np->ring_addr), base + NvRegRxRingPhysAddr);
|
||||
}
|
||||
if (rxtx_flags & NV_SETUP_TX_RING) {
|
||||
writel((u32) cpu_to_le64(np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
|
||||
writel((u32) cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
|
||||
}
|
||||
} else {
|
||||
if (rxtx_flags & NV_SETUP_RX_RING) {
|
||||
|
@ -712,12 +718,37 @@ static void setup_hw_rings(struct net_device *dev, int rxtx_flags)
|
|||
writel((u32) (cpu_to_le64(np->ring_addr) >> 32), base + NvRegRxRingPhysAddrHigh);
|
||||
}
|
||||
if (rxtx_flags & NV_SETUP_TX_RING) {
|
||||
writel((u32) cpu_to_le64(np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
|
||||
writel((u32) (cpu_to_le64(np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)) >> 32), base + NvRegTxRingPhysAddrHigh);
|
||||
writel((u32) cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
|
||||
writel((u32) (cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)) >> 32), base + NvRegTxRingPhysAddrHigh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void free_rings(struct net_device *dev)
|
||||
{
|
||||
struct fe_priv *np = get_nvpriv(dev);
|
||||
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
|
||||
if(np->rx_ring.orig)
|
||||
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (np->rx_ring_size + np->tx_ring_size),
|
||||
np->rx_ring.orig, np->ring_addr);
|
||||
} else {
|
||||
if (np->rx_ring.ex)
|
||||
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size),
|
||||
np->rx_ring.ex, np->ring_addr);
|
||||
}
|
||||
if (np->rx_skbuff)
|
||||
kfree(np->rx_skbuff);
|
||||
if (np->rx_dma)
|
||||
kfree(np->rx_dma);
|
||||
if (np->tx_skbuff)
|
||||
kfree(np->tx_skbuff);
|
||||
if (np->tx_dma)
|
||||
kfree(np->tx_dma);
|
||||
if (np->tx_dma_len)
|
||||
kfree(np->tx_dma_len);
|
||||
}
|
||||
|
||||
static int using_multi_irqs(struct net_device *dev)
|
||||
{
|
||||
struct fe_priv *np = get_nvpriv(dev);
|
||||
|
@ -1056,7 +1087,7 @@ static int nv_alloc_rx(struct net_device *dev)
|
|||
while (np->cur_rx != refill_rx) {
|
||||
struct sk_buff *skb;
|
||||
|
||||
nr = refill_rx % RX_RING;
|
||||
nr = refill_rx % np->rx_ring_size;
|
||||
if (np->rx_skbuff[nr] == NULL) {
|
||||
|
||||
skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
|
||||
|
@ -1085,7 +1116,7 @@ static int nv_alloc_rx(struct net_device *dev)
|
|||
refill_rx++;
|
||||
}
|
||||
np->refill_rx = refill_rx;
|
||||
if (np->cur_rx - refill_rx == RX_RING)
|
||||
if (np->cur_rx - refill_rx == np->rx_ring_size)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1124,9 +1155,9 @@ static void nv_init_rx(struct net_device *dev)
|
|||
struct fe_priv *np = netdev_priv(dev);
|
||||
int i;
|
||||
|
||||
np->cur_rx = RX_RING;
|
||||
np->cur_rx = np->rx_ring_size;
|
||||
np->refill_rx = 0;
|
||||
for (i = 0; i < RX_RING; i++)
|
||||
for (i = 0; i < np->rx_ring_size; i++)
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
|
||||
np->rx_ring.orig[i].FlagLen = 0;
|
||||
else
|
||||
|
@ -1139,7 +1170,7 @@ static void nv_init_tx(struct net_device *dev)
|
|||
int i;
|
||||
|
||||
np->next_tx = np->nic_tx = 0;
|
||||
for (i = 0; i < TX_RING; i++) {
|
||||
for (i = 0; i < np->tx_ring_size; i++) {
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
|
||||
np->tx_ring.orig[i].FlagLen = 0;
|
||||
else
|
||||
|
@ -1184,7 +1215,7 @@ static void nv_drain_tx(struct net_device *dev)
|
|||
struct fe_priv *np = netdev_priv(dev);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < TX_RING; i++) {
|
||||
for (i = 0; i < np->tx_ring_size; i++) {
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
|
||||
np->tx_ring.orig[i].FlagLen = 0;
|
||||
else
|
||||
|
@ -1198,7 +1229,7 @@ static void nv_drain_rx(struct net_device *dev)
|
|||
{
|
||||
struct fe_priv *np = netdev_priv(dev);
|
||||
int i;
|
||||
for (i = 0; i < RX_RING; i++) {
|
||||
for (i = 0; i < np->rx_ring_size; i++) {
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
|
||||
np->rx_ring.orig[i].FlagLen = 0;
|
||||
else
|
||||
|
@ -1230,8 +1261,8 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
u32 tx_flags = 0;
|
||||
u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
|
||||
unsigned int fragments = skb_shinfo(skb)->nr_frags;
|
||||
unsigned int nr = (np->next_tx - 1) % TX_RING;
|
||||
unsigned int start_nr = np->next_tx % TX_RING;
|
||||
unsigned int nr = (np->next_tx - 1) % np->tx_ring_size;
|
||||
unsigned int start_nr = np->next_tx % np->tx_ring_size;
|
||||
unsigned int i;
|
||||
u32 offset = 0;
|
||||
u32 bcnt;
|
||||
|
@ -1247,7 +1278,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
|
||||
spin_lock_irq(&np->lock);
|
||||
|
||||
if ((np->next_tx - np->nic_tx + entries - 1) > TX_LIMIT_STOP) {
|
||||
if ((np->next_tx - np->nic_tx + entries - 1) > np->tx_limit_stop) {
|
||||
spin_unlock_irq(&np->lock);
|
||||
netif_stop_queue(dev);
|
||||
return NETDEV_TX_BUSY;
|
||||
|
@ -1256,7 +1287,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
/* setup the header buffer */
|
||||
do {
|
||||
bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
|
||||
nr = (nr + 1) % TX_RING;
|
||||
nr = (nr + 1) % np->tx_ring_size;
|
||||
|
||||
np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
|
||||
PCI_DMA_TODEVICE);
|
||||
|
@ -1283,7 +1314,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
|
||||
do {
|
||||
bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
|
||||
nr = (nr + 1) % TX_RING;
|
||||
nr = (nr + 1) % np->tx_ring_size;
|
||||
|
||||
np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
|
||||
PCI_DMA_TODEVICE);
|
||||
|
@ -1365,7 +1396,7 @@ static void nv_tx_done(struct net_device *dev)
|
|||
struct sk_buff *skb;
|
||||
|
||||
while (np->nic_tx != np->next_tx) {
|
||||
i = np->nic_tx % TX_RING;
|
||||
i = np->nic_tx % np->tx_ring_size;
|
||||
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
|
||||
Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen);
|
||||
|
@ -1410,7 +1441,7 @@ static void nv_tx_done(struct net_device *dev)
|
|||
nv_release_txskb(dev, i);
|
||||
np->nic_tx++;
|
||||
}
|
||||
if (np->next_tx - np->nic_tx < TX_LIMIT_START)
|
||||
if (np->next_tx - np->nic_tx < np->tx_limit_start)
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
|
@ -1447,7 +1478,7 @@ static void nv_tx_timeout(struct net_device *dev)
|
|||
readl(base + i + 24), readl(base + i + 28));
|
||||
}
|
||||
printk(KERN_INFO "%s: Dumping tx ring\n", dev->name);
|
||||
for (i=0;i<TX_RING;i+= 4) {
|
||||
for (i=0;i<np->tx_ring_size;i+= 4) {
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
|
||||
printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
|
||||
i,
|
||||
|
@ -1563,10 +1594,10 @@ static void nv_rx_process(struct net_device *dev)
|
|||
struct sk_buff *skb;
|
||||
int len;
|
||||
int i;
|
||||
if (np->cur_rx - np->refill_rx >= RX_RING)
|
||||
if (np->cur_rx - np->refill_rx >= np->rx_ring_size)
|
||||
break; /* we scanned the whole ring - do not continue */
|
||||
|
||||
i = np->cur_rx % RX_RING;
|
||||
i = np->cur_rx % np->rx_ring_size;
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
|
||||
Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen);
|
||||
len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
|
||||
|
@ -1755,18 +1786,15 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)
|
|||
nv_drain_rx(dev);
|
||||
nv_drain_tx(dev);
|
||||
/* reinit driver view of the rx queue */
|
||||
nv_init_rx(dev);
|
||||
nv_init_tx(dev);
|
||||
/* alloc new rx buffers */
|
||||
set_bufsize(dev);
|
||||
if (nv_alloc_rx(dev)) {
|
||||
if (nv_init_ring(dev)) {
|
||||
if (!np->in_shutdown)
|
||||
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
|
||||
}
|
||||
/* reinit nic view of the rx queue */
|
||||
writel(np->rx_buf_sz, base + NvRegOffloadConfig);
|
||||
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
|
||||
writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
|
||||
writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
|
||||
base + NvRegRingSizes);
|
||||
pci_push(base);
|
||||
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
|
||||
|
@ -2685,6 +2713,149 @@ static int nv_set_tso(struct net_device *dev, u32 value)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static void nv_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
|
||||
{
|
||||
struct fe_priv *np = netdev_priv(dev);
|
||||
|
||||
ring->rx_max_pending = (np->desc_ver == DESC_VER_1) ? RING_MAX_DESC_VER_1 : RING_MAX_DESC_VER_2_3;
|
||||
ring->rx_mini_max_pending = 0;
|
||||
ring->rx_jumbo_max_pending = 0;
|
||||
ring->tx_max_pending = (np->desc_ver == DESC_VER_1) ? RING_MAX_DESC_VER_1 : RING_MAX_DESC_VER_2_3;
|
||||
|
||||
ring->rx_pending = np->rx_ring_size;
|
||||
ring->rx_mini_pending = 0;
|
||||
ring->rx_jumbo_pending = 0;
|
||||
ring->tx_pending = np->tx_ring_size;
|
||||
}
|
||||
|
||||
static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
|
||||
{
|
||||
struct fe_priv *np = netdev_priv(dev);
|
||||
u8 __iomem *base = get_hwbase(dev);
|
||||
u8 *rxtx_ring, *rx_skbuff, *tx_skbuff, *rx_dma, *tx_dma, *tx_dma_len;
|
||||
dma_addr_t ring_addr;
|
||||
|
||||
if (ring->rx_pending < RX_RING_MIN ||
|
||||
ring->tx_pending < TX_RING_MIN ||
|
||||
ring->rx_mini_pending != 0 ||
|
||||
ring->rx_jumbo_pending != 0 ||
|
||||
(np->desc_ver == DESC_VER_1 &&
|
||||
(ring->rx_pending > RING_MAX_DESC_VER_1 ||
|
||||
ring->tx_pending > RING_MAX_DESC_VER_1)) ||
|
||||
(np->desc_ver != DESC_VER_1 &&
|
||||
(ring->rx_pending > RING_MAX_DESC_VER_2_3 ||
|
||||
ring->tx_pending > RING_MAX_DESC_VER_2_3))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* allocate new rings */
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
|
||||
rxtx_ring = pci_alloc_consistent(np->pci_dev,
|
||||
sizeof(struct ring_desc) * (ring->rx_pending + ring->tx_pending),
|
||||
&ring_addr);
|
||||
} else {
|
||||
rxtx_ring = pci_alloc_consistent(np->pci_dev,
|
||||
sizeof(struct ring_desc_ex) * (ring->rx_pending + ring->tx_pending),
|
||||
&ring_addr);
|
||||
}
|
||||
rx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->rx_pending, GFP_KERNEL);
|
||||
rx_dma = kmalloc(sizeof(dma_addr_t) * ring->rx_pending, GFP_KERNEL);
|
||||
tx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->tx_pending, GFP_KERNEL);
|
||||
tx_dma = kmalloc(sizeof(dma_addr_t) * ring->tx_pending, GFP_KERNEL);
|
||||
tx_dma_len = kmalloc(sizeof(unsigned int) * ring->tx_pending, GFP_KERNEL);
|
||||
if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) {
|
||||
/* fall back to old rings */
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
|
||||
if(rxtx_ring)
|
||||
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (ring->rx_pending + ring->tx_pending),
|
||||
rxtx_ring, ring_addr);
|
||||
} else {
|
||||
if (rxtx_ring)
|
||||
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (ring->rx_pending + ring->tx_pending),
|
||||
rxtx_ring, ring_addr);
|
||||
}
|
||||
if (rx_skbuff)
|
||||
kfree(rx_skbuff);
|
||||
if (rx_dma)
|
||||
kfree(rx_dma);
|
||||
if (tx_skbuff)
|
||||
kfree(tx_skbuff);
|
||||
if (tx_dma)
|
||||
kfree(tx_dma);
|
||||
if (tx_dma_len)
|
||||
kfree(tx_dma_len);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (netif_running(dev)) {
|
||||
nv_disable_irq(dev);
|
||||
spin_lock_bh(&dev->xmit_lock);
|
||||
spin_lock(&np->lock);
|
||||
/* stop engines */
|
||||
nv_stop_rx(dev);
|
||||
nv_stop_tx(dev);
|
||||
nv_txrx_reset(dev);
|
||||
/* drain queues */
|
||||
nv_drain_rx(dev);
|
||||
nv_drain_tx(dev);
|
||||
/* delete queues */
|
||||
free_rings(dev);
|
||||
}
|
||||
|
||||
/* set new values */
|
||||
np->rx_ring_size = ring->rx_pending;
|
||||
np->tx_ring_size = ring->tx_pending;
|
||||
np->tx_limit_stop = ring->tx_pending - TX_LIMIT_DIFFERENCE;
|
||||
np->tx_limit_start = ring->tx_pending - TX_LIMIT_DIFFERENCE - 1;
|
||||
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];
|
||||
} else {
|
||||
np->rx_ring.ex = (struct ring_desc_ex*)rxtx_ring;
|
||||
np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
|
||||
}
|
||||
np->rx_skbuff = (struct sk_buff**)rx_skbuff;
|
||||
np->rx_dma = (dma_addr_t*)rx_dma;
|
||||
np->tx_skbuff = (struct sk_buff**)tx_skbuff;
|
||||
np->tx_dma = (dma_addr_t*)tx_dma;
|
||||
np->tx_dma_len = (unsigned int*)tx_dma_len;
|
||||
np->ring_addr = ring_addr;
|
||||
|
||||
memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
|
||||
memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
|
||||
memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
|
||||
memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
|
||||
memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
|
||||
|
||||
if (netif_running(dev)) {
|
||||
/* reinit driver view of the queues */
|
||||
set_bufsize(dev);
|
||||
if (nv_init_ring(dev)) {
|
||||
if (!np->in_shutdown)
|
||||
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
|
||||
}
|
||||
|
||||
/* reinit nic view of the queues */
|
||||
writel(np->rx_buf_sz, base + NvRegOffloadConfig);
|
||||
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
|
||||
writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
|
||||
base + NvRegRingSizes);
|
||||
pci_push(base);
|
||||
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
|
||||
pci_push(base);
|
||||
|
||||
/* restart engines */
|
||||
nv_start_rx(dev);
|
||||
nv_start_tx(dev);
|
||||
spin_unlock(&np->lock);
|
||||
spin_unlock_bh(&dev->xmit_lock);
|
||||
nv_enable_irq(dev);
|
||||
}
|
||||
return 0;
|
||||
exit:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static struct ethtool_ops ops = {
|
||||
.get_drvinfo = nv_get_drvinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
|
@ -2698,6 +2869,8 @@ static struct ethtool_ops ops = {
|
|||
.get_perm_addr = ethtool_op_get_perm_addr,
|
||||
.get_tso = ethtool_op_get_tso,
|
||||
.set_tso = nv_set_tso,
|
||||
.get_ringparam = nv_get_ringparam,
|
||||
.set_ringparam = nv_set_ringparam,
|
||||
};
|
||||
|
||||
static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
|
||||
|
@ -2904,7 +3077,7 @@ static int nv_open(struct net_device *dev)
|
|||
|
||||
/* 4) give hw rings */
|
||||
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
|
||||
writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
|
||||
writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
|
||||
base + NvRegRingSizes);
|
||||
|
||||
/* 5) continue setup */
|
||||
|
@ -3187,21 +3360,38 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
|
|||
|
||||
dev->irq = pci_dev->irq;
|
||||
|
||||
np->rx_ring_size = RX_RING_DEFAULT;
|
||||
np->tx_ring_size = TX_RING_DEFAULT;
|
||||
np->tx_limit_stop = np->tx_ring_size - TX_LIMIT_DIFFERENCE;
|
||||
np->tx_limit_start = np->tx_ring_size - TX_LIMIT_DIFFERENCE - 1;
|
||||
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
|
||||
np->rx_ring.orig = pci_alloc_consistent(pci_dev,
|
||||
sizeof(struct ring_desc) * (RX_RING + TX_RING),
|
||||
sizeof(struct ring_desc) * (np->rx_ring_size + np->tx_ring_size),
|
||||
&np->ring_addr);
|
||||
if (!np->rx_ring.orig)
|
||||
goto out_unmap;
|
||||
np->tx_ring.orig = &np->rx_ring.orig[RX_RING];
|
||||
np->tx_ring.orig = &np->rx_ring.orig[np->rx_ring_size];
|
||||
} else {
|
||||
np->rx_ring.ex = pci_alloc_consistent(pci_dev,
|
||||
sizeof(struct ring_desc_ex) * (RX_RING + TX_RING),
|
||||
sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size),
|
||||
&np->ring_addr);
|
||||
if (!np->rx_ring.ex)
|
||||
goto out_unmap;
|
||||
np->tx_ring.ex = &np->rx_ring.ex[RX_RING];
|
||||
np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
|
||||
}
|
||||
np->rx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->rx_ring_size, GFP_KERNEL);
|
||||
np->rx_dma = kmalloc(sizeof(dma_addr_t) * np->rx_ring_size, GFP_KERNEL);
|
||||
np->tx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->tx_ring_size, GFP_KERNEL);
|
||||
np->tx_dma = kmalloc(sizeof(dma_addr_t) * np->tx_ring_size, GFP_KERNEL);
|
||||
np->tx_dma_len = kmalloc(sizeof(unsigned int) * np->tx_ring_size, GFP_KERNEL);
|
||||
if (!np->rx_skbuff || !np->rx_dma || !np->tx_skbuff || !np->tx_dma || !np->tx_dma_len)
|
||||
goto out_freering;
|
||||
memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
|
||||
memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
|
||||
memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
|
||||
memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
|
||||
memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
|
||||
|
||||
dev->open = nv_open;
|
||||
dev->stop = nv_close;
|
||||
|
@ -3323,7 +3513,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
|
|||
if (i == 33) {
|
||||
printk(KERN_INFO "%s: open: Could not find a valid PHY.\n",
|
||||
pci_name(pci_dev));
|
||||
goto out_freering;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
/* reset it */
|
||||
|
@ -3337,7 +3527,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
|
|||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
printk(KERN_INFO "forcedeth: unable to register netdev: %d\n", err);
|
||||
goto out_freering;
|
||||
goto out_error;
|
||||
}
|
||||
printk(KERN_INFO "%s: forcedeth.c: subsystem: %05x:%04x bound to %s\n",
|
||||
dev->name, pci_dev->subsystem_vendor, pci_dev->subsystem_device,
|
||||
|
@ -3345,14 +3535,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
|
|||
|
||||
return 0;
|
||||
|
||||
out_freering:
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
|
||||
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
|
||||
np->rx_ring.orig, np->ring_addr);
|
||||
else
|
||||
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING),
|
||||
np->rx_ring.ex, np->ring_addr);
|
||||
out_error:
|
||||
pci_set_drvdata(pci_dev, NULL);
|
||||
out_freering:
|
||||
free_rings(dev);
|
||||
out_unmap:
|
||||
iounmap(get_hwbase(dev));
|
||||
out_relreg:
|
||||
|
@ -3368,15 +3554,11 @@ out:
|
|||
static void __devexit nv_remove(struct pci_dev *pci_dev)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pci_dev);
|
||||
struct fe_priv *np = netdev_priv(dev);
|
||||
|
||||
unregister_netdev(dev);
|
||||
|
||||
/* free all structures */
|
||||
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
|
||||
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring.orig, np->ring_addr);
|
||||
else
|
||||
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), np->rx_ring.ex, np->ring_addr);
|
||||
free_rings(dev);
|
||||
iounmap(get_hwbase(dev));
|
||||
pci_release_regions(pci_dev);
|
||||
pci_disable_device(pci_dev);
|
||||
|
|
Загрузка…
Ссылка в новой задаче