RDMA/nes: Fix for sending fpdus in order to hardware

Locking fix to prevent race conditions. Fpdus (per qp) need to be
forwarded to hardware in the order of their sequence numbers.

Signed-off-by: Tatyana Nikolova <Tatyana.E.Nikolova@intel.com>
Signed-off-by: Donald Wood <Donald.E.Wood@intel.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
This commit is contained in:
Tatyana Nikolova 2012-11-02 23:17:54 +00:00 committed by Roland Dreier
parent bff3976bef
commit fc8d7547b1

View File

@ -247,7 +247,6 @@ static int get_fpdu_info(struct nes_device *nesdev, struct nes_qp *nesqp,
struct nes_rskb_cb *cb; struct nes_rskb_cb *cb;
struct pau_fpdu_info *fpdu_info = NULL; struct pau_fpdu_info *fpdu_info = NULL;
struct pau_fpdu_frag frags[MAX_FPDU_FRAGS]; struct pau_fpdu_frag frags[MAX_FPDU_FRAGS];
unsigned long flags;
u32 fpdu_len = 0; u32 fpdu_len = 0;
u32 tmp_len; u32 tmp_len;
int frag_cnt = 0; int frag_cnt = 0;
@ -262,12 +261,10 @@ static int get_fpdu_info(struct nes_device *nesdev, struct nes_qp *nesqp,
*pau_fpdu_info = NULL; *pau_fpdu_info = NULL;
spin_lock_irqsave(&nesqp->pau_lock, flags);
skb = nes_get_next_skb(nesdev, nesqp, NULL, nesqp->pau_rcv_nxt, &ack, &wnd, &fin_rcvd, &rst_rcvd); skb = nes_get_next_skb(nesdev, nesqp, NULL, nesqp->pau_rcv_nxt, &ack, &wnd, &fin_rcvd, &rst_rcvd);
if (!skb) { if (!skb)
spin_unlock_irqrestore(&nesqp->pau_lock, flags);
goto out; goto out;
}
cb = (struct nes_rskb_cb *)&skb->cb[0]; cb = (struct nes_rskb_cb *)&skb->cb[0];
if (skb->len) { if (skb->len) {
fpdu_len = be16_to_cpu(*(__be16 *) skb->data) + MPA_FRAMING; fpdu_len = be16_to_cpu(*(__be16 *) skb->data) + MPA_FRAMING;
@ -292,10 +289,9 @@ static int get_fpdu_info(struct nes_device *nesdev, struct nes_qp *nesqp,
skb = nes_get_next_skb(nesdev, nesqp, skb, skb = nes_get_next_skb(nesdev, nesqp, skb,
nesqp->pau_rcv_nxt + frag_tot, &ack, &wnd, &fin_rcvd, &rst_rcvd); nesqp->pau_rcv_nxt + frag_tot, &ack, &wnd, &fin_rcvd, &rst_rcvd);
if (!skb) { if (!skb)
spin_unlock_irqrestore(&nesqp->pau_lock, flags);
goto out; goto out;
} else if (rst_rcvd) { if (rst_rcvd) {
/* rst received in the middle of fpdu */ /* rst received in the middle of fpdu */
for (; i >= 0; i--) { for (; i >= 0; i--) {
skb_unlink(frags[i].skb, &nesqp->pau_list); skb_unlink(frags[i].skb, &nesqp->pau_list);
@ -322,8 +318,6 @@ static int get_fpdu_info(struct nes_device *nesdev, struct nes_qp *nesqp,
frag_cnt = 1; frag_cnt = 1;
} }
spin_unlock_irqrestore(&nesqp->pau_lock, flags);
/* Found one */ /* Found one */
fpdu_info = kzalloc(sizeof(*fpdu_info), GFP_ATOMIC); fpdu_info = kzalloc(sizeof(*fpdu_info), GFP_ATOMIC);
if (fpdu_info == NULL) { if (fpdu_info == NULL) {
@ -385,10 +379,8 @@ static int get_fpdu_info(struct nes_device *nesdev, struct nes_qp *nesqp,
if (frags[i].skb->len == 0) { if (frags[i].skb->len == 0) {
/* Pull skb off the list - it will be freed in the callback */ /* Pull skb off the list - it will be freed in the callback */
spin_lock_irqsave(&nesqp->pau_lock, flags);
if (!skb_queue_empty(&nesqp->pau_list)) if (!skb_queue_empty(&nesqp->pau_list))
skb_unlink(frags[i].skb, &nesqp->pau_list); skb_unlink(frags[i].skb, &nesqp->pau_list);
spin_unlock_irqrestore(&nesqp->pau_lock, flags);
} else { } else {
/* Last skb still has data so update the seq */ /* Last skb still has data so update the seq */
iph = (struct iphdr *)(cb->data_start + ETH_HLEN); iph = (struct iphdr *)(cb->data_start + ETH_HLEN);
@ -417,14 +409,18 @@ static int forward_fpdus(struct nes_vnic *nesvnic, struct nes_qp *nesqp)
struct pau_fpdu_info *fpdu_info; struct pau_fpdu_info *fpdu_info;
struct nes_hw_cqp_wqe *cqp_wqe; struct nes_hw_cqp_wqe *cqp_wqe;
struct nes_cqp_request *cqp_request; struct nes_cqp_request *cqp_request;
unsigned long flags;
u64 u64tmp; u64 u64tmp;
u32 u32tmp; u32 u32tmp;
int rc; int rc;
while (1) { while (1) {
spin_lock_irqsave(&nesqp->pau_lock, flags);
rc = get_fpdu_info(nesdev, nesqp, &fpdu_info); rc = get_fpdu_info(nesdev, nesqp, &fpdu_info);
if (fpdu_info == NULL) if (rc || (fpdu_info == NULL)) {
spin_unlock_irqrestore(&nesqp->pau_lock, flags);
return rc; return rc;
}
cqp_request = fpdu_info->cqp_request; cqp_request = fpdu_info->cqp_request;
cqp_wqe = &cqp_request->cqp_wqe; cqp_wqe = &cqp_request->cqp_wqe;
@ -478,6 +474,7 @@ static int forward_fpdus(struct nes_vnic *nesvnic, struct nes_qp *nesqp)
atomic_set(&cqp_request->refcount, 1); atomic_set(&cqp_request->refcount, 1);
nes_post_cqp_request(nesdev, cqp_request); nes_post_cqp_request(nesdev, cqp_request);
spin_unlock_irqrestore(&nesqp->pau_lock, flags);
} }
return 0; return 0;