Merge remote-tracking branch 'lsk/v3.10/topic/gator' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / drivers / infiniband / hw / ipath / ipath_diag.c
index 714293b78518598c7fe262315de6cbfaafe9263b..45802e97332ee830354e9bbbfe206031236629e6 100644 (file)
@@ -326,7 +326,7 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
                                   size_t count, loff_t *off)
 {
        u32 __iomem *piobuf;
-       u32 plen, clen, pbufn;
+       u32 plen, pbufn, maxlen_reserve;
        struct ipath_diag_pkt odp;
        struct ipath_diag_xpkt dp;
        u32 *tmpbuf = NULL;
@@ -335,42 +335,24 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
        u64 val;
        u32 l_state, lt_state; /* LinkState, LinkTrainingState */
 
-       if (count < sizeof(odp)) {
-               ret = -EINVAL;
-               goto bail;
-       }
 
        if (count == sizeof(dp)) {
                if (copy_from_user(&dp, data, sizeof(dp))) {
                        ret = -EFAULT;
                        goto bail;
                }
-       } else if (copy_from_user(&odp, data, sizeof(odp))) {
-               ret = -EFAULT;
-               goto bail;
-       }
-
-       /*
-        * Due to padding/alignment issues (lessened with new struct)
-        * the old and new structs are the same length. We need to
-        * disambiguate them, which we can do because odp.len has never
-        * been less than the total of LRH+BTH+DETH so far, while
-        * dp.unit (same offset) unit is unlikely to get that high.
-        * Similarly, dp.data, the pointer to user at the same offset
-        * as odp.unit, is almost certainly at least one (512byte)page
-        * "above" NULL. The if-block below can be omitted if compatibility
-        * between a new driver and older diagnostic code is unimportant.
-        * compatibility the other direction (new diags, old driver) is
-        * handled in the diagnostic code, with a warning.
-        */
-       if (dp.unit >= 20 && dp.data < 512) {
-               /* very probable version mismatch. Fix it up */
-               memcpy(&odp, &dp, sizeof(odp));
-               /* We got a legacy dp, copy elements to dp */
+       } else if (count == sizeof(odp)) {
+               if (copy_from_user(&odp, data, sizeof(odp))) {
+                       ret = -EFAULT;
+                       goto bail;
+               }
+               dp.len = odp.len;
                dp.unit = odp.unit;
                dp.data = odp.data;
-               dp.len = odp.len;
-               dp.pbc_wd = 0; /* Indicate we need to compute PBC wd */
+               dp.pbc_wd = 0;
+       } else {
+               ret = -EINVAL;
+               goto bail;
        }
 
        /* send count must be an exact number of dwords */
@@ -379,7 +361,7 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
                goto bail;
        }
 
-       clen = dp.len >> 2;
+       plen = dp.len >> 2;
 
        dd = ipath_lookup(dp.unit);
        if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
@@ -422,16 +404,22 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
                goto bail;
        }
 
-       /* need total length before first word written */
-       /* +1 word is for the qword padding */
-       plen = sizeof(u32) + dp.len;
-
-       if ((plen + 4) > dd->ipath_ibmaxlen) {
+       /*
+        * need total length before first word written, plus 2 Dwords. One Dword
+        * is for padding so we get the full user data when not aligned on
+        * a word boundary. The other Dword is to make sure we have room for the
+        * ICRC which gets tacked on later.
+        */
+       maxlen_reserve = 2 * sizeof(u32);
+       if (dp.len > dd->ipath_ibmaxlen - maxlen_reserve) {
                ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
-                         plen - 4, dd->ipath_ibmaxlen);
+                         dp.len, dd->ipath_ibmaxlen);
                ret = -EINVAL;
-               goto bail;      /* before writing pbc */
+               goto bail;
        }
+
+       plen = sizeof(u32) + dp.len;
+
        tmpbuf = vmalloc(plen);
        if (!tmpbuf) {
                dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
@@ -473,11 +461,11 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
         */
        if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
                ipath_flush_wc();
-               __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
+               __iowrite32_copy(piobuf + 2, tmpbuf, plen - 1);
                ipath_flush_wc();
-               __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
+               __raw_writel(tmpbuf[plen - 1], piobuf + plen + 1);
        } else
-               __iowrite32_copy(piobuf + 2, tmpbuf, clen);
+               __iowrite32_copy(piobuf + 2, tmpbuf, plen);
 
        ipath_flush_wc();