Commit c4929802 authored by Ira Weiny's avatar Ira Weiny Committed by Doug Ledford
Browse files

IB/hfi1: Allow for non-double word multiple message sizes for user SDMA



The driver pads non-double word multiple message sizes but it doesn't
account for this padding when the packet length is calculated. Also, the
data length is miscalculated for message sizes less than 4 bytes due to
the bit representation in LRH. And there's a check for non-double word
multiple message sizes that prevents these messages from being sent.
This patch fixes length miscalculations and enables the functionality to
send non-double word multiple message sizes.

Reviewed-by: default avatarHarish Chegondi <harish.chegondi@intel.com>
Signed-off-by: default avatarSebastian Sanchez <sebastian.sanchez@intel.com>
Signed-off-by: default avatarIra Weiny <ira.weiny@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent fe508272
Loading
Loading
Loading
Loading
+22 −9
Original line number Diff line number Diff line
@@ -793,12 +793,19 @@ static inline u32 compute_data_length(struct user_sdma_request *req,
	 * The size of the data of the first packet is in the header
	 * template. However, it includes the header and ICRC, which need
	 * to be subtracted.
	 * The minimum representable packet data length in a header is 4 bytes,
	 * therefore, when the data length request is less than 4 bytes, there's
	 * only one packet, and the packet data length is equal to that of the
	 * request data length.
	 * The size of the remaining packets is the minimum of the frag
	 * size (MTU) or remaining data in the request.
	 */
	u32 len;

	if (!req->seqnum) {
		if (req->data_len < sizeof(u32))
			len = req->data_len;
		else
			len = ((be16_to_cpu(req->hdr.lrh[2]) << 2) -
			       (sizeof(tx->hdr) - 4));
	} else if (req_opcode(req->info.ctrl) == EXPECTED) {
@@ -830,6 +837,13 @@ static inline u32 compute_data_length(struct user_sdma_request *req,
	return len;
}

static inline u32 pad_len(u32 len)
{
	if (len & (sizeof(u32) - 1))
		len += sizeof(u32) - (len & (sizeof(u32) - 1));
	return len;
}

static inline u32 get_lrh_len(struct hfi1_pkt_header hdr, u32 len)
{
	/* (Size of complete header - size of PBC) + 4B ICRC + data length */
@@ -921,7 +935,8 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts)
		if (test_bit(SDMA_REQ_HAVE_AHG, &req->flags)) {
			if (!req->seqnum) {
				u16 pbclen = le16_to_cpu(req->hdr.pbc[0]);
				u32 lrhlen = get_lrh_len(req->hdr, datalen);
				u32 lrhlen = get_lrh_len(req->hdr,
							 pad_len(datalen));
				/*
				 * Copy the request header into the tx header
				 * because the HW needs a cacheline-aligned
@@ -1220,15 +1235,13 @@ static int check_header_template(struct user_sdma_request *req,
	 * Perform safety checks for any type of packet:
	 *    - transfer size is multiple of 64bytes
	 *    - packet length is multiple of 4 bytes
	 *    - entire request length is multiple of 4bytes
	 *    - packet length is not larger than MTU size
	 *
	 * These checks are only done for the first packet of the
	 * transfer since the header is "given" to us by user space.
	 * For the remainder of the packets we compute the values.
	 */
	if (req->info.fragsize % PIO_BLOCK_SIZE ||
	    lrhlen & 0x3 || req->data_len & 0x3  ||
	if (req->info.fragsize % PIO_BLOCK_SIZE || lrhlen & 0x3 ||
	    lrhlen > get_lrh_len(*hdr, req->info.fragsize))
		return -EINVAL;

@@ -1290,7 +1303,7 @@ static int set_txreq_header(struct user_sdma_request *req,
	struct hfi1_pkt_header *hdr = &tx->hdr;
	u16 pbclen;
	int ret;
	u32 tidval = 0, lrhlen = get_lrh_len(*hdr, datalen);
	u32 tidval = 0, lrhlen = get_lrh_len(*hdr, pad_len(datalen));

	/* Copy the header template to the request before modification */
	memcpy(hdr, &req->hdr, sizeof(*hdr));
@@ -1401,7 +1414,7 @@ static int set_txreq_header_ahg(struct user_sdma_request *req,
	struct hfi1_user_sdma_pkt_q *pq = req->pq;
	struct hfi1_pkt_header *hdr = &req->hdr;
	u16 pbclen = le16_to_cpu(hdr->pbc[0]);
	u32 val32, tidval = 0, lrhlen = get_lrh_len(*hdr, len);
	u32 val32, tidval = 0, lrhlen = get_lrh_len(*hdr, pad_len(len));

	if (PBC2LRH(pbclen) != lrhlen) {
		/* PBC.PbcLengthDWs */
+1 −1
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@
 * may not be implemented; the user code must deal with this if it
 * cares, or it must abort after initialization reports the difference.
 */
#define HFI1_USER_SWMINOR 1
#define HFI1_USER_SWMINOR 2

/*
 * We will encode the major/minor inside a single 32bit version number.