Skip to content

Commit fe4dd42

Browse files
dhharalajgunthorpe
authored andcommitted
IB/hfi1: Correctly process FECN and BECN in packets
A CA is supposed to ignore FECN bits in multicast, ACK, and CNP packets. This patch corrects the behavior of the HFI1 driver in this regard by ignoring FECNs in those packet types. While fixing the above behavior, fix the extraction of the FECN and BECN bits from the packet headers for both 9B and 16B packets. Furthermore, this patch corrects the driver's response to a FECN in RDMA READ RESPONSE packets. Instead of sending an "empty" ACK, the driver now sends a CNP packet. While editing that code path, add the missing trace for CNP packets. Fixes: 88733e3 ("IB/hfi1: Add 16B UD support") Fixes: f59fb9e ("IB/hfi1: Fix handling of FECN marked multicast packet") Reviewed-by: Kaike Wan <[email protected]> Reviewed-by: Mike Marciniszyn <[email protected]> Reviewed-by: Dennis Dalessandro <[email protected]> Signed-off-by: Mitko Haralanov <[email protected]> Signed-off-by: Dennis Dalessandro <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent c1a797c commit fe4dd42

File tree

5 files changed

+104
-66
lines changed

5 files changed

+104
-66
lines changed

drivers/infiniband/hw/hfi1/driver.c

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -430,40 +430,60 @@ static const hfi1_handle_cnp hfi1_handle_cnp_tbl[2] = {
430430
[HFI1_PKT_TYPE_16B] = &return_cnp_16B
431431
};
432432

433-
void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt,
434-
bool do_cnp)
433+
/**
434+
* hfi1_process_ecn_slowpath - Process FECN or BECN bits
435+
* @qp: The packet's destination QP
436+
* @pkt: The packet itself.
437+
* @prescan: Is the caller the RXQ prescan
438+
*
439+
* Process the packet's FECN or BECN bits. By now, the packet
440+
* has already been evaluated whether processing of those bit should
441+
* be done.
442+
* The significance of the @prescan argument is that if the caller
443+
* is the RXQ prescan, a CNP will be send out instead of waiting for the
444+
* normal packet processing to send an ACK with BECN set (or a CNP).
445+
*/
446+
bool hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt,
447+
bool prescan)
435448
{
436449
struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
437450
struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
438451
struct ib_other_headers *ohdr = pkt->ohdr;
439452
struct ib_grh *grh = pkt->grh;
440-
u32 rqpn = 0, bth1;
453+
u32 rqpn = 0;
441454
u16 pkey;
442455
u32 rlid, slid, dlid = 0;
443-
u8 hdr_type, sc, svc_type;
444-
bool is_mcast = false;
456+
u8 hdr_type, sc, svc_type, opcode;
457+
bool is_mcast = false, ignore_fecn = false, do_cnp = false,
458+
fecn, becn;
445459

446460
/* can be called from prescan */
447461
if (pkt->etype == RHF_RCV_TYPE_BYPASS) {
448-
is_mcast = hfi1_is_16B_mcast(dlid);
449462
pkey = hfi1_16B_get_pkey(pkt->hdr);
450463
sc = hfi1_16B_get_sc(pkt->hdr);
451464
dlid = hfi1_16B_get_dlid(pkt->hdr);
452465
slid = hfi1_16B_get_slid(pkt->hdr);
466+
is_mcast = hfi1_is_16B_mcast(dlid);
467+
opcode = ib_bth_get_opcode(ohdr);
453468
hdr_type = HFI1_PKT_TYPE_16B;
469+
fecn = hfi1_16B_get_fecn(pkt->hdr);
470+
becn = hfi1_16B_get_becn(pkt->hdr);
454471
} else {
455-
is_mcast = (dlid > be16_to_cpu(IB_MULTICAST_LID_BASE)) &&
456-
(dlid != be16_to_cpu(IB_LID_PERMISSIVE));
457472
pkey = ib_bth_get_pkey(ohdr);
458473
sc = hfi1_9B_get_sc5(pkt->hdr, pkt->rhf);
459-
dlid = ib_get_dlid(pkt->hdr);
474+
dlid = qp->ibqp.qp_type != IB_QPT_UD ? ib_get_dlid(pkt->hdr) :
475+
ppd->lid;
460476
slid = ib_get_slid(pkt->hdr);
477+
is_mcast = (dlid > be16_to_cpu(IB_MULTICAST_LID_BASE)) &&
478+
(dlid != be16_to_cpu(IB_LID_PERMISSIVE));
479+
opcode = ib_bth_get_opcode(ohdr);
461480
hdr_type = HFI1_PKT_TYPE_9B;
481+
fecn = ib_bth_get_fecn(ohdr);
482+
becn = ib_bth_get_becn(ohdr);
462483
}
463484

464485
switch (qp->ibqp.qp_type) {
465486
case IB_QPT_UD:
466-
dlid = ppd->lid;
467487
rlid = slid;
468488
rqpn = ib_get_sqpn(pkt->ohdr);
469489
svc_type = IB_CC_SVCTYPE_UD;
@@ -485,22 +505,31 @@ void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt,
485505
svc_type = IB_CC_SVCTYPE_RC;
486506
break;
487507
default:
488-
return;
508+
return false;
489509
}
490510

491-
bth1 = be32_to_cpu(ohdr->bth[1]);
511+
ignore_fecn = is_mcast || (opcode == IB_OPCODE_CNP) ||
512+
(opcode == IB_OPCODE_RC_ACKNOWLEDGE);
513+
/*
514+
* ACKNOWLEDGE packets do not get a CNP but this will be
515+
* guarded by ignore_fecn above.
516+
*/
517+
do_cnp = prescan ||
518+
(opcode >= IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST &&
519+
opcode <= IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE);
520+
492521
/* Call appropriate CNP handler */
493-
if (do_cnp && (bth1 & IB_FECN_SMASK))
522+
if (!ignore_fecn && do_cnp && fecn)
494523
hfi1_handle_cnp_tbl[hdr_type](ibp, qp, rqpn, pkey,
495524
dlid, rlid, sc, grh);
496525

497-
if (!is_mcast && (bth1 & IB_BECN_SMASK)) {
498-
u32 lqpn = bth1 & RVT_QPN_MASK;
526+
if (becn) {
527+
u32 lqpn = be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK;
499528
u8 sl = ibp->sc_to_sl[sc];
500529

501530
process_becn(ppd, sl, rlid, lqpn, rqpn, svc_type);
502531
}
503-
532+
return !ignore_fecn && fecn;
504533
}
505534

506535
struct ps_mdata {
@@ -599,7 +628,6 @@ static void __prescan_rxq(struct hfi1_packet *packet)
599628
struct rvt_dev_info *rdi = &rcd->dd->verbs_dev.rdi;
600629
u64 rhf = rhf_to_cpu(rhf_addr);
601630
u32 etype = rhf_rcv_type(rhf), qpn, bth1;
602-
int is_ecn = 0;
603631
u8 lnh;
604632

605633
if (ps_done(&mdata, rhf, rcd))
@@ -625,12 +653,10 @@ static void __prescan_rxq(struct hfi1_packet *packet)
625653
goto next; /* just in case */
626654
}
627655

628-
bth1 = be32_to_cpu(packet->ohdr->bth[1]);
629-
is_ecn = !!(bth1 & (IB_FECN_SMASK | IB_BECN_SMASK));
630-
631-
if (!is_ecn)
656+
if (!hfi1_may_ecn(packet))
632657
goto next;
633658

659+
bth1 = be32_to_cpu(packet->ohdr->bth[1]);
634660
qpn = bth1 & RVT_QPN_MASK;
635661
rcu_read_lock();
636662
qp = rvt_lookup_qpn(rdi, &ibp->rvp, qpn);
@@ -640,7 +666,7 @@ static void __prescan_rxq(struct hfi1_packet *packet)
640666
goto next;
641667
}
642668

643-
process_ecn(qp, packet, true);
669+
hfi1_process_ecn_slowpath(qp, packet, true);
644670
rcu_read_unlock();
645671

646672
/* turn off BECN, FECN */

drivers/infiniband/hw/hfi1/hfi.h

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1802,13 +1802,20 @@ static inline struct hfi1_ibport *rcd_to_iport(struct hfi1_ctxtdata *rcd)
18021802
return &rcd->ppd->ibport_data;
18031803
}
18041804

1805-
void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt,
1806-
bool do_cnp);
1807-
static inline bool process_ecn(struct rvt_qp *qp, struct hfi1_packet *pkt,
1808-
bool do_cnp)
1805+
/**
1806+
* hfi1_may_ecn - Check whether FECN or BECN processing should be done
1807+
* @pkt: the packet to be evaluated
1808+
*
1809+
* Check whether the FECN or BECN bits in the packet's header are
1810+
* enabled, depending on packet type.
1811+
*
1812+
* This function only checks for FECN and BECN bits. Additional checks
1813+
* are done in the slowpath (hfi1_process_ecn_slowpath()) in order to
1814+
* ensure correct handling.
1815+
*/
1816+
static inline bool hfi1_may_ecn(struct hfi1_packet *pkt)
18091817
{
1810-
bool becn;
1811-
bool fecn;
1818+
bool fecn, becn;
18121819

18131820
if (pkt->etype == RHF_RCV_TYPE_BYPASS) {
18141821
fecn = hfi1_16B_get_fecn(pkt->hdr);
@@ -1817,10 +1824,18 @@ static inline bool process_ecn(struct rvt_qp *qp, struct hfi1_packet *pkt,
18171824
fecn = ib_bth_get_fecn(pkt->ohdr);
18181825
becn = ib_bth_get_becn(pkt->ohdr);
18191826
}
1820-
if (unlikely(fecn || becn)) {
1821-
hfi1_process_ecn_slowpath(qp, pkt, do_cnp);
1822-
return fecn;
1823-
}
1827+
return fecn || becn;
1828+
}
1829+
1830+
bool hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt,
1831+
bool prescan);
1832+
static inline bool process_ecn(struct rvt_qp *qp, struct hfi1_packet *pkt)
1833+
{
1834+
bool do_work;
1835+
1836+
do_work = hfi1_may_ecn(pkt);
1837+
if (unlikely(do_work))
1838+
return hfi1_process_ecn_slowpath(qp, pkt, false);
18241839
return false;
18251840
}
18261841

drivers/infiniband/hw/hfi1/rc.c

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,8 +2049,7 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
20492049
struct ib_reth *reth;
20502050
unsigned long flags;
20512051
int ret;
2052-
bool is_fecn = false;
2053-
bool copy_last = false;
2052+
bool copy_last = false, fecn;
20542053
u32 rkey;
20552054
u8 extra_bytes = pad + packet->extra_byte + (SIZE_OF_CRC << 2);
20562055

@@ -2059,7 +2058,7 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
20592058
if (hfi1_ruc_check_hdr(ibp, packet))
20602059
return;
20612060

2062-
is_fecn = process_ecn(qp, packet, false);
2061+
fecn = process_ecn(qp, packet);
20632062

20642063
/*
20652064
* Process responses (ACKs) before anything else. Note that the
@@ -2070,8 +2069,6 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
20702069
if (opcode >= OP(RDMA_READ_RESPONSE_FIRST) &&
20712070
opcode <= OP(ATOMIC_ACKNOWLEDGE)) {
20722071
rc_rcv_resp(packet);
2073-
if (is_fecn)
2074-
goto send_ack;
20752072
return;
20762073
}
20772074

@@ -2347,11 +2344,11 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
23472344

23482345
/* Schedule the send engine. */
23492346
qp->s_flags |= RVT_S_RESP_PENDING;
2347+
if (fecn)
2348+
qp->s_flags |= RVT_S_ECN;
23502349
hfi1_schedule_send(qp);
23512350

23522351
spin_unlock_irqrestore(&qp->s_lock, flags);
2353-
if (is_fecn)
2354-
goto send_ack;
23552352
return;
23562353
}
23572354

@@ -2413,11 +2410,11 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
24132410

24142411
/* Schedule the send engine. */
24152412
qp->s_flags |= RVT_S_RESP_PENDING;
2413+
if (fecn)
2414+
qp->s_flags |= RVT_S_ECN;
24162415
hfi1_schedule_send(qp);
24172416

24182417
spin_unlock_irqrestore(&qp->s_lock, flags);
2419-
if (is_fecn)
2420-
goto send_ack;
24212418
return;
24222419
}
24232420

@@ -2430,16 +2427,9 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
24302427
qp->r_ack_psn = psn;
24312428
qp->r_nak_state = 0;
24322429
/* Send an ACK if requested or required. */
2433-
if (psn & IB_BTH_REQ_ACK) {
2434-
if (packet->numpkt == 0) {
2435-
rc_cancel_ack(qp);
2436-
goto send_ack;
2437-
}
2438-
if (qp->r_adefered >= HFI1_PSN_CREDIT) {
2439-
rc_cancel_ack(qp);
2440-
goto send_ack;
2441-
}
2442-
if (unlikely(is_fecn)) {
2430+
if (psn & IB_BTH_REQ_ACK || fecn) {
2431+
if (packet->numpkt == 0 || fecn ||
2432+
qp->r_adefered >= HFI1_PSN_CREDIT) {
24432433
rc_cancel_ack(qp);
24442434
goto send_ack;
24452435
}
@@ -2480,7 +2470,7 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
24802470
qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR;
24812471
qp->r_ack_psn = qp->r_psn;
24822472
send_ack:
2483-
hfi1_send_rc_ack(packet, is_fecn);
2473+
hfi1_send_rc_ack(packet, fecn);
24842474
}
24852475

24862476
void hfi1_rc_hdrerr(

drivers/infiniband/hw/hfi1/uc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ void hfi1_uc_rcv(struct hfi1_packet *packet)
321321
if (hfi1_ruc_check_hdr(ibp, packet))
322322
return;
323323

324-
process_ecn(qp, packet, true);
324+
process_ecn(qp, packet);
325325

326326
psn = ib_bth_get_psn(ohdr);
327327
/* Compare the PSN verses the expected PSN. */

0 commit comments

Comments
 (0)