}
vfree(bp->rx_buf_ring);
bp->rx_buf_ring = NULL;
+ for (i = 0; i < bp->rx_max_pg_ring; i++) {
+ if (bp->rx_pg_desc_ring[i])
+ pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
+ bp->rx_pg_desc_ring[i],
+ bp->rx_pg_desc_mapping[i]);
+ bp->rx_pg_desc_ring[i] = NULL;
+ }
+ if (bp->rx_pg_ring)
+ vfree(bp->rx_pg_ring);
+ bp->rx_pg_ring = NULL;
}
static int
}
+ if (bp->rx_pg_ring_size) {
+ bp->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE *
+ bp->rx_max_pg_ring);
+ if (bp->rx_pg_ring == NULL)
+ goto alloc_mem_err;
+
+ memset(bp->rx_pg_ring, 0, SW_RXPG_RING_SIZE *
+ bp->rx_max_pg_ring);
+ }
+
+ for (i = 0; i < bp->rx_max_pg_ring; i++) {
+ bp->rx_pg_desc_ring[i] =
+ pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
+ &bp->rx_pg_desc_mapping[i]);
+ if (bp->rx_pg_desc_ring[i] == NULL)
+ goto alloc_mem_err;
+
+ }
+
/* Combine status and statistics blocks into one allocation. */
status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
bp->status_stats_size = status_blk_size +
REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val);
}
+static inline int
+bnx2_alloc_rx_page(struct bnx2 *bp, u16 index)
+{
+ dma_addr_t mapping;
+ struct sw_pg *rx_pg = &bp->rx_pg_ring[index];
+ struct rx_bd *rxbd =
+ &bp->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
+ struct page *page = alloc_page(GFP_ATOMIC);
+
+ if (!page)
+ return -ENOMEM;
+ mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ rx_pg->page = page;
+ pci_unmap_addr_set(rx_pg, mapping, mapping);
+ rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
+ rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
+ return 0;
+}
+
+static void
+bnx2_free_rx_page(struct bnx2 *bp, u16 index)
+{
+ struct sw_pg *rx_pg = &bp->rx_pg_ring[index];
+ struct page *page = rx_pg->page;
+
+ if (!page)
+ return;
+
+ pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+
+ __free_page(page);
+ rx_pg->page = NULL;
+}
+
static inline int
bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
{
bp->rx_prod = 0;
bp->rx_cons = 0;
bp->rx_prod_bseq = 0;
+ bp->rx_pg_prod = 0;
+ bp->rx_pg_cons = 0;
bnx2_init_rxbd_rings(bp->rx_desc_ring, bp->rx_desc_mapping,
bp->rx_buf_use_size, bp->rx_max_ring);
CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
+ if (bp->rx_pg_ring_size) {
+ bnx2_init_rxbd_rings(bp->rx_pg_desc_ring,
+ bp->rx_pg_desc_mapping,
+ PAGE_SIZE, bp->rx_max_pg_ring);
+ val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
+ CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
+ CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
+ BNX2_L2CTX_RBDC_JUMBO_KEY);
+
+ val = (u64) bp->rx_pg_desc_mapping[0] >> 32;
+ CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
+
+ val = (u64) bp->rx_pg_desc_mapping[0] & 0xffffffff;
+ CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
+
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
+ }
val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
+ ring_prod = prod = bp->rx_pg_prod;
+ for (i = 0; i < bp->rx_pg_ring_size; i++) {
+ if (bnx2_alloc_rx_page(bp, ring_prod) < 0)
+ break;
+ prod = NEXT_RX_BD(prod);
+ ring_prod = RX_PG_RING_IDX(prod);
+ }
+ bp->rx_pg_prod = prod;
+
ring_prod = prod = bp->rx_prod;
for (i = 0; i < bp->rx_ring_size; i++) {
if (bnx2_alloc_rx_skb(bp, ring_prod) < 0) {
}
bp->rx_prod = prod;
+ REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_PG_BDIDX, bp->rx_pg_prod);
REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, prod);
REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
rx_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8;
bp->rx_copy_thresh = RX_COPY_THRESH;
+ bp->rx_pg_ring_size = 0;
+ bp->rx_max_pg_ring = 0;
+ bp->rx_max_pg_ring_idx = 0;
bp->rx_buf_use_size = rx_size;
/* hw alignment */
dev_kfree_skb(skb);
}
+ for (i = 0; i < bp->rx_max_pg_ring_idx; i++)
+ bnx2_free_rx_page(bp, i);
}
static void
ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
ering->rx_mini_max_pending = 0;
- ering->rx_jumbo_max_pending = 0;
+ ering->rx_jumbo_max_pending = MAX_TOTAL_RX_PG_DESC_CNT;
ering->rx_pending = bp->rx_ring_size;
ering->rx_mini_pending = 0;
- ering->rx_jumbo_pending = 0;
+ ering->rx_jumbo_pending = bp->rx_pg_ring_size;
ering->tx_max_pending = MAX_TX_DESC_CNT;
ering->tx_pending = bp->tx_ring_size;
#define BNX2_L2CTX_HOST_PG_BDIDX 0x00000044
#define BNX2_L2CTX_PG_BUF_SIZE 0x00000048
#define BNX2_L2CTX_RBDC_KEY 0x0000004c
+#define BNX2_L2CTX_RBDC_JUMBO_KEY 0x3ffe
#define BNX2_L2CTX_NX_PG_BDHADDR_HI 0x00000050
#define BNX2_L2CTX_NX_PG_BDHADDR_LO 0x00000054
#define BNX2_MQ_MEM_RD_DATA2_VALUE (0x3fffffffL<<0)
#define BNX2_MQ_MEM_RD_DATA2_VALUE_XI (0x7fffffffL<<0)
+#define BNX2_MQ_MAP_L2_3 0x00003d2c
+#define BNX2_MQ_MAP_L2_3_MQ_OFFSET (0xffL<<0)
+#define BNX2_MQ_MAP_L2_3_SZ (0x3L<<8)
+#define BNX2_MQ_MAP_L2_3_CTX_OFFSET (0x2ffL<<10)
+#define BNX2_MQ_MAP_L2_3_BIN_OFFSET (0x7L<<23)
+#define BNX2_MQ_MAP_L2_3_ARM (0x3L<<26)
+#define BNX2_MQ_MAP_L2_3_ENA (0x1L<<31)
+#define BNX2_MQ_MAP_L2_3_DEFAULT 0x82004646
/*
* tsch_reg definition
#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
#define MAX_RX_RINGS 4
+#define MAX_RX_PG_RINGS 16
#define RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct rx_bd))
#define MAX_RX_DESC_CNT (RX_DESC_CNT - 1)
#define MAX_TOTAL_RX_DESC_CNT (MAX_RX_DESC_CNT * MAX_RX_RINGS)
+#define MAX_TOTAL_RX_PG_DESC_CNT (MAX_RX_DESC_CNT * MAX_RX_PG_RINGS)
#define NEXT_TX_BD(x) (((x) & (MAX_TX_DESC_CNT - 1)) == \
(MAX_TX_DESC_CNT - 1)) ? \
(x) + 2 : (x) + 1
#define RX_RING_IDX(x) ((x) & bp->rx_max_ring_idx)
+#define RX_PG_RING_IDX(x) ((x) & bp->rx_max_pg_ring_idx)
#define RX_RING(x) (((x) & ~MAX_RX_DESC_CNT) >> (BCM_PAGE_BITS - 4))
#define RX_IDX(x) ((x) & MAX_RX_DESC_CNT)
DECLARE_PCI_UNMAP_ADDR(mapping)
};
+struct sw_pg {
+ struct page *page;
+ DECLARE_PCI_UNMAP_ADDR(mapping)
+};
+
#define SW_RXBD_RING_SIZE (sizeof(struct sw_bd) * RX_DESC_CNT)
+#define SW_RXPG_RING_SIZE (sizeof(struct sw_pg) * RX_DESC_CNT)
#define RXBD_RING_SIZE (sizeof(struct rx_bd) * RX_DESC_CNT)
#define SW_TXBD_RING_SIZE (sizeof(struct sw_bd) * TX_DESC_CNT)
#define TXBD_RING_SIZE (sizeof(struct tx_bd) * TX_DESC_CNT)
u32 rx_buf_size; /* with alignment */
u32 rx_copy_thresh;
u32 rx_max_ring_idx;
+ u32 rx_max_pg_ring_idx;
u32 rx_prod_bseq;
u16 rx_prod;
u16 rx_cons;
+ u16 rx_pg_prod;
+ u16 rx_pg_cons;
+
u32 rx_csum;
struct sw_bd *rx_buf_ring;
struct rx_bd *rx_desc_ring[MAX_RX_RINGS];
+ struct sw_pg *rx_pg_ring;
+ struct rx_bd *rx_pg_desc_ring[MAX_RX_PG_RINGS];
/* TX constants */
struct tx_bd *tx_desc_ring;
int rx_ring_size;
dma_addr_t rx_desc_mapping[MAX_RX_RINGS];
+ int rx_max_pg_ring;
+ int rx_pg_ring_size;
+ dma_addr_t rx_pg_desc_mapping[MAX_RX_PG_RINGS];
+
u16 tx_quick_cons_trip;
u16 tx_quick_cons_trip_int;
u16 rx_quick_cons_trip;