summaryrefslogtreecommitdiff
path: root/drivers/staging/rdma/hfi1/verbs.c
diff options
context:
space:
mode:
authorDean Luick <dean.luick@intel.com>2016-02-04 01:35:49 +0300
committerDoug Ledford <dledford@redhat.com>2016-03-11 04:37:56 +0300
commit7b0b01aa8f48cd237322cbffa05662a9c6b156f8 (patch)
tree02482f328f5dc0b7f509af19628c8f88c48a3e52 /drivers/staging/rdma/hfi1/verbs.c
parent53f449e4bf04ac5dce6385a1546ab6108666def2 (diff)
downloadlinux-7b0b01aa8f48cd237322cbffa05662a9c6b156f8.tar.xz
staging/rdma/hfi1: Split last 8 bytes of copy to user buffer
Copy the last 8 bytes of user mode RC WRITE_ONLY and WRITE_LAST opcodes separately from the rest of the data. It is a de-facto standard for some MPI implementations to use a poll on the last few bytes of a verbs message to indicate that the message has been received rather than follow the required function method. The driver uses the kernel memcpy routine, which becomes "rep movsb" on modern machines. This copy, while very fast, does not guarantee in-order copy completion and the result is an occasional perceived corrupted packet. Avoid the issue by splitting the last 8 bytes to copy from the verbs opcodes where it matters and performing an in-order byte copy. Reviewed-by: Mike Marciniszyn <mike.marciniszyn@intel.com> Signed-off-by: Dean Luick <dean.luick@intel.com> Signed-off-by: Jubin John <jubin.john@intel.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
Diffstat (limited to 'drivers/staging/rdma/hfi1/verbs.c')
-rw-r--r--drivers/staging/rdma/hfi1/verbs.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/drivers/staging/rdma/hfi1/verbs.c b/drivers/staging/rdma/hfi1/verbs.c
index d617324e3c48..8f351bc157df 100644
--- a/drivers/staging/rdma/hfi1/verbs.c
+++ b/drivers/staging/rdma/hfi1/verbs.c
@@ -242,14 +242,28 @@ __be64 ib_hfi1_sys_image_guid;
* @ss: the SGE state
* @data: the data to copy
* @length: the length of the data
+ * @copy_last: do a separate copy of the last 8 bytes
*/
void hfi1_copy_sge(
struct rvt_sge_state *ss,
void *data, u32 length,
- int release)
+ int release,
+ int copy_last)
{
struct rvt_sge *sge = &ss->sge;
+ int in_last = 0;
+ int i;
+
+ if (copy_last) {
+ if (length > 8) {
+ length -= 8;
+ } else {
+ copy_last = 0;
+ in_last = 1;
+ }
+ }
+again:
while (length) {
u32 len = sge->length;
@@ -258,7 +272,13 @@ void hfi1_copy_sge(
if (len > sge->sge_length)
len = sge->sge_length;
WARN_ON_ONCE(len == 0);
- memcpy(sge->vaddr, data, len);
+ if (in_last) {
+ /* enforce byte transer ordering */
+ for (i = 0; i < len; i++)
+ ((u8 *)sge->vaddr)[i] = ((u8 *)data)[i];
+ } else {
+ memcpy(sge->vaddr, data, len);
+ }
sge->vaddr += len;
sge->length -= len;
sge->sge_length -= len;
@@ -281,6 +301,13 @@ void hfi1_copy_sge(
data += len;
length -= len;
}
+
+ if (copy_last) {
+ copy_last = 0;
+ in_last = 1;
+ length = 8;
+ goto again;
+ }
}
/**