From 873fcdd4bfc75880888a7d148a71d70ed87c9ebf Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:37 -0700 Subject: [PATCH] RDMA/nes: Allocate work item for disconnect event handling The code currently has a work structure in the QP. This requires a lock and a pending flag to ensure there is never more than one request active. When two events happen quickly (such as FIN and LLP CLOSE), it causes unnecessary timeouts since the second one is dropped. This fix allocates memory for the work request so the second one can be queued. A lock is removed since it is no longer needed. Signed-off-by: Don Wood Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_cm.c | 26 +++++++++++--------------- drivers/infiniband/hw/nes/nes_verbs.h | 7 +++++-- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index fe08eb57c99f..d89bdee0cf55 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -2450,20 +2450,16 @@ static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_nod */ int nes_cm_disconn(struct nes_qp *nesqp) { - unsigned long flags; + struct disconn_work *work; - spin_lock_irqsave(&nesqp->lock, flags); - if (nesqp->disconn_pending == 0) { - nesqp->disconn_pending++; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_add_ref(&nesqp->ibqp); - /* init our disconnect work element, to */ - INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker); - - queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work); - } else - spin_unlock_irqrestore(&nesqp->lock, flags); + work = kzalloc(sizeof *work, GFP_ATOMIC); + if (!work) + return -ENOMEM; /* Timer will clean up */ + nes_add_ref(&nesqp->ibqp); + work->nesqp = nesqp; + INIT_WORK(&work->work, nes_disconnect_worker); + queue_work(g_cm_core->disconn_wq, &work->work); return 0; } @@ -2473,8 +2469,10 @@ int nes_cm_disconn(struct nes_qp *nesqp) */ static void nes_disconnect_worker(struct work_struct *work) { - struct nes_qp *nesqp = container_of(work, struct nes_qp, disconn_work); + struct disconn_work *dwork = container_of(work, struct disconn_work, work); + struct nes_qp *nesqp = dwork->nesqp; + kfree(dwork); nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n", nesqp->last_aeq, nesqp->hwqp.qp_id); nes_cm_disconn_true(nesqp); @@ -2557,7 +2555,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) spin_lock_irqsave(&nesqp->lock, flags); } - nesqp->disconn_pending = 0; /* There might have been another AE while the lock was released */ original_hw_tcp_state = nesqp->hw_tcp_state; original_ibqp_state = nesqp->ibqp_state; @@ -2610,7 +2607,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) } } } else { - nesqp->disconn_pending = 0; spin_unlock_irqrestore(&nesqp->lock, flags); } diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h index 41c07f29f7c9..7df34fea2888 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.h +++ b/drivers/infiniband/hw/nes/nes_verbs.h @@ -119,6 +119,11 @@ struct nes_wq { spinlock_t lock; }; +struct disconn_work { + struct work_struct work; + struct nes_qp *nesqp; +}; + struct iw_cm_id; struct ietf_mpa_frame; @@ -127,7 +132,6 @@ struct nes_qp { void *allocated_buffer; struct iw_cm_id *cm_id; struct workqueue_struct *wq; - struct work_struct disconn_work; struct nes_cq *nesscq; struct nes_cq *nesrcq; struct nes_pd *nespd; @@ -165,7 +169,6 @@ struct nes_qp { u8 hw_iwarp_state; u8 flush_issued; u8 hw_tcp_state; - u8 disconn_pending; u8 destroyed; }; #endif /* NES_VERBS_H */ -- 2.20.1