[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>
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 0d592f7..03c47cf 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -360,6 +360,8 @@
 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 @@
 	}
 	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;
+	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;
 	}
-	kfree(bp->rx_buf_ring);
+	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 @@
 	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 @@
 	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 @@
 	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 @@
 }
 
 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 @@
 	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 @@
 {
 	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 @@
 {
 	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 @@
 	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;