Commit 5216562a authored by Rasesh Mody's avatar Rasesh Mody Committed by David S. Miller

bna: Tx and Rx Optimizations

Change details:
 -      Have contiguous queue pages for TxQ, RxQ and CQ. Data structure and
        QPT changes related to contiguous queue pages
 -      Optimized Tx and Rx unmap structures. Tx and Rx fast path changes due to
        unmap data structure changes
 -      Re-factored Tx and Rx fastpath routines as per the new queue data structures
 -      Implemented bnad_txq_wi_prepare() to program the opcode, flags, frame_len
        and num_vectors in the work item
 -      Reduced Max TxQ and RxQ depth to 2048 while default value for Tx/Rx queue
        depth is unaltered (512)
Signed-off-by: default avatarRasesh Mody <rmody@brocade.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5e46631f
...@@ -138,6 +138,8 @@ do { \ ...@@ -138,6 +138,8 @@ do { \
#define BNA_QE_INDX_ADD(_qe_idx, _qe_num, _q_depth) \ #define BNA_QE_INDX_ADD(_qe_idx, _qe_num, _q_depth) \
((_qe_idx) = ((_qe_idx) + (_qe_num)) & ((_q_depth) - 1)) ((_qe_idx) = ((_qe_idx) + (_qe_num)) & ((_q_depth) - 1))
#define BNA_QE_INDX_INC(_idx, _q_depth) BNA_QE_INDX_ADD(_idx, 1, _q_depth)
#define BNA_Q_INDEX_CHANGE(_old_idx, _updated_idx, _q_depth) \ #define BNA_Q_INDEX_CHANGE(_old_idx, _updated_idx, _q_depth) \
(((_updated_idx) - (_old_idx)) & ((_q_depth) - 1)) (((_updated_idx) - (_old_idx)) & ((_q_depth) - 1))
......
...@@ -1908,6 +1908,9 @@ bna_rxq_qpt_setup(struct bna_rxq *rxq, ...@@ -1908,6 +1908,9 @@ bna_rxq_qpt_setup(struct bna_rxq *rxq,
struct bna_mem_descr *swqpt_mem, struct bna_mem_descr *swqpt_mem,
struct bna_mem_descr *page_mem) struct bna_mem_descr *page_mem)
{ {
u8 *kva;
u64 dma;
struct bna_dma_addr bna_dma;
int i; int i;
rxq->qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb; rxq->qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
...@@ -1917,13 +1920,21 @@ bna_rxq_qpt_setup(struct bna_rxq *rxq, ...@@ -1917,13 +1920,21 @@ bna_rxq_qpt_setup(struct bna_rxq *rxq,
rxq->qpt.page_size = page_size; rxq->qpt.page_size = page_size;
rxq->rcb->sw_qpt = (void **) swqpt_mem->kva; rxq->rcb->sw_qpt = (void **) swqpt_mem->kva;
rxq->rcb->sw_q = page_mem->kva;
kva = page_mem->kva;
BNA_GET_DMA_ADDR(&page_mem->dma, dma);
for (i = 0; i < rxq->qpt.page_count; i++) { for (i = 0; i < rxq->qpt.page_count; i++) {
rxq->rcb->sw_qpt[i] = page_mem[i].kva; rxq->rcb->sw_qpt[i] = kva;
kva += PAGE_SIZE;
BNA_SET_DMA_ADDR(dma, &bna_dma);
((struct bna_dma_addr *)rxq->qpt.kv_qpt_ptr)[i].lsb = ((struct bna_dma_addr *)rxq->qpt.kv_qpt_ptr)[i].lsb =
page_mem[i].dma.lsb; bna_dma.lsb;
((struct bna_dma_addr *)rxq->qpt.kv_qpt_ptr)[i].msb = ((struct bna_dma_addr *)rxq->qpt.kv_qpt_ptr)[i].msb =
page_mem[i].dma.msb; bna_dma.msb;
dma += PAGE_SIZE;
} }
} }
...@@ -1935,6 +1946,9 @@ bna_rxp_cqpt_setup(struct bna_rxp *rxp, ...@@ -1935,6 +1946,9 @@ bna_rxp_cqpt_setup(struct bna_rxp *rxp,
struct bna_mem_descr *swqpt_mem, struct bna_mem_descr *swqpt_mem,
struct bna_mem_descr *page_mem) struct bna_mem_descr *page_mem)
{ {
u8 *kva;
u64 dma;
struct bna_dma_addr bna_dma;
int i; int i;
rxp->cq.qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb; rxp->cq.qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
...@@ -1944,14 +1958,21 @@ bna_rxp_cqpt_setup(struct bna_rxp *rxp, ...@@ -1944,14 +1958,21 @@ bna_rxp_cqpt_setup(struct bna_rxp *rxp,
rxp->cq.qpt.page_size = page_size; rxp->cq.qpt.page_size = page_size;
rxp->cq.ccb->sw_qpt = (void **) swqpt_mem->kva; rxp->cq.ccb->sw_qpt = (void **) swqpt_mem->kva;
rxp->cq.ccb->sw_q = page_mem->kva;
kva = page_mem->kva;
BNA_GET_DMA_ADDR(&page_mem->dma, dma);
for (i = 0; i < rxp->cq.qpt.page_count; i++) { for (i = 0; i < rxp->cq.qpt.page_count; i++) {
rxp->cq.ccb->sw_qpt[i] = page_mem[i].kva; rxp->cq.ccb->sw_qpt[i] = kva;
kva += PAGE_SIZE;
BNA_SET_DMA_ADDR(dma, &bna_dma);
((struct bna_dma_addr *)rxp->cq.qpt.kv_qpt_ptr)[i].lsb = ((struct bna_dma_addr *)rxp->cq.qpt.kv_qpt_ptr)[i].lsb =
page_mem[i].dma.lsb; bna_dma.lsb;
((struct bna_dma_addr *)rxp->cq.qpt.kv_qpt_ptr)[i].msb = ((struct bna_dma_addr *)rxp->cq.qpt.kv_qpt_ptr)[i].msb =
page_mem[i].dma.msb; bna_dma.msb;
dma += PAGE_SIZE;
} }
} }
...@@ -2250,8 +2271,8 @@ bna_rx_res_req(struct bna_rx_config *q_cfg, struct bna_res_info *res_info) ...@@ -2250,8 +2271,8 @@ bna_rx_res_req(struct bna_rx_config *q_cfg, struct bna_res_info *res_info)
res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_type = BNA_RES_T_MEM; res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_type = BNA_RES_T_MEM;
mem_info = &res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info; mem_info = &res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info;
mem_info->mem_type = BNA_MEM_T_DMA; mem_info->mem_type = BNA_MEM_T_DMA;
mem_info->len = PAGE_SIZE; mem_info->len = PAGE_SIZE * cpage_count;
mem_info->num = cpage_count * q_cfg->num_paths; mem_info->num = q_cfg->num_paths;
res_info[BNA_RX_RES_MEM_T_DQPT].res_type = BNA_RES_T_MEM; res_info[BNA_RX_RES_MEM_T_DQPT].res_type = BNA_RES_T_MEM;
mem_info = &res_info[BNA_RX_RES_MEM_T_DQPT].res_u.mem_info; mem_info = &res_info[BNA_RX_RES_MEM_T_DQPT].res_u.mem_info;
...@@ -2268,8 +2289,8 @@ bna_rx_res_req(struct bna_rx_config *q_cfg, struct bna_res_info *res_info) ...@@ -2268,8 +2289,8 @@ bna_rx_res_req(struct bna_rx_config *q_cfg, struct bna_res_info *res_info)
res_info[BNA_RX_RES_MEM_T_DPAGE].res_type = BNA_RES_T_MEM; res_info[BNA_RX_RES_MEM_T_DPAGE].res_type = BNA_RES_T_MEM;
mem_info = &res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info; mem_info = &res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info;
mem_info->mem_type = BNA_MEM_T_DMA; mem_info->mem_type = BNA_MEM_T_DMA;
mem_info->len = PAGE_SIZE; mem_info->len = PAGE_SIZE * dpage_count;
mem_info->num = dpage_count * q_cfg->num_paths; mem_info->num = q_cfg->num_paths;
res_info[BNA_RX_RES_MEM_T_HQPT].res_type = BNA_RES_T_MEM; res_info[BNA_RX_RES_MEM_T_HQPT].res_type = BNA_RES_T_MEM;
mem_info = &res_info[BNA_RX_RES_MEM_T_HQPT].res_u.mem_info; mem_info = &res_info[BNA_RX_RES_MEM_T_HQPT].res_u.mem_info;
...@@ -2286,8 +2307,8 @@ bna_rx_res_req(struct bna_rx_config *q_cfg, struct bna_res_info *res_info) ...@@ -2286,8 +2307,8 @@ bna_rx_res_req(struct bna_rx_config *q_cfg, struct bna_res_info *res_info)
res_info[BNA_RX_RES_MEM_T_HPAGE].res_type = BNA_RES_T_MEM; res_info[BNA_RX_RES_MEM_T_HPAGE].res_type = BNA_RES_T_MEM;
mem_info = &res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info; mem_info = &res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info;
mem_info->mem_type = BNA_MEM_T_DMA; mem_info->mem_type = BNA_MEM_T_DMA;
mem_info->len = (hpage_count ? PAGE_SIZE : 0); mem_info->len = PAGE_SIZE * hpage_count;
mem_info->num = (hpage_count ? (hpage_count * q_cfg->num_paths) : 0); mem_info->num = (hpage_count ? q_cfg->num_paths : 0);
res_info[BNA_RX_RES_MEM_T_IBIDX].res_type = BNA_RES_T_MEM; res_info[BNA_RX_RES_MEM_T_IBIDX].res_type = BNA_RES_T_MEM;
mem_info = &res_info[BNA_RX_RES_MEM_T_IBIDX].res_u.mem_info; mem_info = &res_info[BNA_RX_RES_MEM_T_IBIDX].res_u.mem_info;
...@@ -2332,7 +2353,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad, ...@@ -2332,7 +2353,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad,
struct bna_mem_descr *dsqpt_mem; struct bna_mem_descr *dsqpt_mem;
struct bna_mem_descr *hpage_mem; struct bna_mem_descr *hpage_mem;
struct bna_mem_descr *dpage_mem; struct bna_mem_descr *dpage_mem;
int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0; int i;
int dpage_count, hpage_count, rcb_idx; int dpage_count, hpage_count, rcb_idx;
if (!bna_rx_res_check(rx_mod, rx_cfg)) if (!bna_rx_res_check(rx_mod, rx_cfg))
...@@ -2352,14 +2373,14 @@ bna_rx_create(struct bna *bna, struct bnad *bnad, ...@@ -2352,14 +2373,14 @@ bna_rx_create(struct bna *bna, struct bnad *bnad,
hpage_mem = &res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info.mdl[0]; hpage_mem = &res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info.mdl[0];
dpage_mem = &res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info.mdl[0]; dpage_mem = &res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info.mdl[0];
page_count = res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info.num / page_count = res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info.len /
rx_cfg->num_paths; PAGE_SIZE;
dpage_count = res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info.num / dpage_count = res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info.len /
rx_cfg->num_paths; PAGE_SIZE;
hpage_count = res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info.num / hpage_count = res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info.len /
rx_cfg->num_paths; PAGE_SIZE;
rx = bna_rx_get(rx_mod, rx_cfg->rx_type); rx = bna_rx_get(rx_mod, rx_cfg->rx_type);
rx->bna = bna; rx->bna = bna;
...@@ -2446,10 +2467,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad, ...@@ -2446,10 +2467,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad,
q0->rx_packets_with_error = q0->rxbuf_alloc_failed = 0; q0->rx_packets_with_error = q0->rxbuf_alloc_failed = 0;
bna_rxq_qpt_setup(q0, rxp, dpage_count, PAGE_SIZE, bna_rxq_qpt_setup(q0, rxp, dpage_count, PAGE_SIZE,
&dqpt_mem[i], &dsqpt_mem[i], &dpage_mem[dpage_idx]); &dqpt_mem[i], &dsqpt_mem[i], &dpage_mem[i]);
q0->rcb->page_idx = dpage_idx;
q0->rcb->page_count = dpage_count;
dpage_idx += dpage_count;
if (rx->rcb_setup_cbfn) if (rx->rcb_setup_cbfn)
rx->rcb_setup_cbfn(bnad, q0->rcb); rx->rcb_setup_cbfn(bnad, q0->rcb);
...@@ -2475,10 +2493,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad, ...@@ -2475,10 +2493,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad,
bna_rxq_qpt_setup(q1, rxp, hpage_count, PAGE_SIZE, bna_rxq_qpt_setup(q1, rxp, hpage_count, PAGE_SIZE,
&hqpt_mem[i], &hsqpt_mem[i], &hqpt_mem[i], &hsqpt_mem[i],
&hpage_mem[hpage_idx]); &hpage_mem[i]);
q1->rcb->page_idx = hpage_idx;
q1->rcb->page_count = hpage_count;
hpage_idx += hpage_count;
if (rx->rcb_setup_cbfn) if (rx->rcb_setup_cbfn)
rx->rcb_setup_cbfn(bnad, q1->rcb); rx->rcb_setup_cbfn(bnad, q1->rcb);
...@@ -2510,10 +2525,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad, ...@@ -2510,10 +2525,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad,
rxp->cq.ccb->id = i; rxp->cq.ccb->id = i;
bna_rxp_cqpt_setup(rxp, page_count, PAGE_SIZE, bna_rxp_cqpt_setup(rxp, page_count, PAGE_SIZE,
&cqpt_mem[i], &cswqpt_mem[i], &cpage_mem[cpage_idx]); &cqpt_mem[i], &cswqpt_mem[i], &cpage_mem[i]);
rxp->cq.ccb->page_idx = cpage_idx;
rxp->cq.ccb->page_count = page_count;
cpage_idx += page_count;
if (rx->ccb_setup_cbfn) if (rx->ccb_setup_cbfn)
rx->ccb_setup_cbfn(bnad, rxp->cq.ccb); rx->ccb_setup_cbfn(bnad, rxp->cq.ccb);
...@@ -3230,6 +3242,9 @@ bna_txq_qpt_setup(struct bna_txq *txq, int page_count, int page_size, ...@@ -3230,6 +3242,9 @@ bna_txq_qpt_setup(struct bna_txq *txq, int page_count, int page_size,
struct bna_mem_descr *swqpt_mem, struct bna_mem_descr *swqpt_mem,
struct bna_mem_descr *page_mem) struct bna_mem_descr *page_mem)
{ {
u8 *kva;
u64 dma;
struct bna_dma_addr bna_dma;
int i; int i;
txq->qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb; txq->qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
...@@ -3239,14 +3254,21 @@ bna_txq_qpt_setup(struct bna_txq *txq, int page_count, int page_size, ...@@ -3239,14 +3254,21 @@ bna_txq_qpt_setup(struct bna_txq *txq, int page_count, int page_size,
txq->qpt.page_size = page_size; txq->qpt.page_size = page_size;
txq->tcb->sw_qpt = (void **) swqpt_mem->kva; txq->tcb->sw_qpt = (void **) swqpt_mem->kva;
txq->tcb->sw_q = page_mem->kva;
kva = page_mem->kva;
BNA_GET_DMA_ADDR(&page_mem->dma, dma);
for (i = 0; i < page_count; i++) { for (i = 0; i < page_count; i++) {
txq->tcb->sw_qpt[i] = page_mem[i].kva; txq->tcb->sw_qpt[i] = kva;
kva += PAGE_SIZE;
BNA_SET_DMA_ADDR(dma, &bna_dma);
((struct bna_dma_addr *)txq->qpt.kv_qpt_ptr)[i].lsb = ((struct bna_dma_addr *)txq->qpt.kv_qpt_ptr)[i].lsb =
page_mem[i].dma.lsb; bna_dma.lsb;
((struct bna_dma_addr *)txq->qpt.kv_qpt_ptr)[i].msb = ((struct bna_dma_addr *)txq->qpt.kv_qpt_ptr)[i].msb =
page_mem[i].dma.msb; bna_dma.msb;
dma += PAGE_SIZE;
} }
} }
...@@ -3430,8 +3452,8 @@ bna_tx_res_req(int num_txq, int txq_depth, struct bna_res_info *res_info) ...@@ -3430,8 +3452,8 @@ bna_tx_res_req(int num_txq, int txq_depth, struct bna_res_info *res_info)
res_info[BNA_TX_RES_MEM_T_PAGE].res_type = BNA_RES_T_MEM; res_info[BNA_TX_RES_MEM_T_PAGE].res_type = BNA_RES_T_MEM;
mem_info = &res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info; mem_info = &res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info;
mem_info->mem_type = BNA_MEM_T_DMA; mem_info->mem_type = BNA_MEM_T_DMA;
mem_info->len = PAGE_SIZE; mem_info->len = PAGE_SIZE * page_count;
mem_info->num = num_txq * page_count; mem_info->num = num_txq;
res_info[BNA_TX_RES_MEM_T_IBIDX].res_type = BNA_RES_T_MEM; res_info[BNA_TX_RES_MEM_T_IBIDX].res_type = BNA_RES_T_MEM;
mem_info = &res_info[BNA_TX_RES_MEM_T_IBIDX].res_u.mem_info; mem_info = &res_info[BNA_TX_RES_MEM_T_IBIDX].res_u.mem_info;
...@@ -3457,14 +3479,11 @@ bna_tx_create(struct bna *bna, struct bnad *bnad, ...@@ -3457,14 +3479,11 @@ bna_tx_create(struct bna *bna, struct bnad *bnad,
struct bna_txq *txq; struct bna_txq *txq;
struct list_head *qe; struct list_head *qe;
int page_count; int page_count;
int page_size;
int page_idx;
int i; int i;
intr_info = &res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info; intr_info = &res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info;
page_count = (res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info.num) / page_count = (res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info.len) /
tx_cfg->num_txq; PAGE_SIZE;
page_size = res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info.len;
/** /**
* Get resources * Get resources
...@@ -3529,7 +3548,6 @@ bna_tx_create(struct bna *bna, struct bnad *bnad, ...@@ -3529,7 +3548,6 @@ bna_tx_create(struct bna *bna, struct bnad *bnad,
/* TxQ */ /* TxQ */
i = 0; i = 0;
page_idx = 0;
list_for_each(qe, &tx->txq_q) { list_for_each(qe, &tx->txq_q) {
txq = (struct bna_txq *)qe; txq = (struct bna_txq *)qe;
txq->tcb = (struct bna_tcb *) txq->tcb = (struct bna_tcb *)
...@@ -3569,14 +3587,11 @@ bna_tx_create(struct bna *bna, struct bnad *bnad, ...@@ -3569,14 +3587,11 @@ bna_tx_create(struct bna *bna, struct bnad *bnad,
txq->tcb->id = i; txq->tcb->id = i;
/* QPT, SWQPT, Pages */ /* QPT, SWQPT, Pages */
bna_txq_qpt_setup(txq, page_count, page_size, bna_txq_qpt_setup(txq, page_count, PAGE_SIZE,
&res_info[BNA_TX_RES_MEM_T_QPT].res_u.mem_info.mdl[i], &res_info[BNA_TX_RES_MEM_T_QPT].res_u.mem_info.mdl[i],
&res_info[BNA_TX_RES_MEM_T_SWQPT].res_u.mem_info.mdl[i], &res_info[BNA_TX_RES_MEM_T_SWQPT].res_u.mem_info.mdl[i],
&res_info[BNA_TX_RES_MEM_T_PAGE]. &res_info[BNA_TX_RES_MEM_T_PAGE].
res_u.mem_info.mdl[page_idx]); res_u.mem_info.mdl[i]);
txq->tcb->page_idx = page_idx;
txq->tcb->page_count = page_count;
page_idx += page_count;
/* Callback to bnad for setting up TCB */ /* Callback to bnad for setting up TCB */
if (tx->tcb_setup_cbfn) if (tx->tcb_setup_cbfn)
......
...@@ -430,6 +430,7 @@ struct bna_ib { ...@@ -430,6 +430,7 @@ struct bna_ib {
struct bna_tcb { struct bna_tcb {
/* Fast path */ /* Fast path */
void **sw_qpt; void **sw_qpt;
void *sw_q;
void *unmap_q; void *unmap_q;
u32 producer_index; u32 producer_index;
u32 consumer_index; u32 consumer_index;
...@@ -437,8 +438,6 @@ struct bna_tcb { ...@@ -437,8 +438,6 @@ struct bna_tcb {
u32 q_depth; u32 q_depth;
void __iomem *q_dbell; void __iomem *q_dbell;
struct bna_ib_dbell *i_dbell; struct bna_ib_dbell *i_dbell;
int page_idx;
int page_count;
/* Control path */ /* Control path */
struct bna_txq *txq; struct bna_txq *txq;
struct bnad *bnad; struct bnad *bnad;
...@@ -563,13 +562,12 @@ struct bna_tx_mod { ...@@ -563,13 +562,12 @@ struct bna_tx_mod {
struct bna_rcb { struct bna_rcb {
/* Fast path */ /* Fast path */
void **sw_qpt; void **sw_qpt;
void *sw_q;
void *unmap_q; void *unmap_q;
u32 producer_index; u32 producer_index;
u32 consumer_index; u32 consumer_index;
u32 q_depth; u32 q_depth;
void __iomem *q_dbell; void __iomem *q_dbell;
int page_idx;
int page_count;
/* Control path */ /* Control path */
struct bna_rxq *rxq; struct bna_rxq *rxq;
struct bna_ccb *ccb; struct bna_ccb *ccb;
...@@ -626,6 +624,7 @@ struct bna_pkt_rate { ...@@ -626,6 +624,7 @@ struct bna_pkt_rate {
struct bna_ccb { struct bna_ccb {
/* Fast path */ /* Fast path */
void **sw_qpt; void **sw_qpt;
void *sw_q;
u32 producer_index; u32 producer_index;
volatile u32 *hw_producer_index; volatile u32 *hw_producer_index;
u32 q_depth; u32 q_depth;
...@@ -633,8 +632,6 @@ struct bna_ccb { ...@@ -633,8 +632,6 @@ struct bna_ccb {
struct bna_rcb *rcb[2]; struct bna_rcb *rcb[2];
void *ctrl; /* For bnad */ void *ctrl; /* For bnad */
struct bna_pkt_rate pkt_rate; struct bna_pkt_rate pkt_rate;
int page_idx;
int page_count;
/* Control path */ /* Control path */
struct bna_cq *cq; struct bna_cq *cq;
......
...@@ -61,23 +61,17 @@ static const u8 bnad_bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ...@@ -61,23 +61,17 @@ static const u8 bnad_bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
/* /*
* Local MACROS * Local MACROS
*/ */
#define BNAD_TX_UNMAPQ_DEPTH (bnad->txq_depth * 2)
#define BNAD_RX_UNMAPQ_DEPTH (bnad->rxq_depth)
#define BNAD_GET_MBOX_IRQ(_bnad) \ #define BNAD_GET_MBOX_IRQ(_bnad) \
(((_bnad)->cfg_flags & BNAD_CF_MSIX) ? \ (((_bnad)->cfg_flags & BNAD_CF_MSIX) ? \
((_bnad)->msix_table[BNAD_MAILBOX_MSIX_INDEX].vector) : \ ((_bnad)->msix_table[BNAD_MAILBOX_MSIX_INDEX].vector) : \
((_bnad)->pcidev->irq)) ((_bnad)->pcidev->irq))
#define BNAD_FILL_UNMAPQ_MEM_REQ(_res_info, _num, _depth) \ #define BNAD_FILL_UNMAPQ_MEM_REQ(_res_info, _num, _size) \
do { \ do { \
(_res_info)->res_type = BNA_RES_T_MEM; \ (_res_info)->res_type = BNA_RES_T_MEM; \
(_res_info)->res_u.mem_info.mem_type = BNA_MEM_T_KVA; \ (_res_info)->res_u.mem_info.mem_type = BNA_MEM_T_KVA; \
(_res_info)->res_u.mem_info.num = (_num); \ (_res_info)->res_u.mem_info.num = (_num); \
(_res_info)->res_u.mem_info.len = \ (_res_info)->res_u.mem_info.len = (_size); \
sizeof(struct bnad_unmap_q) + \
(sizeof(struct bnad_skb_unmap) * ((_depth) - 1)); \
} while (0) } while (0)
static void static void
...@@ -103,48 +97,58 @@ bnad_remove_from_list(struct bnad *bnad) ...@@ -103,48 +97,58 @@ bnad_remove_from_list(struct bnad *bnad)
static void static void
bnad_cq_cleanup(struct bnad *bnad, struct bna_ccb *ccb) bnad_cq_cleanup(struct bnad *bnad, struct bna_ccb *ccb)
{ {
struct bna_cq_entry *cmpl, *next_cmpl; struct bna_cq_entry *cmpl;
unsigned int wi_range, wis = 0, ccb_prod = 0;
int i; int i;
BNA_CQ_QPGE_PTR_GET(ccb_prod, ccb->sw_qpt, cmpl,
wi_range);
for (i = 0; i < ccb->q_depth; i++) { for (i = 0; i < ccb->q_depth; i++) {
wis++; cmpl = &((struct bna_cq_entry *)ccb->sw_q)[i];
if (likely(--wi_range))
next_cmpl = cmpl + 1;
else {
BNA_QE_INDX_ADD(ccb_prod, wis, ccb->q_depth);
wis = 0;
BNA_CQ_QPGE_PTR_GET(ccb_prod, ccb->sw_qpt,
next_cmpl, wi_range);
}
cmpl->valid = 0; cmpl->valid = 0;
cmpl = next_cmpl;
} }
} }
/* Tx Datapath functions */
/* Caller should ensure that the entry at unmap_q[index] is valid */
static u32 static u32
bnad_pci_unmap_skb(struct device *pdev, struct bnad_skb_unmap *array, bnad_tx_buff_unmap(struct bnad *bnad,
u32 index, u32 depth, struct sk_buff *skb, u32 frag) struct bnad_tx_unmap *unmap_q,
u32 q_depth, u32 index)
{ {
int j; struct bnad_tx_unmap *unmap;
array[index].skb = NULL; struct sk_buff *skb;
int vector, nvecs;
dma_unmap_single(pdev, dma_unmap_addr(&array[index], dma_addr),
skb_headlen(skb), DMA_TO_DEVICE); unmap = &unmap_q[index];
dma_unmap_addr_set(&array[index], dma_addr, 0); nvecs = unmap->nvecs;
BNA_QE_INDX_ADD(index, 1, depth);
skb = unmap->skb;
unmap->skb = NULL;
unmap->nvecs = 0;
dma_unmap_single(&bnad->pcidev->dev,
dma_unmap_addr(&unmap->vectors[0], dma_addr),
skb_headlen(skb), DMA_TO_DEVICE);
dma_unmap_addr_set(&unmap->vectors[0], dma_addr, 0);
nvecs--;
vector = 0;
while (nvecs) {
vector++;
if (vector == BFI_TX_MAX_VECTORS_PER_WI) {
vector = 0;
BNA_QE_INDX_INC(index, q_depth);
unmap = &unmap_q[index];
}
for (j = 0; j < frag; j++) { dma_unmap_page(&bnad->pcidev->dev,
dma_unmap_page(pdev, dma_unmap_addr(&array[index], dma_addr), dma_unmap_addr(&unmap->vectors[vector], dma_addr),
skb_frag_size(&skb_shinfo(skb)->frags[j]), skb_shinfo(skb)->frags[nvecs].size, DMA_TO_DEVICE);
DMA_TO_DEVICE); dma_unmap_addr_set(&unmap->vectors[vector], dma_addr, 0);
dma_unmap_addr_set(&array[index], dma_addr, 0); nvecs--;
BNA_QE_INDX_ADD(index, 1, depth);
} }
BNA_QE_INDX_INC(index, q_depth);
return index; return index;
} }
...@@ -154,79 +158,64 @@ bnad_pci_unmap_skb(struct device *pdev, struct bnad_skb_unmap *array, ...@@ -154,79 +158,64 @@ bnad_pci_unmap_skb(struct device *pdev, struct bnad_skb_unmap *array,
* so DMA unmap & freeing is fine. * so DMA unmap & freeing is fine.
*/ */
static void static void
bnad_txq_cleanup(struct bnad *bnad, bnad_txq_cleanup(struct bnad *bnad, struct bna_tcb *tcb)
struct bna_tcb *tcb)
{ {
u32 unmap_cons; struct bnad_tx_unmap *unmap_q = tcb->unmap_q;
struct bnad_unmap_q *unmap_q = tcb->unmap_q; struct sk_buff *skb;
struct bnad_skb_unmap *unmap_array; int i;
struct sk_buff *skb = NULL;
int q;
unmap_array = unmap_q->unmap_array;
for (q = 0; q < unmap_q->q_depth; q++) { for (i = 0; i < tcb->q_depth; i++) {
skb = unmap_array[q].skb; skb = unmap_q[i].skb;
if (!skb) if (!skb)
continue; continue;
bnad_tx_buff_unmap(bnad, unmap_q, tcb->q_depth, i);
unmap_cons = q;
unmap_cons = bnad_pci_unmap_skb(&bnad->pcidev->dev, unmap_array,
unmap_cons, unmap_q->q_depth, skb,
skb_shinfo(skb)->nr_frags);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
} }
/* Data Path Handlers */
/* /*
* bnad_txcmpl_process : Frees the Tx bufs on Tx completion * bnad_txcmpl_process : Frees the Tx bufs on Tx completion
* Can be called in a) Interrupt context * Can be called in a) Interrupt context
* b) Sending context * b) Sending context
*/ */
static u32 static u32
bnad_txcmpl_process(struct bnad *bnad, bnad_txcmpl_process(struct bnad *bnad, struct bna_tcb *tcb)
struct bna_tcb *tcb)
{ {
u32 unmap_cons, sent_packets = 0, sent_bytes = 0; u32 sent_packets = 0, sent_bytes = 0;
u16 wis, updated_hw_cons; u32 wis, unmap_wis, hw_cons, cons, q_depth;
struct bnad_unmap_q *unmap_q = tcb->unmap_q; struct bnad_tx_unmap *unmap_q = tcb->unmap_q;
struct bnad_skb_unmap *unmap_array; struct bnad_tx_unmap *unmap;
struct sk_buff *skb; struct sk_buff *skb;
/* Just return if TX is stopped */ /* Just return if TX is stopped */
if (!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) if (!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))
return 0; return 0;
updated_hw_cons = *(tcb->hw_consumer_index); hw_cons = *(tcb->hw_consumer_index);
cons = tcb->consumer_index;
wis = BNA_Q_INDEX_CHANGE(tcb->consumer_index, q_depth = tcb->q_depth;
updated_hw_cons, tcb->q_depth);
wis = BNA_Q_INDEX_CHANGE(cons, hw_cons, q_depth);
BUG_ON(!(wis <= BNA_QE_IN_USE_CNT(tcb, tcb->q_depth))); BUG_ON(!(wis <= BNA_QE_IN_USE_CNT(tcb, tcb->q_depth)));
unmap_array = unmap_q->unmap_array;
unmap_cons = unmap_q->consumer_index;
while (wis) { while (wis) {
skb = unmap_array[unmap_cons].skb; unmap = &unmap_q[cons];
skb = unmap->skb;
sent_packets++; sent_packets++;
sent_bytes += skb->len; sent_bytes += skb->len;
wis -= BNA_TXQ_WI_NEEDED(1 + skb_shinfo(skb)->nr_frags);
unmap_cons = bnad_pci_unmap_skb(&bnad->pcidev->dev, unmap_array, unmap_wis = BNA_TXQ_WI_NEEDED(unmap->nvecs);
unmap_cons, unmap_q->q_depth, skb, wis -= unmap_wis;
skb_shinfo(skb)->nr_frags);
cons = bnad_tx_buff_unmap(bnad, unmap_q, q_depth, cons);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
/* Update consumer pointers. */ /* Update consumer pointers. */
tcb->consumer_index = updated_hw_cons; tcb->consumer_index = hw_cons;
unmap_q->consumer_index = unmap_cons;
tcb->txq->tx_packets += sent_packets; tcb->txq->tx_packets += sent_packets;
tcb->txq->tx_bytes += sent_bytes; tcb->txq->tx_bytes += sent_bytes;
...@@ -277,111 +266,80 @@ bnad_msix_tx(int irq, void *data) ...@@ -277,111 +266,80 @@ bnad_msix_tx(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void
bnad_rcb_cleanup(struct bnad *bnad, struct bna_rcb *rcb)
{
struct bnad_unmap_q *unmap_q = rcb->unmap_q;
rcb->producer_index = 0;
rcb->consumer_index = 0;
unmap_q->producer_index = 0;
unmap_q->consumer_index = 0;
}
static void static void
bnad_rxq_cleanup(struct bnad *bnad, struct bna_rcb *rcb) bnad_rxq_cleanup(struct bnad *bnad, struct bna_rcb *rcb)
{ {
struct bnad_unmap_q *unmap_q; struct bnad_rx_unmap *unmap_q = rcb->unmap_q;
struct bnad_skb_unmap *unmap_array;
struct sk_buff *skb; struct sk_buff *skb;
int unmap_cons; int i;
for (i = 0; i < rcb->q_depth; i++) {
struct bnad_rx_unmap *unmap = &unmap_q[i];
unmap_q = rcb->unmap_q; skb = unmap->skb;
unmap_array = unmap_q->unmap_array;
for (unmap_cons = 0; unmap_cons < unmap_q->q_depth; unmap_cons++) {
skb = unmap_array[unmap_cons].skb;
if (!skb) if (!skb)
continue; continue;
unmap_array[unmap_cons].skb = NULL;
unmap->skb = NULL;
dma_unmap_single(&bnad->pcidev->dev, dma_unmap_single(&bnad->pcidev->dev,
dma_unmap_addr(&unmap_array[unmap_cons], dma_unmap_addr(&unmap->vector, dma_addr),
dma_addr), unmap->vector.len, DMA_FROM_DEVICE);
rcb->rxq->buffer_size, dma_unmap_addr_set(&unmap->vector, dma_addr, 0);
DMA_FROM_DEVICE); unmap->vector.len = 0;
dev_kfree_skb(skb); dev_kfree_skb_any(skb);
} }
bnad_rcb_cleanup(bnad, rcb);
} }
/* Allocate and post BNAD_RXQ_REFILL_THRESHOLD_SHIFT buffers at a time */
static void static void
bnad_rxq_post(struct bnad *bnad, struct bna_rcb *rcb) bnad_rxq_post(struct bnad *bnad, struct bna_rcb *rcb)
{ {
u16 to_alloc, alloced, unmap_prod, wi_range; u32 to_alloc, alloced, prod, q_depth, buff_sz;
struct bnad_unmap_q *unmap_q = rcb->unmap_q; struct bnad_rx_unmap *unmap_q = rcb->unmap_q;
struct bnad_skb_unmap *unmap_array; struct bnad_rx_unmap *unmap;
struct bna_rxq_entry *rxent; struct bna_rxq_entry *rxent;
struct sk_buff *skb; struct sk_buff *skb;
dma_addr_t dma_addr; dma_addr_t dma_addr;
buff_sz = rcb->rxq->buffer_size;
alloced = 0; alloced = 0;
to_alloc = to_alloc = BNA_QE_FREE_CNT(rcb, rcb->q_depth);
BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth); if (!(to_alloc >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT))
return;
unmap_array = unmap_q->unmap_array;
unmap_prod = unmap_q->producer_index;
BNA_RXQ_QPGE_PTR_GET(unmap_prod, rcb->sw_qpt, rxent, wi_range); prod = rcb->producer_index;
q_depth = rcb->q_depth;
while (to_alloc--) { while (to_alloc--) {
if (!wi_range)
BNA_RXQ_QPGE_PTR_GET(unmap_prod, rcb->sw_qpt, rxent,
wi_range);
skb = netdev_alloc_skb_ip_align(bnad->netdev, skb = netdev_alloc_skb_ip_align(bnad->netdev,
rcb->rxq->buffer_size); buff_sz);
if (unlikely(!skb)) { if (unlikely(!skb)) {
BNAD_UPDATE_CTR(bnad, rxbuf_alloc_failed); BNAD_UPDATE_CTR(bnad, rxbuf_alloc_failed);
rcb->rxq->rxbuf_alloc_failed++; rcb->rxq->rxbuf_alloc_failed++;
goto finishing; goto finishing;
} }
unmap_array[unmap_prod].skb = skb;
dma_addr = dma_map_single(&bnad->pcidev->dev, skb->data, dma_addr = dma_map_single(&bnad->pcidev->dev, skb->data,
rcb->rxq->buffer_size, buff_sz, DMA_FROM_DEVICE);
DMA_FROM_DEVICE); rxent = &((struct bna_rxq_entry *)rcb->sw_q)[prod];
dma_unmap_addr_set(&unmap_array[unmap_prod], dma_addr,
dma_addr);
BNA_SET_DMA_ADDR(dma_addr, &rxent->host_addr);
BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth);
rxent++; BNA_SET_DMA_ADDR(dma_addr, &rxent->host_addr);
wi_range--; unmap = &unmap_q[prod];
unmap->skb = skb;
dma_unmap_addr_set(&unmap->vector, dma_addr, dma_addr);
unmap->vector.len = buff_sz;
BNA_QE_INDX_INC(prod, q_depth);
alloced++; alloced++;
} }
finishing: finishing:
if (likely(alloced)) { if (likely(alloced)) {
unmap_q->producer_index = unmap_prod; rcb->producer_index = prod;
rcb->producer_index = unmap_prod;
smp_mb(); smp_mb();
if (likely(test_bit(BNAD_RXQ_POST_OK, &rcb->flags))) if (likely(test_bit(BNAD_RXQ_POST_OK, &rcb->flags)))
bna_rxq_prod_indx_doorbell(rcb); bna_rxq_prod_indx_doorbell(rcb);
} }
} }
static inline void
bnad_refill_rxq(struct bnad *bnad, struct bna_rcb *rcb)
{
struct bnad_unmap_q *unmap_q = rcb->unmap_q;
if (!test_and_set_bit(BNAD_RXQ_REFILL, &rcb->flags)) {
if (BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth)
>> BNAD_RXQ_REFILL_THRESHOLD_SHIFT)
bnad_rxq_post(bnad, rcb);
smp_mb__before_clear_bit();
clear_bit(BNAD_RXQ_REFILL, &rcb->flags);
}
}
#define flags_cksum_prot_mask (BNA_CQ_EF_IPV4 | BNA_CQ_EF_L3_CKSUM_OK | \ #define flags_cksum_prot_mask (BNA_CQ_EF_IPV4 | BNA_CQ_EF_L3_CKSUM_OK | \
BNA_CQ_EF_IPV6 | \ BNA_CQ_EF_IPV6 | \
BNA_CQ_EF_TCP | BNA_CQ_EF_UDP | \ BNA_CQ_EF_TCP | BNA_CQ_EF_UDP | \
...@@ -399,21 +357,21 @@ bnad_refill_rxq(struct bnad *bnad, struct bna_rcb *rcb) ...@@ -399,21 +357,21 @@ bnad_refill_rxq(struct bnad *bnad, struct bna_rcb *rcb)
static u32 static u32
bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget) bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
{ {
struct bna_cq_entry *cmpl, *next_cmpl; struct bna_cq_entry *cq, *cmpl, *next_cmpl;
struct bna_rcb *rcb = NULL; struct bna_rcb *rcb = NULL;
unsigned int wi_range, packets = 0, wis = 0; struct bnad_rx_unmap *unmap_q, *unmap;
struct bnad_unmap_q *unmap_q; unsigned int packets = 0;
struct bnad_skb_unmap *unmap_array, *curr_ua;
struct sk_buff *skb; struct sk_buff *skb;
u32 flags, unmap_cons, masked_flags; u32 flags, masked_flags;
struct bna_pkt_rate *pkt_rt = &ccb->pkt_rate; struct bna_pkt_rate *pkt_rt = &ccb->pkt_rate;
struct bnad_rx_ctrl *rx_ctrl = (struct bnad_rx_ctrl *)(ccb->ctrl); struct bnad_rx_ctrl *rx_ctrl = (struct bnad_rx_ctrl *)(ccb->ctrl);
prefetch(bnad->netdev); prefetch(bnad->netdev);
BNA_CQ_QPGE_PTR_GET(ccb->producer_index, ccb->sw_qpt, cmpl,
wi_range); cq = ccb->sw_q;
BUG_ON(!(wi_range <= ccb->q_depth)); cmpl = &cq[ccb->producer_index];
while (cmpl->valid && packets < budget) {
while (cmpl->valid && (packets < budget)) {
packets++; packets++;
BNA_UPDATE_PKT_CNT(pkt_rt, ntohs(cmpl->length)); BNA_UPDATE_PKT_CNT(pkt_rt, ntohs(cmpl->length));
...@@ -423,33 +381,19 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget) ...@@ -423,33 +381,19 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
rcb = ccb->rcb[0]; rcb = ccb->rcb[0];
unmap_q = rcb->unmap_q; unmap_q = rcb->unmap_q;
unmap_array = unmap_q->unmap_array; unmap = &unmap_q[rcb->consumer_index];
unmap_cons = unmap_q->consumer_index;
curr_ua = &unmap_array[unmap_cons]; skb = unmap->skb;
skb = curr_ua->skb;
BUG_ON(!(skb)); BUG_ON(!(skb));
curr_ua->skb = NULL; unmap->skb = NULL;
dma_unmap_single(&bnad->pcidev->dev, dma_unmap_single(&bnad->pcidev->dev,
dma_unmap_addr(curr_ua, dma_addr), dma_unmap_addr(&unmap->vector, dma_addr),
rcb->rxq->buffer_size, unmap->vector.len, DMA_FROM_DEVICE);
DMA_FROM_DEVICE); unmap->vector.len = 0;
BNA_QE_INDX_ADD(unmap_q->consumer_index, 1, unmap_q->q_depth); BNA_QE_INDX_INC(rcb->consumer_index, rcb->q_depth);
BNA_QE_INDX_INC(ccb->producer_index, ccb->q_depth);
/* Should be more efficient ? Performance ? */ next_cmpl = &cq[ccb->producer_index];
BNA_QE_INDX_ADD(rcb->consumer_index, 1, rcb->q_depth);
wis++;
if (likely(--wi_range))
next_cmpl = cmpl + 1;
else {
BNA_QE_INDX_ADD(ccb->producer_index, wis, ccb->q_depth);
wis = 0;
BNA_CQ_QPGE_PTR_GET(ccb->producer_index, ccb->sw_qpt,
next_cmpl, wi_range);
BUG_ON(!(wi_range <= ccb->q_depth));
}
prefetch(next_cmpl); prefetch(next_cmpl);
flags = ntohl(cmpl->flags); flags = ntohl(cmpl->flags);
...@@ -493,16 +437,12 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget) ...@@ -493,16 +437,12 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
cmpl = next_cmpl; cmpl = next_cmpl;
} }
BNA_QE_INDX_ADD(ccb->producer_index, wis, ccb->q_depth);
if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags))) if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)))
bna_ib_ack_disable_irq(ccb->i_dbell, packets); bna_ib_ack_disable_irq(ccb->i_dbell, packets);
bnad_refill_rxq(bnad, ccb->rcb[0]); bnad_rxq_post(bnad, ccb->rcb[0]);
if (ccb->rcb[1]) if (ccb->rcb[1])
bnad_refill_rxq(bnad, ccb->rcb[1]); bnad_rxq_post(bnad, ccb->rcb[1]);
clear_bit(BNAD_FP_IN_RX_PATH, &rx_ctrl->flags);
return packets; return packets;
} }
...@@ -777,12 +717,9 @@ bnad_cb_tcb_setup(struct bnad *bnad, struct bna_tcb *tcb) ...@@ -777,12 +717,9 @@ bnad_cb_tcb_setup(struct bnad *bnad, struct bna_tcb *tcb)
{ {
struct bnad_tx_info *tx_info = struct bnad_tx_info *tx_info =
(struct bnad_tx_info *)tcb->txq->tx->priv; (struct bnad_tx_info *)tcb->txq->tx->priv;
struct bnad_unmap_q *unmap_q = tcb->unmap_q;
tcb->priv = tcb;
tx_info->tcb[tcb->id] = tcb; tx_info->tcb[tcb->id] = tcb;
unmap_q->producer_index = 0;
unmap_q->consumer_index = 0;
unmap_q->q_depth = BNAD_TX_UNMAPQ_DEPTH;
} }
static void static void
...@@ -795,16 +732,6 @@ bnad_cb_tcb_destroy(struct bnad *bnad, struct bna_tcb *tcb) ...@@ -795,16 +732,6 @@ bnad_cb_tcb_destroy(struct bnad *bnad, struct bna_tcb *tcb)
tcb->priv = NULL; tcb->priv = NULL;
} }
static void
bnad_cb_rcb_setup(struct bnad *bnad, struct bna_rcb *rcb)
{
struct bnad_unmap_q *unmap_q = rcb->unmap_q;
unmap_q->producer_index = 0;
unmap_q->consumer_index = 0;
unmap_q->q_depth = BNAD_RX_UNMAPQ_DEPTH;
}
static void static void
bnad_cb_ccb_setup(struct bnad *bnad, struct bna_ccb *ccb) bnad_cb_ccb_setup(struct bnad *bnad, struct bna_ccb *ccb)
{ {
...@@ -891,10 +818,9 @@ bnad_tx_cleanup(struct delayed_work *work) ...@@ -891,10 +818,9 @@ bnad_tx_cleanup(struct delayed_work *work)
struct bnad_tx_info *tx_info = struct bnad_tx_info *tx_info =
container_of(work, struct bnad_tx_info, tx_cleanup_work); container_of(work, struct bnad_tx_info, tx_cleanup_work);
struct bnad *bnad = NULL; struct bnad *bnad = NULL;
struct bnad_unmap_q *unmap_q;
struct bna_tcb *tcb; struct bna_tcb *tcb;
unsigned long flags; unsigned long flags;
uint32_t i, pending = 0; u32 i, pending = 0;
for (i = 0; i < BNAD_MAX_TXQ_PER_TX; i++) { for (i = 0; i < BNAD_MAX_TXQ_PER_TX; i++) {
tcb = tx_info->tcb[i]; tcb = tx_info->tcb[i];
...@@ -910,10 +836,6 @@ bnad_tx_cleanup(struct delayed_work *work) ...@@ -910,10 +836,6 @@ bnad_tx_cleanup(struct delayed_work *work)
bnad_txq_cleanup(bnad, tcb); bnad_txq_cleanup(bnad, tcb);
unmap_q = tcb->unmap_q;
unmap_q->producer_index = 0;
unmap_q->consumer_index = 0;
smp_mb__before_clear_bit(); smp_mb__before_clear_bit();
clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags); clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
} }
...@@ -929,7 +851,6 @@ bnad_tx_cleanup(struct delayed_work *work) ...@@ -929,7 +851,6 @@ bnad_tx_cleanup(struct delayed_work *work)
spin_unlock_irqrestore(&bnad->bna_lock, flags); spin_unlock_irqrestore(&bnad->bna_lock, flags);
} }
static void static void
bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tx *tx) bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tx *tx)
{ {
...@@ -978,7 +899,7 @@ bnad_rx_cleanup(void *work) ...@@ -978,7 +899,7 @@ bnad_rx_cleanup(void *work)
struct bnad_rx_ctrl *rx_ctrl; struct bnad_rx_ctrl *rx_ctrl;
struct bnad *bnad = NULL; struct bnad *bnad = NULL;
unsigned long flags; unsigned long flags;
uint32_t i; u32 i;
for (i = 0; i < BNAD_MAX_RXP_PER_RX; i++) { for (i = 0; i < BNAD_MAX_RXP_PER_RX; i++) {
rx_ctrl = &rx_info->rx_ctrl[i]; rx_ctrl = &rx_info->rx_ctrl[i];
...@@ -1035,7 +956,6 @@ bnad_cb_rx_post(struct bnad *bnad, struct bna_rx *rx) ...@@ -1035,7 +956,6 @@ bnad_cb_rx_post(struct bnad *bnad, struct bna_rx *rx)
struct bna_ccb *ccb; struct bna_ccb *ccb;
struct bna_rcb *rcb; struct bna_rcb *rcb;
struct bnad_rx_ctrl *rx_ctrl; struct bnad_rx_ctrl *rx_ctrl;
struct bnad_unmap_q *unmap_q;
int i; int i;
int j; int j;
...@@ -1054,17 +974,7 @@ bnad_cb_rx_post(struct bnad *bnad, struct bna_rx *rx) ...@@ -1054,17 +974,7 @@ bnad_cb_rx_post(struct bnad *bnad, struct bna_rx *rx)
set_bit(BNAD_RXQ_STARTED, &rcb->flags); set_bit(BNAD_RXQ_STARTED, &rcb->flags);
set_bit(BNAD_RXQ_POST_OK, &rcb->flags); set_bit(BNAD_RXQ_POST_OK, &rcb->flags);
unmap_q = rcb->unmap_q; bnad_rxq_post(bnad, rcb);
/* Now allocate & post buffers for this RCB */
/* !!Allocation in callback context */
if (!test_and_set_bit(BNAD_RXQ_REFILL, &rcb->flags)) {
if (BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth)
>> BNAD_RXQ_REFILL_THRESHOLD_SHIFT)
bnad_rxq_post(bnad, rcb);
smp_mb__before_clear_bit();
clear_bit(BNAD_RXQ_REFILL, &rcb->flags);
}
} }
} }
} }
...@@ -1788,10 +1698,9 @@ bnad_setup_tx(struct bnad *bnad, u32 tx_id) ...@@ -1788,10 +1698,9 @@ bnad_setup_tx(struct bnad *bnad, u32 tx_id)
spin_unlock_irqrestore(&bnad->bna_lock, flags); spin_unlock_irqrestore(&bnad->bna_lock, flags);
/* Fill Unmap Q memory requirements */ /* Fill Unmap Q memory requirements */
BNAD_FILL_UNMAPQ_MEM_REQ( BNAD_FILL_UNMAPQ_MEM_REQ(&res_info[BNA_TX_RES_MEM_T_UNMAPQ],
&res_info[BNA_TX_RES_MEM_T_UNMAPQ], bnad->num_txq_per_tx, (sizeof(struct bnad_tx_unmap) *
bnad->num_txq_per_tx, bnad->txq_depth));
BNAD_TX_UNMAPQ_DEPTH);
/* Allocate resources */ /* Allocate resources */
err = bnad_tx_res_alloc(bnad, res_info, tx_id); err = bnad_tx_res_alloc(bnad, res_info, tx_id);
...@@ -1929,7 +1838,7 @@ bnad_setup_rx(struct bnad *bnad, u32 rx_id) ...@@ -1929,7 +1838,7 @@ bnad_setup_rx(struct bnad *bnad, u32 rx_id)
&res_info[BNA_RX_RES_T_INTR].res_u.intr_info; &res_info[BNA_RX_RES_T_INTR].res_u.intr_info;
struct bna_rx_config *rx_config = &bnad->rx_config[rx_id]; struct bna_rx_config *rx_config = &bnad->rx_config[rx_id];
static const struct bna_rx_event_cbfn rx_cbfn = { static const struct bna_rx_event_cbfn rx_cbfn = {
.rcb_setup_cbfn = bnad_cb_rcb_setup, .rcb_setup_cbfn = NULL,
.rcb_destroy_cbfn = NULL, .rcb_destroy_cbfn = NULL,
.ccb_setup_cbfn = bnad_cb_ccb_setup, .ccb_setup_cbfn = bnad_cb_ccb_setup,
.ccb_destroy_cbfn = bnad_cb_ccb_destroy, .ccb_destroy_cbfn = bnad_cb_ccb_destroy,
...@@ -1951,11 +1860,10 @@ bnad_setup_rx(struct bnad *bnad, u32 rx_id) ...@@ -1951,11 +1860,10 @@ bnad_setup_rx(struct bnad *bnad, u32 rx_id)
spin_unlock_irqrestore(&bnad->bna_lock, flags); spin_unlock_irqrestore(&bnad->bna_lock, flags);
/* Fill Unmap Q memory requirements */ /* Fill Unmap Q memory requirements */
BNAD_FILL_UNMAPQ_MEM_REQ( BNAD_FILL_UNMAPQ_MEM_REQ(&res_info[BNA_RX_RES_MEM_T_UNMAPQ],
&res_info[BNA_RX_RES_MEM_T_UNMAPQ], rx_config->num_paths + ((rx_config->rxp_type == BNA_RXP_SINGLE)
rx_config->num_paths + ? 0 : rx_config->num_paths), (bnad->rxq_depth *
((rx_config->rxp_type == BNA_RXP_SINGLE) ? 0 : sizeof(struct bnad_rx_unmap)));
rx_config->num_paths), BNAD_RX_UNMAPQ_DEPTH);
/* Allocate resource */ /* Allocate resource */
err = bnad_rx_res_alloc(bnad, res_info, rx_id); err = bnad_rx_res_alloc(bnad, res_info, rx_id);
...@@ -2536,125 +2444,34 @@ bnad_stop(struct net_device *netdev) ...@@ -2536,125 +2444,34 @@ bnad_stop(struct net_device *netdev)
} }
/* TX */ /* TX */
/* /* Returns 0 for success */
* bnad_start_xmit : Netdev entry point for Transmit static int
* Called under lock held by net_device bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
*/ struct sk_buff *skb, struct bna_txq_entry *txqent)
static netdev_tx_t
bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{ {
struct bnad *bnad = netdev_priv(netdev); u16 flags = 0;
u32 txq_id = 0; u32 gso_size;
struct bna_tcb *tcb = bnad->tx_info[0].tcb[txq_id]; u16 vlan_tag = 0;
u16 txq_prod, vlan_tag = 0;
u32 unmap_prod, wis, wis_used, wi_range;
u32 vectors, vect_id, i, acked;
int err;
unsigned int len;
u32 gso_size;
struct bnad_unmap_q *unmap_q = tcb->unmap_q;
dma_addr_t dma_addr;
struct bna_txq_entry *txqent;
u16 flags;
if (unlikely(skb->len <= ETH_HLEN)) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_too_short);
return NETDEV_TX_OK;
}
if (unlikely(skb_headlen(skb) > BFI_TX_MAX_DATA_PER_VECTOR)) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_headlen_too_long);
return NETDEV_TX_OK;
}
if (unlikely(skb_headlen(skb) == 0)) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_headlen_zero);
return NETDEV_TX_OK;
}
/*
* Takes care of the Tx that is scheduled between clearing the flag
* and the netif_tx_stop_all_queues() call.
*/
if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_stopping);
return NETDEV_TX_OK;
}
vectors = 1 + skb_shinfo(skb)->nr_frags;
if (unlikely(vectors > BFI_TX_MAX_VECTORS_PER_PKT)) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_max_vectors);
return NETDEV_TX_OK;
}
wis = BNA_TXQ_WI_NEEDED(vectors); /* 4 vectors per work item */
acked = 0;
if (unlikely(wis > BNA_QE_FREE_CNT(tcb, tcb->q_depth) ||
vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) {
if ((u16) (*tcb->hw_consumer_index) !=
tcb->consumer_index &&
!test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) {
acked = bnad_txcmpl_process(bnad, tcb);
if (likely(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)))
bna_ib_ack(tcb->i_dbell, acked);
smp_mb__before_clear_bit();
clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
} else {
netif_stop_queue(netdev);
BNAD_UPDATE_CTR(bnad, netif_queue_stop);
}
smp_mb();
/*
* Check again to deal with race condition between
* netif_stop_queue here, and netif_wake_queue in
* interrupt handler which is not inside netif tx lock.
*/
if (likely
(wis > BNA_QE_FREE_CNT(tcb, tcb->q_depth) ||
vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) {
BNAD_UPDATE_CTR(bnad, netif_queue_stop);
return NETDEV_TX_BUSY;
} else {
netif_wake_queue(netdev);
BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
}
}
unmap_prod = unmap_q->producer_index;
flags = 0;
txq_prod = tcb->producer_index;
BNA_TXQ_QPGE_PTR_GET(txq_prod, tcb->sw_qpt, txqent, wi_range);
txqent->hdr.wi.reserved = 0;
txqent->hdr.wi.num_vectors = vectors;
if (vlan_tx_tag_present(skb)) { if (vlan_tx_tag_present(skb)) {
vlan_tag = (u16) vlan_tx_tag_get(skb); vlan_tag = (u16)vlan_tx_tag_get(skb);
flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN); flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN);
} }
if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) { if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) {
vlan_tag = vlan_tag = ((tcb->priority & 0x7) << VLAN_PRIO_SHIFT)
(tcb->priority & 0x7) << 13 | (vlan_tag & 0x1fff); | (vlan_tag & 0x1fff);
flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN); flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN);
} }
txqent->hdr.wi.vlan_tag = htons(vlan_tag); txqent->hdr.wi.vlan_tag = htons(vlan_tag);
if (skb_is_gso(skb)) { if (skb_is_gso(skb)) {
gso_size = skb_shinfo(skb)->gso_size; gso_size = skb_shinfo(skb)->gso_size;
if (unlikely(gso_size > bnad->netdev->mtu)) {
if (unlikely(gso_size > netdev->mtu)) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_mss_too_long); BNAD_UPDATE_CTR(bnad, tx_skb_mss_too_long);
return NETDEV_TX_OK; return -EINVAL;
} }
if (unlikely((gso_size + skb_transport_offset(skb) + if (unlikely((gso_size + skb_transport_offset(skb) +
tcp_hdrlen(skb)) >= skb->len)) { tcp_hdrlen(skb)) >= skb->len)) {
txqent->hdr.wi.opcode = txqent->hdr.wi.opcode =
__constant_htons(BNA_TXQ_WI_SEND); __constant_htons(BNA_TXQ_WI_SEND);
txqent->hdr.wi.lso_mss = 0; txqent->hdr.wi.lso_mss = 0;
...@@ -2665,25 +2482,22 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -2665,25 +2482,22 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
txqent->hdr.wi.lso_mss = htons(gso_size); txqent->hdr.wi.lso_mss = htons(gso_size);
} }
err = bnad_tso_prepare(bnad, skb); if (bnad_tso_prepare(bnad, skb)) {
if (unlikely(err)) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_tso_prepare); BNAD_UPDATE_CTR(bnad, tx_skb_tso_prepare);
return NETDEV_TX_OK; return -EINVAL;
} }
flags |= (BNA_TXQ_WI_CF_IP_CKSUM | BNA_TXQ_WI_CF_TCP_CKSUM); flags |= (BNA_TXQ_WI_CF_IP_CKSUM | BNA_TXQ_WI_CF_TCP_CKSUM);
txqent->hdr.wi.l4_hdr_size_n_offset = txqent->hdr.wi.l4_hdr_size_n_offset =
htons(BNA_TXQ_WI_L4_HDR_N_OFFSET htons(BNA_TXQ_WI_L4_HDR_N_OFFSET(
(tcp_hdrlen(skb) >> 2, tcp_hdrlen(skb) >> 2, skb_transport_offset(skb)));
skb_transport_offset(skb))); } else {
} else {
txqent->hdr.wi.opcode = __constant_htons(BNA_TXQ_WI_SEND); txqent->hdr.wi.opcode = __constant_htons(BNA_TXQ_WI_SEND);
txqent->hdr.wi.lso_mss = 0; txqent->hdr.wi.lso_mss = 0;
if (unlikely(skb->len > (netdev->mtu + ETH_HLEN))) { if (unlikely(skb->len > (bnad->netdev->mtu + ETH_HLEN))) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_non_tso_too_long); BNAD_UPDATE_CTR(bnad, tx_skb_non_tso_too_long);
return NETDEV_TX_OK; return -EINVAL;
} }
if (skb->ip_summed == CHECKSUM_PARTIAL) { if (skb->ip_summed == CHECKSUM_PARTIAL) {
...@@ -2691,11 +2505,13 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -2691,11 +2505,13 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
if (skb->protocol == __constant_htons(ETH_P_IP)) if (skb->protocol == __constant_htons(ETH_P_IP))
proto = ip_hdr(skb)->protocol; proto = ip_hdr(skb)->protocol;
#ifdef NETIF_F_IPV6_CSUM
else if (skb->protocol == else if (skb->protocol ==
__constant_htons(ETH_P_IPV6)) { __constant_htons(ETH_P_IPV6)) {
/* nexthdr may not be TCP immediately. */ /* nexthdr may not be TCP immediately. */
proto = ipv6_hdr(skb)->nexthdr; proto = ipv6_hdr(skb)->nexthdr;
} }
#endif
if (proto == IPPROTO_TCP) { if (proto == IPPROTO_TCP) {
flags |= BNA_TXQ_WI_CF_TCP_CKSUM; flags |= BNA_TXQ_WI_CF_TCP_CKSUM;
txqent->hdr.wi.l4_hdr_size_n_offset = txqent->hdr.wi.l4_hdr_size_n_offset =
...@@ -2705,12 +2521,11 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -2705,12 +2521,11 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
BNAD_UPDATE_CTR(bnad, tcpcsum_offload); BNAD_UPDATE_CTR(bnad, tcpcsum_offload);
if (unlikely(skb_headlen(skb) < if (unlikely(skb_headlen(skb) <
skb_transport_offset(skb) + tcp_hdrlen(skb))) { skb_transport_offset(skb) +
dev_kfree_skb(skb); tcp_hdrlen(skb))) {
BNAD_UPDATE_CTR(bnad, tx_skb_tcp_hdr); BNAD_UPDATE_CTR(bnad, tx_skb_tcp_hdr);
return NETDEV_TX_OK; return -EINVAL;
} }
} else if (proto == IPPROTO_UDP) { } else if (proto == IPPROTO_UDP) {
flags |= BNA_TXQ_WI_CF_UDP_CKSUM; flags |= BNA_TXQ_WI_CF_UDP_CKSUM;
txqent->hdr.wi.l4_hdr_size_n_offset = txqent->hdr.wi.l4_hdr_size_n_offset =
...@@ -2719,51 +2534,149 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -2719,51 +2534,149 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
BNAD_UPDATE_CTR(bnad, udpcsum_offload); BNAD_UPDATE_CTR(bnad, udpcsum_offload);
if (unlikely(skb_headlen(skb) < if (unlikely(skb_headlen(skb) <
skb_transport_offset(skb) + skb_transport_offset(skb) +
sizeof(struct udphdr))) { sizeof(struct udphdr))) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_udp_hdr); BNAD_UPDATE_CTR(bnad, tx_skb_udp_hdr);
return NETDEV_TX_OK; return -EINVAL;
} }
} else { } else {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_csum_err); BNAD_UPDATE_CTR(bnad, tx_skb_csum_err);
return NETDEV_TX_OK; return -EINVAL;
} }
} else { } else
txqent->hdr.wi.l4_hdr_size_n_offset = 0; txqent->hdr.wi.l4_hdr_size_n_offset = 0;
}
} }
txqent->hdr.wi.flags = htons(flags); txqent->hdr.wi.flags = htons(flags);
txqent->hdr.wi.frame_length = htonl(skb->len); txqent->hdr.wi.frame_length = htonl(skb->len);
unmap_q->unmap_array[unmap_prod].skb = skb; return 0;
}
/*
* bnad_start_xmit : Netdev entry point for Transmit
* Called under lock held by net_device
*/
static netdev_tx_t
bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct bnad *bnad = netdev_priv(netdev);
u32 txq_id = 0;
struct bna_tcb *tcb = NULL;
struct bnad_tx_unmap *unmap_q, *unmap, *head_unmap;
u32 prod, q_depth, vect_id;
u32 wis, vectors, len;
int i;
dma_addr_t dma_addr;
struct bna_txq_entry *txqent;
len = skb_headlen(skb); len = skb_headlen(skb);
txqent->vector[0].length = htons(len);
dma_addr = dma_map_single(&bnad->pcidev->dev, skb->data,
skb_headlen(skb), DMA_TO_DEVICE);
dma_unmap_addr_set(&unmap_q->unmap_array[unmap_prod], dma_addr,
dma_addr);
BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[0].host_addr); /* Sanity checks for the skb */
BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth);
if (unlikely(skb->len <= ETH_HLEN)) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_too_short);
return NETDEV_TX_OK;
}
if (unlikely(len > BFI_TX_MAX_DATA_PER_VECTOR)) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_headlen_zero);
return NETDEV_TX_OK;
}
if (unlikely(len == 0)) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_headlen_zero);
return NETDEV_TX_OK;
}
tcb = bnad->tx_info[0].tcb[txq_id];
q_depth = tcb->q_depth;
prod = tcb->producer_index;
vect_id = 0; unmap_q = tcb->unmap_q;
wis_used = 1;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { /*
* Takes care of the Tx that is scheduled between clearing the flag
* and the netif_tx_stop_all_queues() call.
*/
if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_stopping);
return NETDEV_TX_OK;
}
vectors = 1 + skb_shinfo(skb)->nr_frags;
wis = BNA_TXQ_WI_NEEDED(vectors); /* 4 vectors per work item */
if (unlikely(vectors > BFI_TX_MAX_VECTORS_PER_PKT)) {
dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_max_vectors);
return NETDEV_TX_OK;
}
/* Check for available TxQ resources */
if (unlikely(wis > BNA_QE_FREE_CNT(tcb, q_depth))) {
if ((*tcb->hw_consumer_index != tcb->consumer_index) &&
!test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) {
u32 sent;
sent = bnad_txcmpl_process(bnad, tcb);
if (likely(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)))
bna_ib_ack(tcb->i_dbell, sent);
smp_mb__before_clear_bit();
clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
} else {
netif_stop_queue(netdev);
BNAD_UPDATE_CTR(bnad, netif_queue_stop);
}
smp_mb();
/*
* Check again to deal with race condition between
* netif_stop_queue here, and netif_wake_queue in
* interrupt handler which is not inside netif tx lock.
*/
if (likely(wis > BNA_QE_FREE_CNT(tcb, q_depth))) {
BNAD_UPDATE_CTR(bnad, netif_queue_stop);
return NETDEV_TX_BUSY;
} else {
netif_wake_queue(netdev);
BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
}
}
txqent = &((struct bna_txq_entry *)tcb->sw_q)[prod];
head_unmap = &unmap_q[prod];
/* Program the opcode, flags, frame_len, num_vectors in WI */
if (bnad_txq_wi_prepare(bnad, tcb, skb, txqent)) {
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
txqent->hdr.wi.reserved = 0;
txqent->hdr.wi.num_vectors = vectors;
head_unmap->skb = skb;
head_unmap->nvecs = 0;
/* Program the vectors */
unmap = head_unmap;
dma_addr = dma_map_single(&bnad->pcidev->dev, skb->data,
len, DMA_TO_DEVICE);
BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[0].host_addr);
txqent->vector[0].length = htons(len);
dma_unmap_addr_set(&unmap->vectors[0], dma_addr, dma_addr);
head_unmap->nvecs++;
for (i = 0, vect_id = 0; i < vectors - 1; i++) {
const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
u16 size = skb_frag_size(frag); u16 size = skb_frag_size(frag);
if (unlikely(size == 0)) { if (unlikely(size == 0)) {
unmap_prod = unmap_q->producer_index; /* Undo the changes starting at tcb->producer_index */
bnad_tx_buff_unmap(bnad, unmap_q, q_depth,
unmap_prod = bnad_pci_unmap_skb(&bnad->pcidev->dev, tcb->producer_index);
unmap_q->unmap_array,
unmap_prod, unmap_q->q_depth, skb,
i);
dev_kfree_skb(skb); dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_frag_zero); BNAD_UPDATE_CTR(bnad, tx_skb_frag_zero);
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -2771,47 +2684,35 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -2771,47 +2684,35 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
len += size; len += size;
if (++vect_id == BFI_TX_MAX_VECTORS_PER_WI) { vect_id++;
if (vect_id == BFI_TX_MAX_VECTORS_PER_WI) {
vect_id = 0; vect_id = 0;
if (--wi_range) BNA_QE_INDX_INC(prod, q_depth);
txqent++; txqent = &((struct bna_txq_entry *)tcb->sw_q)[prod];
else {
BNA_QE_INDX_ADD(txq_prod, wis_used,
tcb->q_depth);
wis_used = 0;
BNA_TXQ_QPGE_PTR_GET(txq_prod, tcb->sw_qpt,
txqent, wi_range);
}
wis_used++;
txqent->hdr.wi_ext.opcode = txqent->hdr.wi_ext.opcode =
__constant_htons(BNA_TXQ_WI_EXTENSION); __constant_htons(BNA_TXQ_WI_EXTENSION);
unmap = &unmap_q[prod];
} }
BUG_ON(!(size <= BFI_TX_MAX_DATA_PER_VECTOR));
txqent->vector[vect_id].length = htons(size);
dma_addr = skb_frag_dma_map(&bnad->pcidev->dev, frag, dma_addr = skb_frag_dma_map(&bnad->pcidev->dev, frag,
0, size, DMA_TO_DEVICE); 0, size, DMA_TO_DEVICE);
dma_unmap_addr_set(&unmap_q->unmap_array[unmap_prod], dma_addr,
dma_addr);
BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[vect_id].host_addr); BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[vect_id].host_addr);
BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth); txqent->vector[vect_id].length = htons(size);
dma_unmap_addr_set(&unmap->vectors[vect_id], dma_addr,
dma_addr);
head_unmap->nvecs++;
} }
if (unlikely(len != skb->len)) { if (unlikely(len != skb->len)) {
unmap_prod = unmap_q->producer_index; /* Undo the changes starting at tcb->producer_index */
bnad_tx_buff_unmap(bnad, unmap_q, q_depth, tcb->producer_index);
unmap_prod = bnad_pci_unmap_skb(&bnad->pcidev->dev,
unmap_q->unmap_array, unmap_prod,
unmap_q->q_depth, skb,
skb_shinfo(skb)->nr_frags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_len_mismatch); BNAD_UPDATE_CTR(bnad, tx_skb_len_mismatch);
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
unmap_q->producer_index = unmap_prod; BNA_QE_INDX_INC(prod, q_depth);
BNA_QE_INDX_ADD(txq_prod, wis_used, tcb->q_depth); tcb->producer_index = prod;
tcb->producer_index = txq_prod;
smp_mb(); smp_mb();
...@@ -3333,7 +3234,6 @@ bnad_pci_probe(struct pci_dev *pdev, ...@@ -3333,7 +3234,6 @@ bnad_pci_probe(struct pci_dev *pdev,
if (err) if (err)
goto res_free; goto res_free;
/* Set up timers */ /* Set up timers */
setup_timer(&bnad->bna.ioceth.ioc.ioc_timer, bnad_ioc_timeout, setup_timer(&bnad->bna.ioceth.ioc.ioc_timer, bnad_ioc_timeout,
((unsigned long)bnad)); ((unsigned long)bnad));
......
...@@ -83,12 +83,9 @@ struct bnad_rx_ctrl { ...@@ -83,12 +83,9 @@ struct bnad_rx_ctrl {
#define BNAD_IOCETH_TIMEOUT 10000 #define BNAD_IOCETH_TIMEOUT 10000
#define BNAD_MAX_Q_DEPTH 0x10000 #define BNAD_MIN_Q_DEPTH 512
#define BNAD_MIN_Q_DEPTH 0x200 #define BNAD_MAX_RXQ_DEPTH 2048
#define BNAD_MAX_TXQ_DEPTH 2048
#define BNAD_MAX_RXQ_DEPTH (BNAD_MAX_Q_DEPTH / bnad_rxqs_per_cq)
/* keeping MAX TX and RX Q depth equal */
#define BNAD_MAX_TXQ_DEPTH BNAD_MAX_RXQ_DEPTH
#define BNAD_JUMBO_MTU 9000 #define BNAD_JUMBO_MTU 9000
...@@ -101,9 +98,8 @@ struct bnad_rx_ctrl { ...@@ -101,9 +98,8 @@ struct bnad_rx_ctrl {
#define BNAD_TXQ_TX_STARTED 1 #define BNAD_TXQ_TX_STARTED 1
/* Bit positions for rcb->flags */ /* Bit positions for rcb->flags */
#define BNAD_RXQ_REFILL 0 #define BNAD_RXQ_STARTED 0
#define BNAD_RXQ_STARTED 1 #define BNAD_RXQ_POST_OK 1
#define BNAD_RXQ_POST_OK 2
/* Resource limits */ /* Resource limits */
#define BNAD_NUM_TXQ (bnad->num_tx * bnad->num_txq_per_tx) #define BNAD_NUM_TXQ (bnad->num_tx * bnad->num_txq_per_tx)
...@@ -221,18 +217,24 @@ struct bnad_rx_info { ...@@ -221,18 +217,24 @@ struct bnad_rx_info {
struct work_struct rx_cleanup_work; struct work_struct rx_cleanup_work;
} ____cacheline_aligned; } ____cacheline_aligned;
/* Unmap queues for Tx / Rx cleanup */ struct bnad_tx_vector {
struct bnad_skb_unmap { DEFINE_DMA_UNMAP_ADDR(dma_addr);
};
struct bnad_tx_unmap {
struct sk_buff *skb; struct sk_buff *skb;
u32 nvecs;
struct bnad_tx_vector vectors[BFI_TX_MAX_VECTORS_PER_WI];
};
struct bnad_rx_vector {
DEFINE_DMA_UNMAP_ADDR(dma_addr); DEFINE_DMA_UNMAP_ADDR(dma_addr);
u32 len;
}; };
struct bnad_unmap_q { struct bnad_rx_unmap {
u32 producer_index; struct sk_buff *skb;
u32 consumer_index; struct bnad_rx_vector vector;
u32 q_depth;
/* This should be the last one */
struct bnad_skb_unmap unmap_array[1];
}; };
/* Bit mask values for bnad->cfg_flags */ /* Bit mask values for bnad->cfg_flags */
...@@ -252,11 +254,6 @@ struct bnad_unmap_q { ...@@ -252,11 +254,6 @@ struct bnad_unmap_q {
#define BNAD_RF_STATS_TIMER_RUNNING 5 #define BNAD_RF_STATS_TIMER_RUNNING 5
#define BNAD_RF_TX_PRIO_SET 6 #define BNAD_RF_TX_PRIO_SET 6
/* Define for Fast Path flags */
/* Defined as bit positions */
#define BNAD_FP_IN_RX_PATH 0
struct bnad { struct bnad {
struct net_device *netdev; struct net_device *netdev;
u32 id; u32 id;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment