Commit f218d67e authored by Selvin Xavier's avatar Selvin Xavier Committed by Doug Ledford

RDMA/bnxt_re: Allow posting when QPs are in error

This  patch allows driver to post send and receive
requests on QPs which are in  error state.

Instead of flushing the QP in the context of polling
error CQEs, the QPs will be added to a flush list
maintained per CQ. QP state is moved to error.
QP is added to flush list if the user moves it
to error state using modify_qp also. After polling the HW
CQ in poll_cq routine, this flush list is traversed
and driver completes work requests on each QP in the flush
list, till the budget expires. The QP is moved out of
flush list during QP destroy or during modify_QP to RESET.

When ULPs post Work Requests while QP is in error state,
driver will store the ULP data and then increment the
QP producer s/w index, without ringing doorbell. It then
schedules a worker to invoke the CQ handler since the
interrupts wont be generated from the HW for this request.
Signed-off-by: default avatarSriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
Signed-off-by: default avatarSelvin Xavier <selvin.xavier@broadcom.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 5fac5b1b
...@@ -786,6 +786,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp) ...@@ -786,6 +786,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp)
struct bnxt_re_dev *rdev = qp->rdev; struct bnxt_re_dev *rdev = qp->rdev;
int rc; int rc;
bnxt_qplib_del_flush_qp(&qp->qplib_qp);
rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp); rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
if (rc) { if (rc) {
dev_err(rdev_to_dev(rdev), "Failed to destroy HW QP"); dev_err(rdev_to_dev(rdev), "Failed to destroy HW QP");
...@@ -800,6 +801,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp) ...@@ -800,6 +801,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp)
return rc; return rc;
} }
bnxt_qplib_del_flush_qp(&qp->qplib_qp);
rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, rc = bnxt_qplib_destroy_qp(&rdev->qplib_res,
&rdev->qp1_sqp->qplib_qp); &rdev->qp1_sqp->qplib_qp);
if (rc) { if (rc) {
...@@ -1344,6 +1346,21 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, ...@@ -1344,6 +1346,21 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
} }
qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_STATE; qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_STATE;
qp->qplib_qp.state = __from_ib_qp_state(qp_attr->qp_state); qp->qplib_qp.state = __from_ib_qp_state(qp_attr->qp_state);
if (!qp->sumem &&
qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
dev_dbg(rdev_to_dev(rdev),
"Move QP = %p to flush list\n",
qp);
bnxt_qplib_add_flush_qp(&qp->qplib_qp);
}
if (!qp->sumem &&
qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_RESET) {
dev_dbg(rdev_to_dev(rdev),
"Move QP = %p out of flush list\n",
qp);
bnxt_qplib_del_flush_qp(&qp->qplib_qp);
}
} }
if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) { if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) {
qp->qplib_qp.modify_flags |= qp->qplib_qp.modify_flags |=
...@@ -2354,6 +2371,7 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev, ...@@ -2354,6 +2371,7 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev,
} }
cq->qplib_cq.max_wqe = entries; cq->qplib_cq.max_wqe = entries;
cq->qplib_cq.cnq_hw_ring_id = rdev->nq.ring_id; cq->qplib_cq.cnq_hw_ring_id = rdev->nq.ring_id;
cq->qplib_cq.nq = &rdev->nq;
rc = bnxt_qplib_create_cq(&rdev->qplib_res, &cq->qplib_cq); rc = bnxt_qplib_create_cq(&rdev->qplib_res, &cq->qplib_cq);
if (rc) { if (rc) {
...@@ -2861,6 +2879,10 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc) ...@@ -2861,6 +2879,10 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc)
sq->send_phantom = false; sq->send_phantom = false;
} }
} }
if (ncqe < budget)
ncqe += bnxt_qplib_process_flush_list(&cq->qplib_cq,
cqe + ncqe,
budget - ncqe);
if (!ncqe) if (!ncqe)
break; break;
......
...@@ -1037,7 +1037,8 @@ static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev) ...@@ -1037,7 +1037,8 @@ static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev)
/* Establish RCFW Communication Channel to initialize the context /* Establish RCFW Communication Channel to initialize the context
* memory for the function and all child VFs * memory for the function and all child VFs
*/ */
rc = bnxt_qplib_alloc_rcfw_channel(rdev->en_dev->pdev, &rdev->rcfw); rc = bnxt_qplib_alloc_rcfw_channel(rdev->en_dev->pdev, &rdev->rcfw,
BNXT_RE_MAX_QPC_COUNT);
if (rc) if (rc)
goto fail; goto fail;
......
This diff is collapsed.
...@@ -220,19 +220,20 @@ struct bnxt_qplib_q { ...@@ -220,19 +220,20 @@ struct bnxt_qplib_q {
u16 q_full_delta; u16 q_full_delta;
u16 max_sge; u16 max_sge;
u32 psn; u32 psn;
bool flush_in_progress;
bool condition; bool condition;
bool single; bool single;
bool send_phantom; bool send_phantom;
u32 phantom_wqe_cnt; u32 phantom_wqe_cnt;
u32 phantom_cqe_cnt; u32 phantom_cqe_cnt;
u32 next_cq_cons; u32 next_cq_cons;
bool flushed;
}; };
struct bnxt_qplib_qp { struct bnxt_qplib_qp {
struct bnxt_qplib_pd *pd; struct bnxt_qplib_pd *pd;
struct bnxt_qplib_dpi *dpi; struct bnxt_qplib_dpi *dpi;
u64 qp_handle; u64 qp_handle;
#define BNXT_QPLIB_QP_ID_INVALID 0xFFFFFFFF
u32 id; u32 id;
u8 type; u8 type;
u8 sig_type; u8 sig_type;
...@@ -296,6 +297,8 @@ struct bnxt_qplib_qp { ...@@ -296,6 +297,8 @@ struct bnxt_qplib_qp {
dma_addr_t sq_hdr_buf_map; dma_addr_t sq_hdr_buf_map;
void *rq_hdr_buf; void *rq_hdr_buf;
dma_addr_t rq_hdr_buf_map; dma_addr_t rq_hdr_buf_map;
struct list_head sq_flush;
struct list_head rq_flush;
}; };
#define BNXT_QPLIB_MAX_CQE_ENTRY_SIZE sizeof(struct cq_base) #define BNXT_QPLIB_MAX_CQE_ENTRY_SIZE sizeof(struct cq_base)
...@@ -351,6 +354,7 @@ struct bnxt_qplib_cq { ...@@ -351,6 +354,7 @@ struct bnxt_qplib_cq {
u16 period; u16 period;
struct bnxt_qplib_hwq hwq; struct bnxt_qplib_hwq hwq;
u32 cnq_hw_ring_id; u32 cnq_hw_ring_id;
struct bnxt_qplib_nq *nq;
bool resize_in_progress; bool resize_in_progress;
struct scatterlist *sghead; struct scatterlist *sghead;
u32 nmap; u32 nmap;
...@@ -360,6 +364,9 @@ struct bnxt_qplib_cq { ...@@ -360,6 +364,9 @@ struct bnxt_qplib_cq {
unsigned long flags; unsigned long flags;
#define CQ_FLAGS_RESIZE_IN_PROG 1 #define CQ_FLAGS_RESIZE_IN_PROG 1
wait_queue_head_t waitq; wait_queue_head_t waitq;
struct list_head sqf_head, rqf_head;
atomic_t arm_state;
spinlock_t compl_lock; /* synch CQ handlers */
}; };
#define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE sizeof(struct xrrq_irrq) #define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE sizeof(struct xrrq_irrq)
...@@ -417,6 +424,13 @@ struct bnxt_qplib_nq { ...@@ -417,6 +424,13 @@ struct bnxt_qplib_nq {
(struct bnxt_qplib_nq *nq, (struct bnxt_qplib_nq *nq,
void *srq, void *srq,
u8 event); u8 event);
struct workqueue_struct *cqn_wq;
};
struct bnxt_qplib_nq_work {
struct work_struct work;
struct bnxt_qplib_nq *nq;
struct bnxt_qplib_cq *cq;
}; };
void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq); void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq);
...@@ -453,4 +467,13 @@ bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq); ...@@ -453,4 +467,13 @@ bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq);
void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type); void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type);
void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq); void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq);
int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq); int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq);
void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp);
void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp);
void bnxt_qplib_acquire_cq_locks(struct bnxt_qplib_qp *qp,
unsigned long *flags);
void bnxt_qplib_release_cq_locks(struct bnxt_qplib_qp *qp,
unsigned long *flags);
int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq,
struct bnxt_qplib_cqe *cqe,
int num_cqes);
#endif /* __BNXT_QPLIB_FP_H__ */ #endif /* __BNXT_QPLIB_FP_H__ */
...@@ -44,6 +44,9 @@ ...@@ -44,6 +44,9 @@
#include "roce_hsi.h" #include "roce_hsi.h"
#include "qplib_res.h" #include "qplib_res.h"
#include "qplib_rcfw.h" #include "qplib_rcfw.h"
#include "qplib_sp.h"
#include "qplib_fp.h"
static void bnxt_qplib_service_creq(unsigned long data); static void bnxt_qplib_service_creq(unsigned long data);
/* Hardware communication channel */ /* Hardware communication channel */
...@@ -279,16 +282,29 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw, ...@@ -279,16 +282,29 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
struct creq_qp_event *qp_event) struct creq_qp_event *qp_event)
{ {
struct bnxt_qplib_hwq *cmdq = &rcfw->cmdq; struct bnxt_qplib_hwq *cmdq = &rcfw->cmdq;
struct creq_qp_error_notification *err_event;
struct bnxt_qplib_crsq *crsqe; struct bnxt_qplib_crsq *crsqe;
unsigned long flags; unsigned long flags;
struct bnxt_qplib_qp *qp;
u16 cbit, blocked = 0; u16 cbit, blocked = 0;
u16 cookie; u16 cookie;
__le16 mcookie; __le16 mcookie;
u32 qp_id;
switch (qp_event->event) { switch (qp_event->event) {
case CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION: case CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION:
err_event = (struct creq_qp_error_notification *)qp_event;
qp_id = le32_to_cpu(err_event->xid);
qp = rcfw->qp_tbl[qp_id].qp_handle;
dev_dbg(&rcfw->pdev->dev, dev_dbg(&rcfw->pdev->dev,
"QPLIB: Received QP error notification"); "QPLIB: Received QP error notification");
dev_dbg(&rcfw->pdev->dev,
"QPLIB: qpid 0x%x, req_err=0x%x, resp_err=0x%x\n",
qp_id, err_event->req_err_state_reason,
err_event->res_err_state_reason);
bnxt_qplib_acquire_cq_locks(qp, &flags);
bnxt_qplib_mark_qp_error(qp);
bnxt_qplib_release_cq_locks(qp, &flags);
break; break;
default: default:
/* Command Response */ /* Command Response */
...@@ -507,6 +523,7 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, ...@@ -507,6 +523,7 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
{ {
kfree(rcfw->qp_tbl);
kfree(rcfw->crsqe_tbl); kfree(rcfw->crsqe_tbl);
bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->cmdq); bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->cmdq);
bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->creq); bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->creq);
...@@ -514,7 +531,8 @@ void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) ...@@ -514,7 +531,8 @@ void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
} }
int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev, int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
struct bnxt_qplib_rcfw *rcfw) struct bnxt_qplib_rcfw *rcfw,
int qp_tbl_sz)
{ {
rcfw->pdev = pdev; rcfw->pdev = pdev;
rcfw->creq.max_elements = BNXT_QPLIB_CREQE_MAX_CNT; rcfw->creq.max_elements = BNXT_QPLIB_CREQE_MAX_CNT;
...@@ -541,6 +559,12 @@ int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev, ...@@ -541,6 +559,12 @@ int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
if (!rcfw->crsqe_tbl) if (!rcfw->crsqe_tbl)
goto fail; goto fail;
rcfw->qp_tbl_size = qp_tbl_sz;
rcfw->qp_tbl = kcalloc(qp_tbl_sz, sizeof(struct bnxt_qplib_qp_node),
GFP_KERNEL);
if (!rcfw->qp_tbl)
goto fail;
return 0; return 0;
fail: fail:
......
...@@ -148,6 +148,11 @@ struct bnxt_qplib_rcfw_sbuf { ...@@ -148,6 +148,11 @@ struct bnxt_qplib_rcfw_sbuf {
u32 size; u32 size;
}; };
struct bnxt_qplib_qp_node {
u32 qp_id; /* QP id */
void *qp_handle; /* ptr to qplib_qp */
};
/* RCFW Communication Channels */ /* RCFW Communication Channels */
struct bnxt_qplib_rcfw { struct bnxt_qplib_rcfw {
struct pci_dev *pdev; struct pci_dev *pdev;
...@@ -181,11 +186,13 @@ struct bnxt_qplib_rcfw { ...@@ -181,11 +186,13 @@ struct bnxt_qplib_rcfw {
/* Actual Cmd and Resp Queues */ /* Actual Cmd and Resp Queues */
struct bnxt_qplib_hwq cmdq; struct bnxt_qplib_hwq cmdq;
struct bnxt_qplib_crsq *crsqe_tbl; struct bnxt_qplib_crsq *crsqe_tbl;
int qp_tbl_size;
struct bnxt_qplib_qp_node *qp_tbl;
}; };
void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw); void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev, int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
struct bnxt_qplib_rcfw *rcfw); struct bnxt_qplib_rcfw *rcfw, int qp_tbl_sz);
void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw); void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev, int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
struct bnxt_qplib_rcfw *rcfw, struct bnxt_qplib_rcfw *rcfw,
...@@ -207,4 +214,5 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, ...@@ -207,4 +214,5 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw); int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw);
int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
struct bnxt_qplib_ctx *ctx, int is_virtfn); struct bnxt_qplib_ctx *ctx, int is_virtfn);
void bnxt_qplib_mark_qp_error(void *qp_handle);
#endif /* __BNXT_QPLIB_RCFW_H__ */ #endif /* __BNXT_QPLIB_RCFW_H__ */
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