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

Commit 72c07e2b authored by Don Hiatt's avatar Don Hiatt Committed by Doug Ledford
Browse files

IB/hfi1: Add support to receive 16B bypass packets



We introduce a struct hfi1_16b_header to support 16B headers.
16B bypass packets are received by the driver and processed
similar to 9B packets. Add basic support to handle 16B packets.

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 13c19222
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -14468,6 +14468,7 @@ void hfi1_deinit_vnic_rsm(struct hfi1_devdata *dd)
static void init_rxe(struct hfi1_devdata *dd)
static void init_rxe(struct hfi1_devdata *dd)
{
{
	struct rsm_map_table *rmt;
	struct rsm_map_table *rmt;
	u64 val;


	/* enable all receive errors */
	/* enable all receive errors */
	write_csr(dd, RCV_ERR_MASK, ~0ull);
	write_csr(dd, RCV_ERR_MASK, ~0ull);
@@ -14492,6 +14493,11 @@ static void init_rxe(struct hfi1_devdata *dd)
	 * (64 bytes).  Max_Payload_Size is possibly modified upward in
	 * (64 bytes).  Max_Payload_Size is possibly modified upward in
	 * tune_pcie_caps() which is called after this routine.
	 * tune_pcie_caps() which is called after this routine.
	 */
	 */

	/* Have 16 bytes (4DW) of bypass header available in header queue */
	val = read_csr(dd, RCV_BYPASS);
	val |= (4ull << 16);
	write_csr(dd, RCV_BYPASS, val);
}
}


static void init_other(struct hfi1_devdata *dd)
static void init_other(struct hfi1_devdata *dd)
+1 −0
Original line number Original line Diff line number Diff line
@@ -327,6 +327,7 @@ struct diag_pkt {
/* misc. */
/* misc. */
#define SC15_PACKET 0xF
#define SC15_PACKET 0xF
#define SIZE_OF_CRC 1
#define SIZE_OF_CRC 1
#define SIZE_OF_LT 1


#define LIM_MGMT_P_KEY       0x7FFF
#define LIM_MGMT_P_KEY       0x7FFF
#define FULL_MGMT_P_KEY      0xFFFF
#define FULL_MGMT_P_KEY      0xFFFF
+112 −15
Original line number Original line Diff line number Diff line
@@ -237,6 +237,13 @@ static inline struct ib_header *hfi1_get_msgheader(struct hfi1_devdata *dd,
	return (struct ib_header *)hfi1_get_header(dd, rhf_addr);
	return (struct ib_header *)hfi1_get_header(dd, rhf_addr);
}
}


static inline struct hfi1_16b_header
		*hfi1_get_16B_header(struct hfi1_devdata *dd,
				     __le32 *rhf_addr)
{
	return (struct hfi1_16b_header *)hfi1_get_header(dd, rhf_addr);
}

/*
/*
 * Validate and encode the a given RcvArray Buffer size.
 * Validate and encode the a given RcvArray Buffer size.
 * The function will check whether the given size falls within
 * The function will check whether the given size falls within
@@ -925,6 +932,11 @@ static inline int set_armed_to_active(struct hfi1_ctxtdata *rcd,
		struct ib_header *hdr = hfi1_get_msgheader(packet->rcd->dd,
		struct ib_header *hdr = hfi1_get_msgheader(packet->rcd->dd,
							   packet->rhf_addr);
							   packet->rhf_addr);
		sc = hfi1_9B_get_sc5(hdr, packet->rhf);
		sc = hfi1_9B_get_sc5(hdr, packet->rhf);
	} else if (etype == RHF_RCV_TYPE_BYPASS) {
		struct hfi1_16b_header *hdr = hfi1_get_16B_header(
						packet->rcd->dd,
						packet->rhf_addr);
		sc = hfi1_16B_get_sc(hdr);
	}
	}
	if (sc != SC15_PACKET) {
	if (sc != SC15_PACKET) {
		int hwstate = driver_lstate(rcd->ppd);
		int hwstate = driver_lstate(rcd->ppd);
@@ -1386,9 +1398,14 @@ static int hfi1_setup_9B_packet(struct hfi1_packet *packet)
	}
	}


	/* Query commonly used fields from packet header */
	/* Query commonly used fields from packet header */
	packet->payload = packet->ebuf;
	packet->opcode = ib_bth_get_opcode(packet->ohdr);
	packet->opcode = ib_bth_get_opcode(packet->ohdr);
	packet->slid = ib_get_slid(hdr);
	packet->slid = ib_get_slid(hdr);
	packet->dlid = ib_get_dlid(hdr);
	packet->dlid = ib_get_dlid(hdr);
	if (unlikely((packet->dlid >= be16_to_cpu(IB_MULTICAST_LID_BASE)) &&
		     (packet->dlid != be16_to_cpu(IB_LID_PERMISSIVE))))
		packet->dlid += opa_get_mcast_base(OPA_MCAST_NR) -
				be16_to_cpu(IB_MULTICAST_LID_BASE);
	packet->sl = ib_get_sl(hdr);
	packet->sl = ib_get_sl(hdr);
	packet->sc = hfi1_9B_get_sc5(hdr, packet->rhf);
	packet->sc = hfi1_9B_get_sc5(hdr, packet->rhf);
	packet->pad = ib_bth_get_pad(packet->ohdr);
	packet->pad = ib_bth_get_pad(packet->ohdr);
@@ -1402,6 +1419,73 @@ static int hfi1_setup_9B_packet(struct hfi1_packet *packet)
	return -EINVAL;
	return -EINVAL;
}
}


static int hfi1_setup_bypass_packet(struct hfi1_packet *packet)
{
	/*
	 * Bypass packets have a different header/payload split
	 * compared to an IB packet.
	 * Current split is set such that 16 bytes of the actual
	 * header is in the header buffer and the remining is in
	 * the eager buffer. We chose 16 since hfi1 driver only
	 * supports 16B bypass packets and we will be able to
	 * receive the entire LRH with such a split.
	 */

	struct hfi1_ctxtdata *rcd = packet->rcd;
	struct hfi1_pportdata *ppd = rcd->ppd;
	struct hfi1_ibport *ibp = &ppd->ibport_data;
	u8 l4;
	u8 grh_len;

	packet->hdr = (struct hfi1_16b_header *)
			hfi1_get_16B_header(packet->rcd->dd,
					    packet->rhf_addr);
	packet->hlen = (u8 *)packet->rhf_addr - (u8 *)packet->hdr;

	l4 = hfi1_16B_get_l4(packet->hdr);
	if (l4 == OPA_16B_L4_IB_LOCAL) {
		grh_len = 0;
		packet->ohdr = packet->ebuf;
		packet->grh = NULL;
	} else if (l4 == OPA_16B_L4_IB_GLOBAL) {
		u32 vtf;

		grh_len = sizeof(struct ib_grh);
		packet->ohdr = packet->ebuf + grh_len;
		packet->grh = packet->ebuf;
		if (packet->grh->next_hdr != IB_GRH_NEXT_HDR)
			goto drop;
		vtf = be32_to_cpu(packet->grh->version_tclass_flow);
		if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION)
			goto drop;
	} else {
		goto drop;
	}

	/* Query commonly used fields from packet header */
	packet->opcode = ib_bth_get_opcode(packet->ohdr);
	packet->hlen = hdr_len_by_opcode[packet->opcode] + 8 + grh_len;
	packet->payload = packet->ebuf + packet->hlen - (4 * sizeof(u32));
	packet->slid = hfi1_16B_get_slid(packet->hdr);
	packet->dlid = hfi1_16B_get_dlid(packet->hdr);
	if (unlikely(hfi1_is_16B_mcast(packet->dlid)))
		packet->dlid += opa_get_mcast_base(OPA_MCAST_NR) -
				opa_get_lid(opa_get_mcast_base(OPA_MCAST_NR),
					    16B);
	packet->sc = hfi1_16B_get_sc(packet->hdr);
	packet->sl = ibp->sc_to_sl[packet->sc];
	packet->pad = hfi1_16B_bth_get_pad(packet->ohdr);
	packet->extra_byte = SIZE_OF_LT;
	packet->fecn = hfi1_16B_get_fecn(packet->hdr);
	packet->becn = hfi1_16B_get_becn(packet->hdr);

	return 0;
drop:
	hfi1_cdbg(PKT, "%s: packet dropped\n", __func__);
	ibp->rvp.n_pkt_drops++;
	return -EINVAL;
}

void handle_eflags(struct hfi1_packet *packet)
void handle_eflags(struct hfi1_packet *packet)
{
{
	struct hfi1_ctxtdata *rcd = packet->rcd;
	struct hfi1_ctxtdata *rcd = packet->rcd;
@@ -1464,8 +1548,8 @@ static inline bool hfi1_is_vnic_packet(struct hfi1_packet *packet)
	if (packet->rcd->is_vnic)
	if (packet->rcd->is_vnic)
		return true;
		return true;


	if ((HFI1_GET_L2_TYPE(packet->ebuf) == OPA_VNIC_L2_TYPE) &&
	if ((hfi1_16B_get_l2(packet->ebuf) == OPA_16B_L2_TYPE) &&
	    (HFI1_GET_L4_TYPE(packet->ebuf) == OPA_VNIC_L4_ETHR))
	    (hfi1_16B_get_l4(packet->ebuf) == OPA_16B_L4_ETHR))
		return true;
		return true;


	return false;
	return false;
@@ -1475,26 +1559,39 @@ int process_receive_bypass(struct hfi1_packet *packet)
{
{
	struct hfi1_devdata *dd = packet->rcd->dd;
	struct hfi1_devdata *dd = packet->rcd->dd;


	if (hfi1_is_vnic_packet(packet)) {
		hfi1_vnic_bypass_rcv(packet);
		return RHF_RCV_CONTINUE;
	}

	if (hfi1_setup_bypass_packet(packet))
		return RHF_RCV_CONTINUE;

	if (unlikely(rhf_err_flags(packet->rhf))) {
	if (unlikely(rhf_err_flags(packet->rhf))) {
		handle_eflags(packet);
		handle_eflags(packet);
	} else if (hfi1_is_vnic_packet(packet)) {
		hfi1_vnic_bypass_rcv(packet);
		return RHF_RCV_CONTINUE;
		return RHF_RCV_CONTINUE;
	}
	}


	dd_dev_err(dd, "Unsupported bypass packet. Dropping\n");
	if (hfi1_16B_get_l2(packet->hdr) == 0x2) {
		hfi1_16B_rcv(packet);
	} else {
		dd_dev_err(dd,
			   "Bypass packets other than 16B are not supported in normal operation. Dropping\n");
		incr_cntr64(&dd->sw_rcv_bypass_packet_errors);
		incr_cntr64(&dd->sw_rcv_bypass_packet_errors);
	if (!(dd->err_info_rcvport.status_and_code & OPA_EI_STATUS_SMASK)) {
		if (!(dd->err_info_rcvport.status_and_code &
		      OPA_EI_STATUS_SMASK)) {
			u64 *flits = packet->ebuf;
			u64 *flits = packet->ebuf;


			if (flits && !(packet->rhf & RHF_LEN_ERR)) {
			if (flits && !(packet->rhf & RHF_LEN_ERR)) {
				dd->err_info_rcvport.packet_flit1 = flits[0];
				dd->err_info_rcvport.packet_flit1 = flits[0];
				dd->err_info_rcvport.packet_flit2 =
				dd->err_info_rcvport.packet_flit2 =
				packet->tlen > sizeof(flits[0]) ? flits[1] : 0;
					packet->tlen > sizeof(flits[0]) ?
					flits[1] : 0;
			}
			}
			dd->err_info_rcvport.status_and_code |=
			dd->err_info_rcvport.status_and_code |=
				(OPA_EI_STATUS_SMASK | BAD_L2_ERR);
				(OPA_EI_STATUS_SMASK | BAD_L2_ERR);
		}
		}
	}
	return RHF_RCV_CONTINUE;
	return RHF_RCV_CONTINUE;
}
}


+127 −4
Original line number Original line Diff line number Diff line
@@ -66,6 +66,7 @@
#include <linux/i2c.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/i2c-algo-bit.h>
#include <rdma/ib_hdrs.h>
#include <rdma/ib_hdrs.h>
#include <rdma/opa_addr.h>
#include <linux/rhashtable.h>
#include <linux/rhashtable.h>
#include <linux/netdevice.h>
#include <linux/netdevice.h>
#include <rdma/rdma_vt.h>
#include <rdma/rdma_vt.h>
@@ -325,6 +326,7 @@ struct hfi1_ctxtdata {
struct hfi1_packet {
struct hfi1_packet {
	void *ebuf;
	void *ebuf;
	void *hdr;
	void *hdr;
	void *payload;
	struct hfi1_ctxtdata *rcd;
	struct hfi1_ctxtdata *rcd;
	__le32 *rhf_addr;
	__le32 *rhf_addr;
	struct rvt_qp *qp;
	struct rvt_qp *qp;
@@ -351,6 +353,83 @@ struct hfi1_packet {
	bool fecn;
	bool fecn;
};
};


/*
 * OPA 16B Header
 */
#define OPA_16B_L4_MASK		0xFFull
#define OPA_16B_SC_MASK		0x1F00000ull
#define OPA_16B_SC_SHIFT	20
#define OPA_16B_LID_MASK	0xFFFFFull
#define OPA_16B_DLID_MASK	0xF000ull
#define OPA_16B_DLID_SHIFT	20
#define OPA_16B_DLID_HIGH_SHIFT	12
#define OPA_16B_SLID_MASK	0xF00ull
#define OPA_16B_SLID_SHIFT	20
#define OPA_16B_SLID_HIGH_SHIFT	8
#define OPA_16B_BECN_MASK       0x80000000ull
#define OPA_16B_BECN_SHIFT      31
#define OPA_16B_FECN_MASK       0x10000000ull
#define OPA_16B_FECN_SHIFT      28
#define OPA_16B_L2_MASK		0x60000000ull
#define OPA_16B_L2_SHIFT	29

/*
 * OPA 16B L2/L4 Encodings
 */
#define OPA_16B_L2_TYPE		0x02
#define OPA_16B_L4_IB_LOCAL	0x09
#define OPA_16B_L4_IB_GLOBAL	0x0A
#define OPA_16B_L4_ETHR		OPA_VNIC_L4_ETHR

static inline u8 hfi1_16B_get_l4(struct hfi1_16b_header *hdr)
{
	return (u8)(hdr->lrh[2] & OPA_16B_L4_MASK);
}

static inline u8 hfi1_16B_get_sc(struct hfi1_16b_header *hdr)
{
	return (u8)((hdr->lrh[1] & OPA_16B_SC_MASK) >> OPA_16B_SC_SHIFT);
}

static inline u32 hfi1_16B_get_dlid(struct hfi1_16b_header *hdr)
{
	return (u32)((hdr->lrh[1] & OPA_16B_LID_MASK) |
		     (((hdr->lrh[2] & OPA_16B_DLID_MASK) >>
		     OPA_16B_DLID_HIGH_SHIFT) << OPA_16B_DLID_SHIFT));
}

static inline u32 hfi1_16B_get_slid(struct hfi1_16b_header *hdr)
{
	return (u32)((hdr->lrh[0] & OPA_16B_LID_MASK) |
		     (((hdr->lrh[2] & OPA_16B_SLID_MASK) >>
		     OPA_16B_SLID_HIGH_SHIFT) << OPA_16B_SLID_SHIFT));
}

static inline u8 hfi1_16B_get_becn(struct hfi1_16b_header *hdr)
{
	return (u8)((hdr->lrh[0] & OPA_16B_BECN_MASK) >> OPA_16B_BECN_SHIFT);
}

static inline u8 hfi1_16B_get_fecn(struct hfi1_16b_header *hdr)
{
	return (u8)((hdr->lrh[1] & OPA_16B_FECN_MASK) >> OPA_16B_FECN_SHIFT);
}

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);
}

/*
 * BTH
 */
#define OPA_16B_BTH_PAD_MASK	7
static inline u8 hfi1_16B_bth_get_pad(struct ib_other_headers *ohdr)
{
	return (u8)((be32_to_cpu(ohdr->bth[0]) >> IB_BTH_PAD_SHIFT) &
		   OPA_16B_BTH_PAD_MASK);
}

struct rvt_sge_state;
struct rvt_sge_state;


/*
/*
@@ -2084,11 +2163,55 @@ int hfi1_tempsense_rd(struct hfi1_devdata *dd, struct hfi1_temp *temp);


/*
/*
 * hfi1_check_mcast- Check if the given lid is
 * hfi1_check_mcast- Check if the given lid is
 * in the IB multicast range.
 * in the OPA multicast range.
 *
 * The LID might either reside in ah.dlid or might be
 * in the GRH of the address handle as DGID if extended
 * addresses are in use.
 */
 */
static inline bool hfi1_check_mcast(u16 lid)
static inline bool hfi1_check_mcast(u32 lid)
{
	return ((lid >= opa_get_mcast_base(OPA_MCAST_NR)) &&
		(lid != be32_to_cpu(OPA_LID_PERMISSIVE)));
}

#define opa_get_lid(lid, format)	\
	__opa_get_lid(lid, OPA_PORT_PACKET_FORMAT_##format)

/* Convert a lid to a specific lid space */
static inline u32 __opa_get_lid(u32 lid, u8 format)
{
	bool is_mcast = hfi1_check_mcast(lid);

	switch (format) {
	case OPA_PORT_PACKET_FORMAT_8B:
	case OPA_PORT_PACKET_FORMAT_10B:
		if (is_mcast)
			return (lid - opa_get_mcast_base(OPA_MCAST_NR) +
				0xF0000);
		return lid & 0xFFFFF;
	case OPA_PORT_PACKET_FORMAT_16B:
		if (is_mcast)
			return (lid - opa_get_mcast_base(OPA_MCAST_NR) +
				0xF00000);
		return lid & 0xFFFFFF;
	case OPA_PORT_PACKET_FORMAT_9B:
		if (is_mcast)
			return (lid -
				opa_get_mcast_base(OPA_MCAST_NR) +
				be16_to_cpu(IB_MULTICAST_LID_BASE));
		else
			return lid & 0xFFFF;
	default:
		return lid;
	}
}

/* Return true if the given lid is the OPA 16B multicast range */
static inline bool hfi1_is_16B_mcast(u32 lid)
{
{
	return ((lid >= be16_to_cpu(IB_MULTICAST_LID_BASE)) &&
	return ((lid >=
		(lid != be16_to_cpu(IB_LID_PERMISSIVE)));
		opa_get_lid(opa_get_mcast_base(OPA_MCAST_NR), 16B)) &&
		(lid != opa_get_lid(be32_to_cpu(OPA_LID_PERMISSIVE), 16B)));
}
}
#endif                          /* _HFI1_KERNEL_H */
#endif                          /* _HFI1_KERNEL_H */
+1 −1
Original line number Original line Diff line number Diff line
@@ -1916,7 +1916,7 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn,
void hfi1_rc_rcv(struct hfi1_packet *packet)
void hfi1_rc_rcv(struct hfi1_packet *packet)
{
{
	struct hfi1_ctxtdata *rcd = packet->rcd;
	struct hfi1_ctxtdata *rcd = packet->rcd;
	void *data = packet->ebuf;
	void *data = packet->payload;
	u32 tlen = packet->tlen;
	u32 tlen = packet->tlen;
	struct rvt_qp *qp = packet->qp;
	struct rvt_qp *qp = packet->qp;
	struct hfi1_ibport *ibp = rcd_to_iport(rcd);
	struct hfi1_ibport *ibp = rcd_to_iport(rcd);
Loading