FW runs out of buffer if buffers are not posted back soon. ASYNC Rx CQE indicates that FW has consumed 8 RQEs. Use it to post back buffers instead of waiting for buffers to be processed and freed by driver. Signed-off-by: Jitendra Bhivare <jitendra.bhivare@xxxxxxxxxxxx> --- drivers/scsi/be2iscsi/be_main.c | 124 ++++++++++++++++------------------------ drivers/scsi/be2iscsi/be_main.h | 1 + 2 files changed, 51 insertions(+), 74 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index b76fd26..1cd9c2d 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1467,7 +1467,8 @@ beiscsi_hdl_put_handle(struct hd_async_context *pasync_ctx, static struct hd_async_handle * beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, struct hd_async_context *pasync_ctx, - struct i_t_dpdu_cqe *pdpdu_cqe) + struct i_t_dpdu_cqe *pdpdu_cqe, + u8 *header) { struct beiscsi_hba *phba = beiscsi_conn->phba; struct hd_async_handle *pasync_handle; @@ -1515,6 +1516,7 @@ beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, switch (code) { case UNSOL_HDR_NOTIFY: pasync_handle = pasync_ctx->async_entry[ci].header; + *header = 1; break; case UNSOL_DATA_DIGEST_ERROR_NOTIFY: error = 1; @@ -1547,6 +1549,7 @@ beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, /* FW has stale address - attempt continuing by dropping */ } + list_del_init(&pasync_handle->link); /** * Each CID is associated with unique CRI. * ASYNC_CRI_FROM_CID mapping and CRI_FROM_CID are totaly different. @@ -1554,11 +1557,6 @@ beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, pasync_handle->cri = BE_GET_ASYNC_CRI_FROM_CID(cid); pasync_handle->is_final = final; pasync_handle->buffer_len = dpl; - /* empty the slot */ - if (pasync_handle->is_header) - pasync_ctx->async_entry[ci].header = NULL; - else - pasync_ctx->async_entry[ci].data = NULL; /** * DEF PDU header and data buffers with errors should be simply @@ -1708,85 +1706,53 @@ beiscsi_hdl_gather_pdu(struct beiscsi_conn *beiscsi_conn, static void beiscsi_hdq_post_handles(struct beiscsi_hba *phba, - u8 header, u8 ulp_num) + u8 header, u8 ulp_num, u16 nbuf) { - struct hd_async_handle *pasync_handle, *tmp, **slot; + struct hd_async_handle *pasync_handle; struct hd_async_context *pasync_ctx; struct hwi_controller *phwi_ctrlr; - struct list_head *hfree_list; struct phys_addr *pasync_sge; u32 ring_id, doorbell = 0; u32 doorbell_offset; - u16 prod = 0, cons; - u16 index; + u16 prod, pi; phwi_ctrlr = phba->phwi_ctrlr; pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num); if (header) { - cons = pasync_ctx->async_header.free_entries; - hfree_list = &pasync_ctx->async_header.free_list; + pasync_sge = pasync_ctx->async_header.ring_base; + pi = pasync_ctx->async_header.pi; ring_id = phwi_ctrlr->default_pdu_hdr[ulp_num].id; doorbell_offset = phwi_ctrlr->default_pdu_hdr[ulp_num]. doorbell_offset; } else { - cons = pasync_ctx->async_data.free_entries; - hfree_list = &pasync_ctx->async_data.free_list; + pasync_sge = pasync_ctx->async_data.ring_base; + pi = pasync_ctx->async_data.pi; ring_id = phwi_ctrlr->default_pdu_data[ulp_num].id; doorbell_offset = phwi_ctrlr->default_pdu_data[ulp_num]. doorbell_offset; } - /* number of entries posted must be in multiples of 8 */ - if (cons % 8) - return; - list_for_each_entry_safe(pasync_handle, tmp, hfree_list, link) { - list_del_init(&pasync_handle->link); - pasync_handle->is_final = 0; - pasync_handle->buffer_len = 0; - - /* handles can be consumed out of order, use index in handle */ - index = pasync_handle->index; - WARN_ON(pasync_handle->is_header != header); + for (prod = 0; prod < nbuf; prod++) { if (header) - slot = &pasync_ctx->async_entry[index].header; + pasync_handle = pasync_ctx->async_entry[pi].header; else - slot = &pasync_ctx->async_entry[index].data; - /** - * The slot just tracks handle's hold and release, so - * overwriting at the same index won't do any harm but - * needs to be caught. - */ - if (*slot != NULL) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, - "BM_%d : async PDU %s slot at %u not empty\n", - header ? "header" : "data", index); + pasync_handle = pasync_ctx->async_entry[pi].data; + WARN_ON(pasync_handle->is_header != header); + WARN_ON(pasync_handle->index != pi); + /* setup the ring only once */ + if (nbuf == pasync_ctx->num_entries) { + /* note hi is lo */ + pasync_sge[pi].hi = pasync_handle->pa.u.a32.address_lo; + pasync_sge[pi].lo = pasync_handle->pa.u.a32.address_hi; } - /** - * We use same freed index as in completion to post so this - * operation is not required for refills. Its required only - * for ring creation. - */ - if (header) - pasync_sge = pasync_ctx->async_header.ring_base; - else - pasync_sge = pasync_ctx->async_data.ring_base; - pasync_sge += index; - /* if its a refill then address is same; hi is lo */ - WARN_ON(pasync_sge->hi && - pasync_sge->hi != pasync_handle->pa.u.a32.address_lo); - WARN_ON(pasync_sge->lo && - pasync_sge->lo != pasync_handle->pa.u.a32.address_hi); - pasync_sge->hi = pasync_handle->pa.u.a32.address_lo; - pasync_sge->lo = pasync_handle->pa.u.a32.address_hi; - - *slot = pasync_handle; - if (++prod == cons) - break; + if (++pi == pasync_ctx->num_entries) + pi = 0; } + if (header) - pasync_ctx->async_header.free_entries -= prod; + pasync_ctx->async_header.pi = pi; else - pasync_ctx->async_data.free_entries -= prod; + pasync_ctx->async_data.pi = pi; doorbell |= ring_id & DB_DEF_PDU_RING_ID_MASK; doorbell |= 1 << DB_DEF_PDU_REARM_SHIFT; @@ -1803,20 +1769,26 @@ beiscsi_hdq_process_compl(struct beiscsi_conn *beiscsi_conn, struct hd_async_handle *pasync_handle = NULL; struct hd_async_context *pasync_ctx; struct hwi_controller *phwi_ctrlr; + u8 ulp_num, consumed, header = 0; u16 cid_cri; - u8 ulp_num; phwi_ctrlr = phba->phwi_ctrlr; cid_cri = BE_GET_CRI_FROM_CID(beiscsi_conn->beiscsi_conn_cid); ulp_num = BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, cid_cri); pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num); pasync_handle = beiscsi_hdl_get_handle(beiscsi_conn, pasync_ctx, - pdpdu_cqe); - if (!pasync_handle) - return; - - beiscsi_hdl_gather_pdu(beiscsi_conn, pasync_ctx, pasync_handle); - beiscsi_hdq_post_handles(phba, pasync_handle->is_header, ulp_num); + pdpdu_cqe, &header); + if (is_chip_be2_be3r(phba)) + consumed = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, + num_cons, pdpdu_cqe); + else + consumed = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2, + num_cons, pdpdu_cqe); + if (pasync_handle) + beiscsi_hdl_gather_pdu(beiscsi_conn, pasync_ctx, pasync_handle); + /* num_cons indicates number of 8 RQEs consumed */ + if (consumed) + beiscsi_hdq_post_handles(phba, header, ulp_num, 8 * consumed); } void beiscsi_process_mcc_cq(struct beiscsi_hba *phba) @@ -2775,6 +2747,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) "BM_%d : No Virtual address for ULP : %d\n", ulp_num); + pasync_ctx->async_header.pi = 0; pasync_ctx->async_header.buffer_size = p->defpdu_hdr_sz; pasync_ctx->async_header.va_base = mem_descr->mem_array[0].virtual_address; @@ -2883,6 +2856,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) ulp_num); idx = 0; + pasync_ctx->async_data.pi = 0; pasync_ctx->async_data.buffer_size = p->defpdu_data_sz; pasync_ctx->async_data.va_base = mem_descr->mem_array[idx].virtual_address; @@ -2913,11 +2887,12 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) list_add_tail(&pasync_header_h->link, &pasync_ctx->async_header. free_list); + pasync_ctx->async_entry[index].header = + pasync_header_h; pasync_header_h++; pasync_ctx->async_header.free_entries++; INIT_LIST_HEAD(&pasync_ctx->async_entry[index]. wq.list); - pasync_ctx->async_entry[index].header = NULL; pasync_data_h->cri = -1; pasync_data_h->is_header = 0; @@ -2954,9 +2929,10 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) list_add_tail(&pasync_data_h->link, &pasync_ctx->async_data. free_list); + pasync_ctx->async_entry[index].data = + pasync_data_h; pasync_data_h++; pasync_ctx->async_data.free_entries++; - pasync_ctx->async_entry[index].data = NULL; } } } @@ -3734,6 +3710,7 @@ static int hwi_init_port(struct beiscsi_hba *phba) unsigned int def_pdu_ring_sz; struct be_ctrl_info *ctrl = &phba->ctrl; int status, ulp_num; + u16 nbufs; phwi_ctrlr = phba->phwi_ctrlr; phwi_context = phwi_ctrlr->phwi_ctxt; @@ -3770,9 +3747,8 @@ static int hwi_init_port(struct beiscsi_hba *phba) for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { - def_pdu_ring_sz = - BEISCSI_ASYNC_HDQ_SIZE(phba, ulp_num) * - sizeof(struct phys_addr); + nbufs = phwi_context->pasync_ctx[ulp_num]->num_entries; + def_pdu_ring_sz = nbufs * sizeof(struct phys_addr); status = beiscsi_create_def_hdr(phba, phwi_context, phwi_ctrlr, @@ -3800,9 +3776,9 @@ static int hwi_init_port(struct beiscsi_hba *phba) * let EP know about it. */ beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR, - ulp_num); + ulp_num, nbufs); beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_DATA, - ulp_num); + ulp_num, nbufs); } } diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 216f9b4..cebacac 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -634,6 +634,7 @@ struct hd_async_buf_context { * They are posted back to FW in groups of 8. */ struct list_head free_list; + u16 pi; }; /** -- 2.7.4