IB/hfi1: Make iovec loop index easy to understand
[cascardo/linux.git] / drivers / infiniband / hw / hfi1 / user_sdma.c
index 47ffd27..586f078 100644 (file)
@@ -496,10 +496,31 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd)
        return 0;
 }
 
+static u8 dlid_to_selector(u16 dlid)
+{
+       static u8 mapping[256];
+       static int initialized;
+       static u8 next;
+       int hash;
+
+       if (!initialized) {
+               memset(mapping, 0xFF, 256);
+               initialized = 1;
+       }
+
+       hash = ((dlid >> 8) ^ dlid) & 0xFF;
+       if (mapping[hash] == 0xFF) {
+               mapping[hash] = next;
+               next = (next + 1) & 0x7F;
+       }
+
+       return mapping[hash];
+}
+
 int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
                                   unsigned long dim, unsigned long *count)
 {
-       int ret = 0, i = 0;
+       int ret = 0, i;
        struct hfi1_filedata *fd = fp->private_data;
        struct hfi1_ctxtdata *uctxt = fd->uctxt;
        struct hfi1_user_sdma_pkt_q *pq = fd->pq;
@@ -511,6 +532,8 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
        struct user_sdma_request *req;
        u8 opcode, sc, vl;
        int req_queued = 0;
+       u16 dlid;
+       u8 selector;
 
        if (iovec[idx].iov_len < sizeof(info) + sizeof(req->hdr)) {
                hfi1_cdbg(
@@ -634,7 +657,7 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
        idx++;
 
        /* Save all the IO vector structures */
-       while (i < req->data_iovs) {
+       for (i = 0; i < req->data_iovs; i++) {
                INIT_LIST_HEAD(&req->iovs[i].list);
                memcpy(&req->iovs[i].iov, iovec + idx++, sizeof(struct iovec));
                ret = pin_vector_pages(req, &req->iovs[i]);
@@ -642,7 +665,7 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
                        req->status = ret;
                        goto free_req;
                }
-               req->data_len += req->iovs[i++].iov.iov_len;
+               req->data_len += req->iovs[i].iov.iov_len;
        }
        SDMA_DBG(req, "total data length %u", req->data_len);
 
@@ -686,9 +709,13 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
                idx++;
        }
 
+       dlid = be16_to_cpu(req->hdr.lrh[1]);
+       selector = dlid_to_selector(dlid);
+
        /* Have to select the engine */
        req->sde = sdma_select_engine_vl(dd,
-                                        (u32)(uctxt->ctxt + fd->subctxt),
+                                        (u32)(uctxt->ctxt + fd->subctxt +
+                                              selector),
                                         vl);
        if (!req->sde || !sdma_running(req->sde)) {
                ret = -ECOMM;
@@ -766,14 +793,21 @@ 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) {
-               len = ((be16_to_cpu(req->hdr.lrh[2]) << 2) -
-                      (sizeof(tx->hdr) - 4));
+               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) {
                u32 tidlen = EXP_TID_GET(req->tids[req->tididx], LEN) *
                        PAGE_SIZE;
@@ -803,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 */
@@ -894,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
@@ -1073,7 +1115,8 @@ static u32 sdma_cache_evict(struct hfi1_user_sdma_pkt_q *pq, u32 npages)
 }
 
 static int pin_vector_pages(struct user_sdma_request *req,
-                           struct user_sdma_iovec *iovec) {
+                           struct user_sdma_iovec *iovec)
+{
        int ret = 0, pinned, npages, cleared;
        struct page **pages;
        struct hfi1_user_sdma_pkt_q *pq = req->pq;
@@ -1181,7 +1224,7 @@ bail:
 static void unpin_vector_pages(struct mm_struct *mm, struct page **pages,
                               unsigned start, unsigned npages)
 {
-       hfi1_release_user_pages(mm, pages + start, npages, 0);
+       hfi1_release_user_pages(mm, pages + start, npages, false);
        kfree(pages);
 }
 
@@ -1192,16 +1235,14 @@ 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 4bytes
-        *    - entire request length is multiple of 4bytes
+        *    - packet length is multiple of 4 bytes
         *    - 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;
 
@@ -1263,7 +1304,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));
@@ -1374,7 +1415,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 */