diff options
author | Ira Weiny <ira.weiny@intel.com> | 2016-07-27 21:08:42 -0400 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2016-08-02 22:46:21 -0400 |
commit | c49298026908a8ce9dcf01ed68734ad171cef98b (patch) | |
tree | 303688733b41eadebc1f24ccbbedb259bda9d100 | |
parent | fe508272c963d62de4183c32b6883c3d54c557ef (diff) |
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: Harish Chegondi <harish.chegondi@intel.com>
Signed-off-by: Sebastian Sanchez <sebastian.sanchez@intel.com>
Signed-off-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r-- | drivers/infiniband/hw/hfi1/user_sdma.c | 31 | ||||
-rw-r--r-- | include/uapi/rdma/hfi/hfi1_user.h | 2 |
2 files changed, 23 insertions, 10 deletions
diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index d16ed52a2cb1..1e266c95056a 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c | |||
@@ -793,14 +793,21 @@ static inline u32 compute_data_length(struct user_sdma_request *req, | |||
793 | * The size of the data of the first packet is in the header | 793 | * The size of the data of the first packet is in the header |
794 | * template. However, it includes the header and ICRC, which need | 794 | * template. However, it includes the header and ICRC, which need |
795 | * to be subtracted. | 795 | * to be subtracted. |
796 | * The minimum representable packet data length in a header is 4 bytes, | ||
797 | * therefore, when the data length request is less than 4 bytes, there's | ||
798 | * only one packet, and the packet data length is equal to that of the | ||
799 | * request data length. | ||
796 | * The size of the remaining packets is the minimum of the frag | 800 | * The size of the remaining packets is the minimum of the frag |
797 | * size (MTU) or remaining data in the request. | 801 | * size (MTU) or remaining data in the request. |
798 | */ | 802 | */ |
799 | u32 len; | 803 | u32 len; |
800 | 804 | ||
801 | if (!req->seqnum) { | 805 | if (!req->seqnum) { |
802 | len = ((be16_to_cpu(req->hdr.lrh[2]) << 2) - | 806 | if (req->data_len < sizeof(u32)) |
803 | (sizeof(tx->hdr) - 4)); | 807 | len = req->data_len; |
808 | else | ||
809 | len = ((be16_to_cpu(req->hdr.lrh[2]) << 2) - | ||
810 | (sizeof(tx->hdr) - 4)); | ||
804 | } else if (req_opcode(req->info.ctrl) == EXPECTED) { | 811 | } else if (req_opcode(req->info.ctrl) == EXPECTED) { |
805 | u32 tidlen = EXP_TID_GET(req->tids[req->tididx], LEN) * | 812 | u32 tidlen = EXP_TID_GET(req->tids[req->tididx], LEN) * |
806 | PAGE_SIZE; | 813 | PAGE_SIZE; |
@@ -830,6 +837,13 @@ static inline u32 compute_data_length(struct user_sdma_request *req, | |||
830 | return len; | 837 | return len; |
831 | } | 838 | } |
832 | 839 | ||
840 | static inline u32 pad_len(u32 len) | ||
841 | { | ||
842 | if (len & (sizeof(u32) - 1)) | ||
843 | len += sizeof(u32) - (len & (sizeof(u32) - 1)); | ||
844 | return len; | ||
845 | } | ||
846 | |||
833 | static inline u32 get_lrh_len(struct hfi1_pkt_header hdr, u32 len) | 847 | static inline u32 get_lrh_len(struct hfi1_pkt_header hdr, u32 len) |
834 | { | 848 | { |
835 | /* (Size of complete header - size of PBC) + 4B ICRC + data length */ | 849 | /* (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) | |||
921 | if (test_bit(SDMA_REQ_HAVE_AHG, &req->flags)) { | 935 | if (test_bit(SDMA_REQ_HAVE_AHG, &req->flags)) { |
922 | if (!req->seqnum) { | 936 | if (!req->seqnum) { |
923 | u16 pbclen = le16_to_cpu(req->hdr.pbc[0]); | 937 | u16 pbclen = le16_to_cpu(req->hdr.pbc[0]); |
924 | u32 lrhlen = get_lrh_len(req->hdr, datalen); | 938 | u32 lrhlen = get_lrh_len(req->hdr, |
939 | pad_len(datalen)); | ||
925 | /* | 940 | /* |
926 | * Copy the request header into the tx header | 941 | * Copy the request header into the tx header |
927 | * because the HW needs a cacheline-aligned | 942 | * because the HW needs a cacheline-aligned |
@@ -1219,16 +1234,14 @@ static int check_header_template(struct user_sdma_request *req, | |||
1219 | /* | 1234 | /* |
1220 | * Perform safety checks for any type of packet: | 1235 | * Perform safety checks for any type of packet: |
1221 | * - transfer size is multiple of 64bytes | 1236 | * - transfer size is multiple of 64bytes |
1222 | * - packet length is multiple of 4bytes | 1237 | * - packet length is multiple of 4 bytes |
1223 | * - entire request length is multiple of 4bytes | ||
1224 | * - packet length is not larger than MTU size | 1238 | * - packet length is not larger than MTU size |
1225 | * | 1239 | * |
1226 | * These checks are only done for the first packet of the | 1240 | * These checks are only done for the first packet of the |
1227 | * transfer since the header is "given" to us by user space. | 1241 | * transfer since the header is "given" to us by user space. |
1228 | * For the remainder of the packets we compute the values. | 1242 | * For the remainder of the packets we compute the values. |
1229 | */ | 1243 | */ |
1230 | if (req->info.fragsize % PIO_BLOCK_SIZE || | 1244 | if (req->info.fragsize % PIO_BLOCK_SIZE || lrhlen & 0x3 || |
1231 | lrhlen & 0x3 || req->data_len & 0x3 || | ||
1232 | lrhlen > get_lrh_len(*hdr, req->info.fragsize)) | 1245 | lrhlen > get_lrh_len(*hdr, req->info.fragsize)) |
1233 | return -EINVAL; | 1246 | return -EINVAL; |
1234 | 1247 | ||
@@ -1290,7 +1303,7 @@ static int set_txreq_header(struct user_sdma_request *req, | |||
1290 | struct hfi1_pkt_header *hdr = &tx->hdr; | 1303 | struct hfi1_pkt_header *hdr = &tx->hdr; |
1291 | u16 pbclen; | 1304 | u16 pbclen; |
1292 | int ret; | 1305 | int ret; |
1293 | u32 tidval = 0, lrhlen = get_lrh_len(*hdr, datalen); | 1306 | u32 tidval = 0, lrhlen = get_lrh_len(*hdr, pad_len(datalen)); |
1294 | 1307 | ||
1295 | /* Copy the header template to the request before modification */ | 1308 | /* Copy the header template to the request before modification */ |
1296 | memcpy(hdr, &req->hdr, sizeof(*hdr)); | 1309 | memcpy(hdr, &req->hdr, sizeof(*hdr)); |
@@ -1401,7 +1414,7 @@ static int set_txreq_header_ahg(struct user_sdma_request *req, | |||
1401 | struct hfi1_user_sdma_pkt_q *pq = req->pq; | 1414 | struct hfi1_user_sdma_pkt_q *pq = req->pq; |
1402 | struct hfi1_pkt_header *hdr = &req->hdr; | 1415 | struct hfi1_pkt_header *hdr = &req->hdr; |
1403 | u16 pbclen = le16_to_cpu(hdr->pbc[0]); | 1416 | u16 pbclen = le16_to_cpu(hdr->pbc[0]); |
1404 | u32 val32, tidval = 0, lrhlen = get_lrh_len(*hdr, len); | 1417 | u32 val32, tidval = 0, lrhlen = get_lrh_len(*hdr, pad_len(len)); |
1405 | 1418 | ||
1406 | if (PBC2LRH(pbclen) != lrhlen) { | 1419 | if (PBC2LRH(pbclen) != lrhlen) { |
1407 | /* PBC.PbcLengthDWs */ | 1420 | /* PBC.PbcLengthDWs */ |
diff --git a/include/uapi/rdma/hfi/hfi1_user.h b/include/uapi/rdma/hfi/hfi1_user.h index 98bebf8bef55..d15e7289d835 100644 --- a/include/uapi/rdma/hfi/hfi1_user.h +++ b/include/uapi/rdma/hfi/hfi1_user.h | |||
@@ -75,7 +75,7 @@ | |||
75 | * may not be implemented; the user code must deal with this if it | 75 | * may not be implemented; the user code must deal with this if it |
76 | * cares, or it must abort after initialization reports the difference. | 76 | * cares, or it must abort after initialization reports the difference. |
77 | */ | 77 | */ |
78 | #define HFI1_USER_SWMINOR 1 | 78 | #define HFI1_USER_SWMINOR 2 |
79 | 79 | ||
80 | /* | 80 | /* |
81 | * We will encode the major/minor inside a single 32bit version number. | 81 | * We will encode the major/minor inside a single 32bit version number. |