Skip to content

Commit 2529aea

Browse files
jakemoronirleon
authored andcommitted
RDMA/irdma: Use CQ ID for CEQE context
The hardware allows for an opaque CQ context field to be carried over into CEQEs for the CQ. Previously, a pointer to the CQ was used for this context. In the normal CQ destroy flow, the CEQ ring is scrubbed to remove any preexisting CEQEs for the CQ that may not have been processed yet so that the CQ structure is not dereferenced in the CEQ ISR after the CQ has been freed. However, in some cases, it is possible for a CEQE to be in flight in HW even after the CQ destroy command completion is received, so it could be missed during the scrub. To protect against this, we can take advantage of the CQ table that already exists and use the CQ ID for this context rather than a CQ pointer. Signed-off-by: Jacob Moroni <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Leon Romanovsky <[email protected]>
1 parent 2b7c2ba commit 2529aea

6 files changed

Lines changed: 127 additions & 51 deletions

File tree

drivers/infiniband/hw/irdma/ctrl.c

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2886,15 +2886,6 @@ static int irdma_sc_resume_qp(struct irdma_sc_cqp *cqp, struct irdma_sc_qp *qp,
28862886
return 0;
28872887
}
28882888

2889-
/**
2890-
* irdma_sc_cq_ack - acknowledge completion q
2891-
* @cq: cq struct
2892-
*/
2893-
static inline void irdma_sc_cq_ack(struct irdma_sc_cq *cq)
2894-
{
2895-
writel(cq->cq_uk.cq_id, cq->cq_uk.cq_ack_db);
2896-
}
2897-
28982889
/**
28992890
* irdma_sc_cq_init - initialize completion q
29002891
* @cq: cq struct
@@ -2956,7 +2947,7 @@ static int irdma_sc_cq_create(struct irdma_sc_cq *cq, u64 scratch,
29562947
return -ENOMEM;
29572948

29582949
set_64bit_val(wqe, 0, cq->cq_uk.cq_size);
2959-
set_64bit_val(wqe, 8, (uintptr_t)cq >> 1);
2950+
set_64bit_val(wqe, 8, cq->cq_uk.cq_id);
29602951
set_64bit_val(wqe, 16,
29612952
FIELD_PREP(IRDMA_CQPSQ_CQ_SHADOW_READ_THRESHOLD, cq->shadow_read_threshold));
29622953
set_64bit_val(wqe, 32, (cq->virtual_map ? 0 : cq->cq_pa));
@@ -3013,7 +3004,7 @@ int irdma_sc_cq_destroy(struct irdma_sc_cq *cq, u64 scratch, bool post_sq)
30133004
return -ENOMEM;
30143005

30153006
set_64bit_val(wqe, 0, cq->cq_uk.cq_size);
3016-
set_64bit_val(wqe, 8, (uintptr_t)cq >> 1);
3007+
set_64bit_val(wqe, 8, cq->cq_uk.cq_id);
30173008
set_64bit_val(wqe, 40, cq->shadow_area_pa);
30183009
set_64bit_val(wqe, 48,
30193010
(cq->virtual_map ? cq->first_pm_pbl_idx : 0));
@@ -3082,7 +3073,7 @@ static int irdma_sc_cq_modify(struct irdma_sc_cq *cq,
30823073
return -ENOMEM;
30833074

30843075
set_64bit_val(wqe, 0, info->cq_size);
3085-
set_64bit_val(wqe, 8, (uintptr_t)cq >> 1);
3076+
set_64bit_val(wqe, 8, cq->cq_uk.cq_id);
30863077
set_64bit_val(wqe, 16,
30873078
FIELD_PREP(IRDMA_CQPSQ_CQ_SHADOW_READ_THRESHOLD, info->shadow_read_threshold));
30883079
set_64bit_val(wqe, 32, info->cq_pa);
@@ -4458,47 +4449,38 @@ int irdma_sc_ceq_destroy(struct irdma_sc_ceq *ceq, u64 scratch, bool post_sq)
44584449
* irdma_sc_process_ceq - process ceq
44594450
* @dev: sc device struct
44604451
* @ceq: ceq sc structure
4452+
* @cq_idx: Pointer to a CQ ID that will be populated.
44614453
*
44624454
* It is expected caller serializes this function with cleanup_ceqes()
44634455
* because these functions manipulate the same ceq
4456+
*
4457+
* Return: True if cq_idx has been populated with a CQ ID.
44644458
*/
4465-
void *irdma_sc_process_ceq(struct irdma_sc_dev *dev, struct irdma_sc_ceq *ceq)
4459+
bool irdma_sc_process_ceq(struct irdma_sc_dev *dev, struct irdma_sc_ceq *ceq,
4460+
u32 *cq_idx)
44664461
{
44674462
u64 temp;
44684463
__le64 *ceqe;
4469-
struct irdma_sc_cq *cq = NULL;
4470-
struct irdma_sc_cq *temp_cq;
44714464
u8 polarity;
4472-
u32 cq_idx;
44734465

44744466
do {
4475-
cq_idx = 0;
44764467
ceqe = IRDMA_GET_CURRENT_CEQ_ELEM(ceq);
44774468
get_64bit_val(ceqe, 0, &temp);
44784469
polarity = (u8)FIELD_GET(IRDMA_CEQE_VALID, temp);
44794470
if (polarity != ceq->polarity)
4480-
return NULL;
4471+
return false;
44814472

4482-
temp_cq = (struct irdma_sc_cq *)(unsigned long)(temp << 1);
4483-
if (!temp_cq) {
4484-
cq_idx = IRDMA_INVALID_CQ_IDX;
4485-
IRDMA_RING_MOVE_TAIL(ceq->ceq_ring);
4486-
4487-
if (!IRDMA_RING_CURRENT_TAIL(ceq->ceq_ring))
4488-
ceq->polarity ^= 1;
4489-
continue;
4490-
}
4491-
4492-
cq = temp_cq;
4473+
/* Truncate. Discard valid bit which is MSb of temp. */
4474+
*cq_idx = temp;
4475+
if (*cq_idx >= dev->hmc_info->hmc_obj[IRDMA_HMC_IW_CQ].cnt)
4476+
*cq_idx = IRDMA_INVALID_CQ_IDX;
44934477

44944478
IRDMA_RING_MOVE_TAIL(ceq->ceq_ring);
44954479
if (!IRDMA_RING_CURRENT_TAIL(ceq->ceq_ring))
44964480
ceq->polarity ^= 1;
4497-
} while (cq_idx == IRDMA_INVALID_CQ_IDX);
4481+
} while (*cq_idx == IRDMA_INVALID_CQ_IDX);
44984482

4499-
if (cq)
4500-
irdma_sc_cq_ack(cq);
4501-
return cq;
4483+
return true;
45024484
}
45034485

45044486
/**
@@ -4512,10 +4494,10 @@ void *irdma_sc_process_ceq(struct irdma_sc_dev *dev, struct irdma_sc_ceq *ceq)
45124494
*/
45134495
void irdma_sc_cleanup_ceqes(struct irdma_sc_cq *cq, struct irdma_sc_ceq *ceq)
45144496
{
4515-
struct irdma_sc_cq *next_cq;
45164497
u8 ceq_polarity = ceq->polarity;
45174498
__le64 *ceqe;
45184499
u8 polarity;
4500+
u32 cq_idx;
45194501
u64 temp;
45204502
int next;
45214503
u32 i;
@@ -4530,9 +4512,10 @@ void irdma_sc_cleanup_ceqes(struct irdma_sc_cq *cq, struct irdma_sc_ceq *ceq)
45304512
if (polarity != ceq_polarity)
45314513
return;
45324514

4533-
next_cq = (struct irdma_sc_cq *)(unsigned long)(temp << 1);
4534-
if (cq == next_cq)
4535-
set_64bit_val(ceqe, 0, temp & IRDMA_CEQE_VALID);
4515+
cq_idx = temp;
4516+
if (cq_idx == cq->cq_uk.cq_id)
4517+
set_64bit_val(ceqe, 0, (temp & IRDMA_CEQE_VALID) |
4518+
IRDMA_INVALID_CQ_IDX);
45364519

45374520
next = IRDMA_RING_GET_NEXT_TAIL(ceq->ceq_ring, i);
45384521
if (!next)
@@ -4973,7 +4956,7 @@ int irdma_sc_ccq_destroy(struct irdma_sc_cq *ccq, u64 scratch, bool post_sq)
49734956
return -ENOMEM;
49744957

49754958
set_64bit_val(wqe, 0, ccq->cq_uk.cq_size);
4976-
set_64bit_val(wqe, 8, (uintptr_t)ccq >> 1);
4959+
set_64bit_val(wqe, 8, ccq->cq_uk.cq_id);
49774960
set_64bit_val(wqe, 40, ccq->shadow_area_pa);
49784961

49794962
hdr = ccq->cq_uk.cq_id |
@@ -6459,6 +6442,9 @@ int irdma_sc_dev_init(enum irdma_vers ver, struct irdma_sc_dev *dev,
64596442
int ret_code = 0;
64606443
u8 db_size;
64616444

6445+
spin_lock_init(&dev->puda_cq_lock);
6446+
dev->ilq_cq = NULL;
6447+
dev->ieq_cq = NULL;
64626448
INIT_LIST_HEAD(&dev->cqp_cmd_head); /* for CQP command backlog */
64636449
mutex_init(&dev->ws_mutex);
64646450
dev->hmc_fn_id = info->hmc_fn_id;

drivers/infiniband/hw/irdma/hw.c

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,74 @@ static void irdma_puda_ce_handler(struct irdma_pci_f *rf,
9898
irdma_sc_ccq_arm(cq);
9999
}
100100

101+
/**
102+
* irdma_process_normal_ceqe - Handle a CEQE for a normal CQ.
103+
* @rf: RDMA PCI function.
104+
* @dev: iWARP device.
105+
* @cq_idx: CQ ID. Must be in table bounds.
106+
*
107+
* Context: Atomic (CEQ lock must be held)
108+
*/
109+
static void irdma_process_normal_ceqe(struct irdma_pci_f *rf,
110+
struct irdma_sc_dev *dev, u32 cq_idx)
111+
{
112+
/* cq_idx bounds validated in irdma_sc_process_ceq. */
113+
struct irdma_cq *icq = READ_ONCE(rf->cq_table[cq_idx]);
114+
struct irdma_sc_cq *cq;
115+
116+
if (unlikely(!icq)) {
117+
/* Should not happen since CEQ is scrubbed upon CQ delete. */
118+
ibdev_warn_ratelimited(to_ibdev(dev), "Stale CEQE for CQ %u",
119+
cq_idx);
120+
return;
121+
}
122+
123+
cq = &icq->sc_cq;
124+
125+
if (unlikely(cq->cq_type != IRDMA_CQ_TYPE_IWARP)) {
126+
ibdev_warn_ratelimited(to_ibdev(dev), "Unexpected CQ type %u",
127+
cq->cq_type);
128+
return;
129+
}
130+
131+
writel(cq->cq_uk.cq_id, cq->cq_uk.cq_ack_db);
132+
irdma_iwarp_ce_handler(cq);
133+
}
134+
135+
/**
136+
* irdma_process_reserved_ceqe - Handle a CEQE for a reserved CQ.
137+
* @rf: RDMA PCI function.
138+
* @dev: iWARP device.
139+
* @cq_idx: CQ ID.
140+
*
141+
* Context: Atomic
142+
*/
143+
static void irdma_process_reserved_ceqe(struct irdma_pci_f *rf,
144+
struct irdma_sc_dev *dev, u32 cq_idx)
145+
{
146+
struct irdma_sc_cq *cq;
147+
148+
if (cq_idx == IRDMA_RSVD_CQ_ID_CQP) {
149+
cq = &rf->ccq.sc_cq;
150+
/* CQP CQ lifetime > CEQ. */
151+
writel(cq->cq_uk.cq_id, cq->cq_uk.cq_ack_db);
152+
queue_work(rf->cqp_cmpl_wq, &rf->cqp_cmpl_work);
153+
} else if (cq_idx == IRDMA_RSVD_CQ_ID_ILQ ||
154+
cq_idx == IRDMA_RSVD_CQ_ID_IEQ) {
155+
scoped_guard(spinlock_irqsave, &dev->puda_cq_lock) {
156+
cq = (cq_idx == IRDMA_RSVD_CQ_ID_ILQ) ?
157+
dev->ilq_cq : dev->ieq_cq;
158+
if (!cq) {
159+
ibdev_warn_ratelimited(to_ibdev(dev),
160+
"Stale ILQ/IEQ CEQE");
161+
return;
162+
}
163+
writel(cq->cq_uk.cq_id, cq->cq_uk.cq_ack_db);
164+
irdma_puda_ce_handler(rf, cq);
165+
}
166+
}
167+
}
168+
101169
/**
102170
* irdma_process_ceq - handle ceq for completions
103171
* @rf: RDMA PCI function
@@ -107,28 +175,28 @@ static void irdma_process_ceq(struct irdma_pci_f *rf, struct irdma_ceq *ceq)
107175
{
108176
struct irdma_sc_dev *dev = &rf->sc_dev;
109177
struct irdma_sc_ceq *sc_ceq;
110-
struct irdma_sc_cq *cq;
111178
unsigned long flags;
179+
u32 cq_idx;
112180

113181
sc_ceq = &ceq->sc_ceq;
114182
do {
115183
spin_lock_irqsave(&ceq->ce_lock, flags);
116-
cq = irdma_sc_process_ceq(dev, sc_ceq);
117-
if (!cq) {
184+
185+
if (!irdma_sc_process_ceq(dev, sc_ceq, &cq_idx)) {
118186
spin_unlock_irqrestore(&ceq->ce_lock, flags);
119187
break;
120188
}
121189

122-
if (cq->cq_type == IRDMA_CQ_TYPE_IWARP)
123-
irdma_iwarp_ce_handler(cq);
190+
/* Normal CQs must be handled while holding CEQ lock. */
191+
if (likely(cq_idx > IRDMA_RSVD_CQ_ID_IEQ)) {
192+
irdma_process_normal_ceqe(rf, dev, cq_idx);
193+
spin_unlock_irqrestore(&ceq->ce_lock, flags);
194+
continue;
195+
}
124196

125197
spin_unlock_irqrestore(&ceq->ce_lock, flags);
126198

127-
if (cq->cq_type == IRDMA_CQ_TYPE_CQP)
128-
queue_work(rf->cqp_cmpl_wq, &rf->cqp_cmpl_work);
129-
else if (cq->cq_type == IRDMA_CQ_TYPE_ILQ ||
130-
cq->cq_type == IRDMA_CQ_TYPE_IEQ)
131-
irdma_puda_ce_handler(rf, cq);
199+
irdma_process_reserved_ceqe(rf, dev, cq_idx);
132200
} while (1);
133201
}
134202

drivers/infiniband/hw/irdma/puda.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,13 @@ static int irdma_puda_cq_create(struct irdma_puda_rsrc *rsrc)
809809
dma_free_coherent(dev->hw->device, rsrc->cqmem.size,
810810
rsrc->cqmem.va, rsrc->cqmem.pa);
811811
rsrc->cqmem.va = NULL;
812+
} else {
813+
scoped_guard(spinlock_irqsave, &dev->puda_cq_lock) {
814+
if (rsrc->type == IRDMA_PUDA_RSRC_TYPE_ILQ)
815+
dev->ilq_cq = cq;
816+
else
817+
dev->ieq_cq = cq;
818+
}
812819
}
813820

814821
return ret;
@@ -856,6 +863,13 @@ static void irdma_puda_free_cq(struct irdma_puda_rsrc *rsrc)
856863
struct irdma_ccq_cqe_info compl_info;
857864
struct irdma_sc_dev *dev = rsrc->dev;
858865

866+
scoped_guard(spinlock_irqsave, &dev->puda_cq_lock) {
867+
if (rsrc->type == IRDMA_PUDA_RSRC_TYPE_ILQ)
868+
dev->ilq_cq = NULL;
869+
else
870+
dev->ieq_cq = NULL;
871+
}
872+
859873
if (rsrc->dev->ceq_valid) {
860874
irdma_cqp_cq_destroy_cmd(dev, &rsrc->cq);
861875
return;

drivers/infiniband/hw/irdma/type.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,9 @@ struct irdma_sc_dev {
707707
struct irdma_sc_aeq *aeq;
708708
struct irdma_sc_ceq *ceq[IRDMA_CEQ_MAX_COUNT];
709709
struct irdma_sc_cq *ccq;
710+
spinlock_t puda_cq_lock;
711+
struct irdma_sc_cq *ilq_cq;
712+
struct irdma_sc_cq *ieq_cq;
710713
const struct irdma_irq_ops *irq_ops;
711714
struct irdma_qos qos[IRDMA_MAX_USER_PRIORITY];
712715
struct irdma_hmc_fpm_misc hmc_fpm_misc;
@@ -1344,7 +1347,8 @@ int irdma_sc_ceq_destroy(struct irdma_sc_ceq *ceq, u64 scratch, bool post_sq);
13441347
int irdma_sc_ceq_init(struct irdma_sc_ceq *ceq,
13451348
struct irdma_ceq_init_info *info);
13461349
void irdma_sc_cleanup_ceqes(struct irdma_sc_cq *cq, struct irdma_sc_ceq *ceq);
1347-
void *irdma_sc_process_ceq(struct irdma_sc_dev *dev, struct irdma_sc_ceq *ceq);
1350+
bool irdma_sc_process_ceq(struct irdma_sc_dev *dev, struct irdma_sc_ceq *ceq,
1351+
u32 *cq_idx);
13481352

13491353
int irdma_sc_aeq_init(struct irdma_sc_aeq *aeq,
13501354
struct irdma_aeq_init_info *info);

drivers/infiniband/hw/irdma/utils.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,8 @@ void irdma_cq_rem_ref(struct ib_cq *ibcq)
829829
return;
830830
}
831831

832-
iwdev->rf->cq_table[iwcq->cq_num] = NULL;
832+
/* May be asynchronously sampled by CEQ ISR without holding tbl lock. */
833+
WRITE_ONCE(iwdev->rf->cq_table[iwcq->cq_num], NULL);
833834
spin_unlock_irqrestore(&iwdev->rf->cqtable_lock, flags);
834835
complete(&iwcq->free_cq);
835836
}

drivers/infiniband/hw/irdma/verbs.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2669,9 +2669,12 @@ static int irdma_create_cq(struct ib_cq *ibcq,
26692669
goto cq_destroy;
26702670
}
26712671
}
2672-
rf->cq_table[cq_num] = iwcq;
2672+
26732673
init_completion(&iwcq->free_cq);
26742674

2675+
/* Populate table entry after CQ is fully created. */
2676+
smp_store_release(&rf->cq_table[cq_num], iwcq);
2677+
26752678
return 0;
26762679
cq_destroy:
26772680
irdma_cq_wq_destroy(rf, cq);

0 commit comments

Comments
 (0)