aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bnx2.c
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2006-03-20 17:49:20 -0800
committerDavid S. Miller <davem@davemloft.net>2006-03-20 17:49:20 -0800
commit13daffa2f2ba65674e7816a0e95e7b93246cb686 (patch)
tree3170a19dfba530398d4f12e54a21400254fa98b1 /drivers/net/bnx2.c
parent[BNX2]: Fix bug when rx ring is full (diff)
downloadlinux-dev-13daffa2f2ba65674e7816a0e95e7b93246cb686.tar.xz
linux-dev-13daffa2f2ba65674e7816a0e95e7b93246cb686.zip
[BNX2]: Support larger rx ring sizes (part 1)
Increase maximum receive ring size from 255 to 1020 by supporting up to 4 linked pages of receive descriptors. To accomodate the higher memory usage, each physical descriptor page is allocated separately and the software ring that keeps track of the SKBs and the DMA addresses is allocated using vmalloc. Some of the receive-related fields in the bp structure are re- organized a bit for better locality of reference. The max. was reduced to 1020 from 4080 after discussion with David Miller. This patch contains ring init code changes only. This next patch contains rx data path code changes. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bnx2.c')
-rw-r--r--drivers/net/bnx2.c117
1 files changed, 85 insertions, 32 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 0d592f7c3a99..03c47cf04e90 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -360,6 +360,8 @@ bnx2_netif_start(struct bnx2 *bp)
static void
bnx2_free_mem(struct bnx2 *bp)
{
+ int i;
+
if (bp->stats_blk) {
pci_free_consistent(bp->pdev, sizeof(struct statistics_block),
bp->stats_blk, bp->stats_blk_mapping);
@@ -378,19 +380,23 @@ bnx2_free_mem(struct bnx2 *bp)
}
kfree(bp->tx_buf_ring);
bp->tx_buf_ring = NULL;
- if (bp->rx_desc_ring) {
- pci_free_consistent(bp->pdev,
- sizeof(struct rx_bd) * RX_DESC_CNT,
- bp->rx_desc_ring, bp->rx_desc_mapping);
- bp->rx_desc_ring = NULL;
- }
- kfree(bp->rx_buf_ring);
+ for (i = 0; i < bp->rx_max_ring; i++) {
+ if (bp->rx_desc_ring[i])
+ pci_free_consistent(bp->pdev,
+ sizeof(struct rx_bd) * RX_DESC_CNT,
+ bp->rx_desc_ring[i],
+ bp->rx_desc_mapping[i]);
+ bp->rx_desc_ring[i] = NULL;
+ }
+ vfree(bp->rx_buf_ring);
bp->rx_buf_ring = NULL;
}
static int
bnx2_alloc_mem(struct bnx2 *bp)
{
+ int i;
+
bp->tx_buf_ring = kmalloc(sizeof(struct sw_bd) * TX_DESC_CNT,
GFP_KERNEL);
if (bp->tx_buf_ring == NULL)
@@ -404,18 +410,23 @@ bnx2_alloc_mem(struct bnx2 *bp)
if (bp->tx_desc_ring == NULL)
goto alloc_mem_err;
- bp->rx_buf_ring = kmalloc(sizeof(struct sw_bd) * RX_DESC_CNT,
- GFP_KERNEL);
+ bp->rx_buf_ring = vmalloc(sizeof(struct sw_bd) * RX_DESC_CNT *
+ bp->rx_max_ring);
if (bp->rx_buf_ring == NULL)
goto alloc_mem_err;
- memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT);
- bp->rx_desc_ring = pci_alloc_consistent(bp->pdev,
- sizeof(struct rx_bd) *
- RX_DESC_CNT,
- &bp->rx_desc_mapping);
- if (bp->rx_desc_ring == NULL)
- goto alloc_mem_err;
+ memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT *
+ bp->rx_max_ring);
+
+ for (i = 0; i < bp->rx_max_ring; i++) {
+ bp->rx_desc_ring[i] =
+ pci_alloc_consistent(bp->pdev,
+ sizeof(struct rx_bd) * RX_DESC_CNT,
+ &bp->rx_desc_mapping[i]);
+ if (bp->rx_desc_ring[i] == NULL)
+ goto alloc_mem_err;
+
+ }
bp->status_blk = pci_alloc_consistent(bp->pdev,
sizeof(struct status_block),
@@ -1520,7 +1531,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
struct sk_buff *skb;
struct sw_bd *rx_buf = &bp->rx_buf_ring[index];
dma_addr_t mapping;
- struct rx_bd *rxbd = &bp->rx_desc_ring[index];
+ struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
unsigned long align;
skb = dev_alloc_skb(bp->rx_buf_size);
@@ -3349,24 +3360,32 @@ bnx2_init_rx_ring(struct bnx2 *bp)
bp->hw_rx_cons = 0;
bp->rx_prod_bseq = 0;
- rxbd = &bp->rx_desc_ring[0];
- for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) {
- rxbd->rx_bd_len = bp->rx_buf_use_size;
- rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
- }
+ for (i = 0; i < bp->rx_max_ring; i++) {
+ int j;
- rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping >> 32;
- rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping & 0xffffffff;
+ rxbd = &bp->rx_desc_ring[i][0];
+ for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
+ rxbd->rx_bd_len = bp->rx_buf_use_size;
+ rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
+ }
+ if (i == (bp->rx_max_ring - 1))
+ j = 0;
+ else
+ j = i + 1;
+ rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping[j] >> 32;
+ rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping[j] &
+ 0xffffffff;
+ }
val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
val |= 0x02 << 8;
CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val);
- val = (u64) bp->rx_desc_mapping >> 32;
+ val = (u64) bp->rx_desc_mapping[0] >> 32;
CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, val);
- val = (u64) bp->rx_desc_mapping & 0xffffffff;
+ val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val);
for (i = 0; i < bp->rx_ring_size; i++) {
@@ -3384,6 +3403,29 @@ bnx2_init_rx_ring(struct bnx2 *bp)
}
static void
+bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
+{
+ u32 num_rings, max;
+
+ bp->rx_ring_size = size;
+ num_rings = 1;
+ while (size > MAX_RX_DESC_CNT) {
+ size -= MAX_RX_DESC_CNT;
+ num_rings++;
+ }
+ /* round to next power of 2 */
+ max = MAX_RX_RINGS;
+ while ((max & num_rings) == 0)
+ max >>= 1;
+
+ if (num_rings != max)
+ max <<= 1;
+
+ bp->rx_max_ring = max;
+ bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
+}
+
+static void
bnx2_free_tx_skbs(struct bnx2 *bp)
{
int i;
@@ -3428,7 +3470,7 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
if (bp->rx_buf_ring == NULL)
return;
- for (i = 0; i < RX_DESC_CNT; i++) {
+ for (i = 0; i < bp->rx_max_ring_idx; i++) {
struct sw_bd *rx_buf = &bp->rx_buf_ring[i];
struct sk_buff *skb = rx_buf->skb;
@@ -4792,7 +4834,7 @@ bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
{
struct bnx2 *bp = netdev_priv(dev);
- ering->rx_max_pending = MAX_RX_DESC_CNT;
+ ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
ering->rx_mini_max_pending = 0;
ering->rx_jumbo_max_pending = 0;
@@ -4809,17 +4851,28 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
{
struct bnx2 *bp = netdev_priv(dev);
- if ((ering->rx_pending > MAX_RX_DESC_CNT) ||
+ if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
(ering->tx_pending > MAX_TX_DESC_CNT) ||
(ering->tx_pending <= MAX_SKB_FRAGS)) {
return -EINVAL;
}
- bp->rx_ring_size = ering->rx_pending;
+ if (netif_running(bp->dev)) {
+ bnx2_netif_stop(bp);
+ bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
+ bnx2_free_skbs(bp);
+ bnx2_free_mem(bp);
+ }
+
+ bnx2_set_rx_ring_size(bp, ering->rx_pending);
bp->tx_ring_size = ering->tx_pending;
if (netif_running(bp->dev)) {
- bnx2_netif_stop(bp);
+ int rc;
+
+ rc = bnx2_alloc_mem(bp);
+ if (rc)
+ return rc;
bnx2_init_nic(bp);
bnx2_netif_start(bp);
}
@@ -5493,7 +5546,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->mac_addr[5] = (u8) reg;
bp->tx_ring_size = MAX_TX_DESC_CNT;
- bp->rx_ring_size = 100;
+ bnx2_set_rx_ring_size(bp, 100);
bp->rx_csum = 1;