Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5786adf3 authored by Don Hiatt's avatar Don Hiatt Committed by Doug Ledford
Browse files

IB/hfi1: Add support to process 16B header errors



Enhance hdr_rcverr() to also handle errors during
16B bypass packet receive.

Reviewed-by: default avatarDennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: default avatarDon Hiatt <don.hiatt@intel.com>
Signed-off-by: default avatarDennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 30e07416
Loading
Loading
Loading
Loading
+47 −11
Original line number Original line Diff line number Diff line
@@ -269,8 +269,7 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd,
{
{
	struct ib_header *rhdr = packet->hdr;
	struct ib_header *rhdr = packet->hdr;
	u32 rte = rhf_rcv_type_err(packet->rhf);
	u32 rte = rhf_rcv_type_err(packet->rhf);
	u8 lnh = ib_get_lnh(rhdr);
	u32 mlid_base;
	bool has_grh = false;
	struct hfi1_ibport *ibp = rcd_to_iport(rcd);
	struct hfi1_ibport *ibp = rcd_to_iport(rcd);
	struct hfi1_devdata *dd = ppd->dd;
	struct hfi1_devdata *dd = ppd->dd;
	struct rvt_dev_info *rdi = &dd->verbs_dev.rdi;
	struct rvt_dev_info *rdi = &dd->verbs_dev.rdi;
@@ -278,29 +277,34 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd,
	if (packet->rhf & (RHF_VCRC_ERR | RHF_ICRC_ERR))
	if (packet->rhf & (RHF_VCRC_ERR | RHF_ICRC_ERR))
		return;
		return;


	if (packet->etype == RHF_RCV_TYPE_BYPASS) {
		goto drop;
	} else {
		u8 lnh = ib_get_lnh(rhdr);

		mlid_base = be16_to_cpu(IB_MULTICAST_LID_BASE);
		if (lnh == HFI1_LRH_BTH) {
		if (lnh == HFI1_LRH_BTH) {
			packet->ohdr = &rhdr->u.oth;
			packet->ohdr = &rhdr->u.oth;
		} else if (lnh == HFI1_LRH_GRH) {
		} else if (lnh == HFI1_LRH_GRH) {
		has_grh = true;
			packet->ohdr = &rhdr->u.l.oth;
			packet->ohdr = &rhdr->u.l.oth;
			packet->grh = &rhdr->u.l.grh;
			packet->grh = &rhdr->u.l.grh;
		} else {
		} else {
			goto drop;
			goto drop;
		}
		}
	}


	if (packet->rhf & RHF_TID_ERR) {
	if (packet->rhf & RHF_TID_ERR) {
		/* For TIDERR and RC QPs preemptively schedule a NAK */
		/* For TIDERR and RC QPs preemptively schedule a NAK */
		u32 tlen = rhf_pkt_len(packet->rhf); /* in bytes */
		u32 tlen = rhf_pkt_len(packet->rhf); /* in bytes */
		u32 dlid = ib_get_dlid(rhdr);
		u32 dlid = ib_get_dlid(rhdr);
		u32 qp_num;
		u32 qp_num;
		u32 mlid_base = be16_to_cpu(IB_MULTICAST_LID_BASE);


		/* Sanity check packet */
		/* Sanity check packet */
		if (tlen < 24)
		if (tlen < 24)
			goto drop;
			goto drop;


		/* Check for GRH */
		/* Check for GRH */
		if (has_grh) {
		if (packet->grh) {
			u32 vtf;
			u32 vtf;
			struct ib_grh *grh = packet->grh;
			struct ib_grh *grh = packet->grh;


@@ -1370,6 +1374,35 @@ static inline void hfi1_setup_ib_header(struct hfi1_packet *packet)
	packet->hlen = (u8 *)packet->rhf_addr - (u8 *)packet->hdr;
	packet->hlen = (u8 *)packet->rhf_addr - (u8 *)packet->hdr;
}
}


static int hfi1_bypass_ingress_pkt_check(struct hfi1_packet *packet)
{
	struct hfi1_pportdata *ppd = packet->rcd->ppd;

	/* slid and dlid cannot be 0 */
	if ((!packet->slid) || (!packet->dlid))
		return -EINVAL;

	/* Compare port lid with incoming packet dlid */
	if ((!(hfi1_is_16B_mcast(packet->dlid))) &&
	    (packet->dlid !=
		opa_get_lid(be32_to_cpu(OPA_LID_PERMISSIVE), 16B))) {
		if (packet->dlid != ppd->lid)
			return -EINVAL;
	}

	/* No multicast packets with SC15 */
	if ((hfi1_is_16B_mcast(packet->dlid)) && (packet->sc == 0xF))
		return -EINVAL;

	/* Packets with permissive DLID always on SC15 */
	if ((packet->dlid == opa_get_lid(be32_to_cpu(OPA_LID_PERMISSIVE),
					 16B)) &&
	    (packet->sc != 0xF))
		return -EINVAL;

	return 0;
}

static int hfi1_setup_9B_packet(struct hfi1_packet *packet)
static int hfi1_setup_9B_packet(struct hfi1_packet *packet)
{
{
	struct hfi1_ibport *ibp = rcd_to_iport(packet->rcd);
	struct hfi1_ibport *ibp = rcd_to_iport(packet->rcd);
@@ -1479,6 +1512,9 @@ static int hfi1_setup_bypass_packet(struct hfi1_packet *packet)
	packet->fecn = hfi1_16B_get_fecn(packet->hdr);
	packet->fecn = hfi1_16B_get_fecn(packet->hdr);
	packet->becn = hfi1_16B_get_becn(packet->hdr);
	packet->becn = hfi1_16B_get_becn(packet->hdr);


	if (hfi1_bypass_ingress_pkt_check(packet))
		goto drop;

	return 0;
	return 0;
drop:
drop:
	hfi1_cdbg(PKT, "%s: packet dropped\n", __func__);
	hfi1_cdbg(PKT, "%s: packet dropped\n", __func__);
+11 −2
Original line number Original line Diff line number Diff line
@@ -372,6 +372,10 @@ struct hfi1_packet {
#define OPA_16B_FECN_SHIFT      28
#define OPA_16B_FECN_SHIFT      28
#define OPA_16B_L2_MASK		0x60000000ull
#define OPA_16B_L2_MASK		0x60000000ull
#define OPA_16B_L2_SHIFT	29
#define OPA_16B_L2_SHIFT	29
#define OPA_16B_PKEY_MASK	0xFFFF0000ull
#define OPA_16B_PKEY_SHIFT	16
#define OPA_16B_LEN_MASK	0x7FF00000ull
#define OPA_16B_LEN_SHIFT	20


/*
/*
 * OPA 16B L2/L4 Encodings
 * OPA 16B L2/L4 Encodings
@@ -420,6 +424,11 @@ static inline u8 hfi1_16B_get_l2(struct hfi1_16b_header *hdr)
	return (u8)((hdr->lrh[1] & OPA_16B_L2_MASK) >> OPA_16B_L2_SHIFT);
	return (u8)((hdr->lrh[1] & OPA_16B_L2_MASK) >> OPA_16B_L2_SHIFT);
}
}


static inline u16 hfi1_16B_get_pkey(struct hfi1_16b_header *hdr)
{
	return (u16)((hdr->lrh[2] & OPA_16B_PKEY_MASK) >> OPA_16B_PKEY_SHIFT);
}

/*
/*
 * BTH
 * BTH
 */
 */
@@ -1597,9 +1606,9 @@ static void ingress_pkey_table_fail(struct hfi1_pportdata *ppd, u16 pkey,
 * by HW and rcv_pkey_check function should be called instead.
 * by HW and rcv_pkey_check function should be called instead.
 */
 */
static inline int ingress_pkey_check(struct hfi1_pportdata *ppd, u16 pkey,
static inline int ingress_pkey_check(struct hfi1_pportdata *ppd, u16 pkey,
				     u8 sc5, u8 idx, u16 slid)
				     u8 sc5, u8 idx, u32 slid, bool force)
{
{
	if (!(ppd->part_enforce & HFI1_PART_ENFORCE_IN))
	if (!(force) && !(ppd->part_enforce & HFI1_PART_ENFORCE_IN))
		return 0;
		return 0;


	/* If SC15, pkey[0:14] must be 0x7fff */
	/* If SC15, pkey[0:14] must be 0x7fff */
+20 −11
Original line number Original line Diff line number Diff line
@@ -227,15 +227,23 @@ int hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_packet *packet)
	u32 sl = packet->sl;
	u32 sl = packet->sl;
	int migrated;
	int migrated;
	u32 bth0, bth1;
	u32 bth0, bth1;
	u16 pkey;


	bth0 = be32_to_cpu(packet->ohdr->bth[0]);
	bth0 = be32_to_cpu(packet->ohdr->bth[0]);
	bth1 = be32_to_cpu(packet->ohdr->bth[1]);
	bth1 = be32_to_cpu(packet->ohdr->bth[1]);
	if (packet->etype == RHF_RCV_TYPE_BYPASS) {
		pkey = hfi1_16B_get_pkey(packet->hdr);
		migrated = bth1 & OPA_BTH_MIG_REQ;
	} else {
		pkey = ib_bth_get_pkey(packet->ohdr);
		migrated = bth0 & IB_BTH_MIG_REQ;
		migrated = bth0 & IB_BTH_MIG_REQ;
	}


	if (qp->s_mig_state == IB_MIG_ARMED && migrated) {
	if (qp->s_mig_state == IB_MIG_ARMED && migrated) {
		if (!packet->grh) {
		if (!packet->grh) {
			if (rdma_ah_get_ah_flags(&qp->alt_ah_attr) &
			if ((rdma_ah_get_ah_flags(&qp->alt_ah_attr) &
			    IB_AH_GRH)
			     IB_AH_GRH) &&
			    (packet->etype != RHF_RCV_TYPE_BYPASS))
				return 1;
				return 1;
		} else {
		} else {
			const struct ib_global_route *grh;
			const struct ib_global_route *grh;
@@ -254,10 +262,10 @@ int hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_packet *packet)
				grh->dgid.global.interface_id))
				grh->dgid.global.interface_id))
				return 1;
				return 1;
		}
		}
		if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), (u16)bth0,
		if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), pkey,
					    sc5, slid))) {
					    sc5, slid))) {
			hfi1_bad_pkey(ibp, (u16)bth0, sl,
			hfi1_bad_pkey(ibp, pkey, sl, 0, qp->ibqp.qp_num,
				      0, qp->ibqp.qp_num, slid, dlid);
				      slid, dlid);
			return 1;
			return 1;
		}
		}
		/* Validate the SLID. See Ch. 9.6.1.5 and 17.2.8 */
		/* Validate the SLID. See Ch. 9.6.1.5 and 17.2.8 */
@@ -270,8 +278,9 @@ int hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_packet *packet)
		spin_unlock_irqrestore(&qp->s_lock, flags);
		spin_unlock_irqrestore(&qp->s_lock, flags);
	} else {
	} else {
		if (!packet->grh) {
		if (!packet->grh) {
			if (rdma_ah_get_ah_flags(&qp->remote_ah_attr) &
			if ((rdma_ah_get_ah_flags(&qp->remote_ah_attr) &
						 IB_AH_GRH)
			     IB_AH_GRH) &&
			    (packet->etype != RHF_RCV_TYPE_BYPASS))
				return 1;
				return 1;
		} else {
		} else {
			const struct ib_global_route *grh;
			const struct ib_global_route *grh;
@@ -290,10 +299,10 @@ int hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_packet *packet)
			     grh->dgid.global.interface_id))
			     grh->dgid.global.interface_id))
				return 1;
				return 1;
		}
		}
		if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), (u16)bth0,
		if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), pkey,
					    sc5, slid))) {
					    sc5, slid))) {
			hfi1_bad_pkey(ibp, (u16)bth0, sl,
			hfi1_bad_pkey(ibp, pkey, sl, 0, qp->ibqp.qp_num,
				      0, qp->ibqp.qp_num, slid, dlid);
				      slid, dlid);
			return 1;
			return 1;
		}
		}
		/* Validate the SLID. See Ch. 9.6.1.5 */
		/* Validate the SLID. See Ch. 9.6.1.5 */
+2 −1
Original line number Original line Diff line number Diff line
@@ -109,7 +109,8 @@ static void ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
		slid = ppd->lid | (rdma_ah_get_path_bits(ah_attr) &
		slid = ppd->lid | (rdma_ah_get_path_bits(ah_attr) &
				   ((1 << ppd->lmc) - 1));
				   ((1 << ppd->lmc) - 1));
		if (unlikely(ingress_pkey_check(ppd, pkey, sc5,
		if (unlikely(ingress_pkey_check(ppd, pkey, sc5,
						qp->s_pkey_index, slid))) {
						qp->s_pkey_index,
						slid, false))) {
			hfi1_bad_pkey(ibp, pkey,
			hfi1_bad_pkey(ibp, pkey,
				      rdma_ah_get_sl(ah_attr),
				      rdma_ah_get_sl(ah_attr),
				      sqp->ibqp.qp_num, qp->ibqp.qp_num,
				      sqp->ibqp.qp_num, qp->ibqp.qp_num,
+31 −8
Original line number Original line Diff line number Diff line
@@ -568,6 +568,24 @@ static u64 hfi1_fault_tx(struct rvt_qp *qp, u8 opcode, u64 pbc)
	return pbc;
	return pbc;
}
}


static int hfi1_do_pkey_check(struct hfi1_packet *packet)
{
	struct hfi1_ctxtdata *rcd = packet->rcd;
	struct hfi1_pportdata *ppd = rcd->ppd;
	struct hfi1_16b_header *hdr = packet->hdr;
	u16 pkey;

	/* Pkey check needed only for bypass packets */
	if (packet->etype != RHF_RCV_TYPE_BYPASS)
		return 0;

	/* Perform pkey check */
	pkey = hfi1_16B_get_pkey(hdr);
	return ingress_pkey_check(ppd, pkey, packet->sc,
				  packet->qp->s_pkey_index,
				  packet->slid, true);
}

static inline void hfi1_handle_packet(struct hfi1_packet *packet,
static inline void hfi1_handle_packet(struct hfi1_packet *packet,
				      bool is_mcast)
				      bool is_mcast)
{
{
@@ -594,6 +612,8 @@ static inline void hfi1_handle_packet(struct hfi1_packet *packet,
			goto drop;
			goto drop;
		list_for_each_entry_rcu(p, &mcast->qp_list, list) {
		list_for_each_entry_rcu(p, &mcast->qp_list, list) {
			packet->qp = p->qp;
			packet->qp = p->qp;
			if (hfi1_do_pkey_check(packet))
				goto drop;
			spin_lock_irqsave(&packet->qp->r_lock, flags);
			spin_lock_irqsave(&packet->qp->r_lock, flags);
			packet_handler = qp_ok(packet);
			packet_handler = qp_ok(packet);
			if (likely(packet_handler))
			if (likely(packet_handler))
@@ -613,15 +633,16 @@ static inline void hfi1_handle_packet(struct hfi1_packet *packet,
		qp_num = ib_bth_get_qpn(packet->ohdr);
		qp_num = ib_bth_get_qpn(packet->ohdr);
		rcu_read_lock();
		rcu_read_lock();
		packet->qp = rvt_lookup_qpn(rdi, &ibp->rvp, qp_num);
		packet->qp = rvt_lookup_qpn(rdi, &ibp->rvp, qp_num);
		if (!packet->qp) {
		if (!packet->qp)
			rcu_read_unlock();
			goto unlock_drop;
			goto drop;

		}
		if (hfi1_do_pkey_check(packet))
			goto unlock_drop;

		if (unlikely(hfi1_dbg_fault_opcode(packet->qp, packet->opcode,
		if (unlikely(hfi1_dbg_fault_opcode(packet->qp, packet->opcode,
						   true))) {
						   true)))
			rcu_read_unlock();
			goto unlock_drop;
			goto drop;

		}
		spin_lock_irqsave(&packet->qp->r_lock, flags);
		spin_lock_irqsave(&packet->qp->r_lock, flags);
		packet_handler = qp_ok(packet);
		packet_handler = qp_ok(packet);
		if (likely(packet_handler))
		if (likely(packet_handler))
@@ -632,6 +653,8 @@ static inline void hfi1_handle_packet(struct hfi1_packet *packet,
		rcu_read_unlock();
		rcu_read_unlock();
	}
	}
	return;
	return;
unlock_drop:
	rcu_read_unlock();
drop:
drop:
	ibp->rvp.n_pkt_drops++;
	ibp->rvp.n_pkt_drops++;
}
}
Loading