aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/hw/ipath/ipath_diag.c66
1 files changed, 25 insertions, 41 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index 714293b78518..e2f9a51f4a38 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -326,7 +326,7 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
326 size_t count, loff_t *off) 326 size_t count, loff_t *off)
327{ 327{
328 u32 __iomem *piobuf; 328 u32 __iomem *piobuf;
329 u32 plen, clen, pbufn; 329 u32 plen, pbufn, maxlen_reserve;
330 struct ipath_diag_pkt odp; 330 struct ipath_diag_pkt odp;
331 struct ipath_diag_xpkt dp; 331 struct ipath_diag_xpkt dp;
332 u32 *tmpbuf = NULL; 332 u32 *tmpbuf = NULL;
@@ -335,51 +335,29 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
335 u64 val; 335 u64 val;
336 u32 l_state, lt_state; /* LinkState, LinkTrainingState */ 336 u32 l_state, lt_state; /* LinkState, LinkTrainingState */
337 337
338 if (count < sizeof(odp)) {
339 ret = -EINVAL;
340 goto bail;
341 }
342 338
343 if (count == sizeof(dp)) { 339 if (count == sizeof(dp)) {
344 if (copy_from_user(&dp, data, sizeof(dp))) { 340 if (copy_from_user(&dp, data, sizeof(dp))) {
345 ret = -EFAULT; 341 ret = -EFAULT;
346 goto bail; 342 goto bail;
347 } 343 }
348 } else if (copy_from_user(&odp, data, sizeof(odp))) { 344 } else if (count == sizeof(odp)) {
349 ret = -EFAULT; 345 if (copy_from_user(&odp, data, sizeof(odp))) {
346 ret = -EFAULT;
347 goto bail;
348 }
349 } else {
350 ret = -EINVAL;
350 goto bail; 351 goto bail;
351 } 352 }
352 353
353 /*
354 * Due to padding/alignment issues (lessened with new struct)
355 * the old and new structs are the same length. We need to
356 * disambiguate them, which we can do because odp.len has never
357 * been less than the total of LRH+BTH+DETH so far, while
358 * dp.unit (same offset) unit is unlikely to get that high.
359 * Similarly, dp.data, the pointer to user at the same offset
360 * as odp.unit, is almost certainly at least one (512byte)page
361 * "above" NULL. The if-block below can be omitted if compatibility
362 * between a new driver and older diagnostic code is unimportant.
363 * compatibility the other direction (new diags, old driver) is
364 * handled in the diagnostic code, with a warning.
365 */
366 if (dp.unit >= 20 && dp.data < 512) {
367 /* very probable version mismatch. Fix it up */
368 memcpy(&odp, &dp, sizeof(odp));
369 /* We got a legacy dp, copy elements to dp */
370 dp.unit = odp.unit;
371 dp.data = odp.data;
372 dp.len = odp.len;
373 dp.pbc_wd = 0; /* Indicate we need to compute PBC wd */
374 }
375
376 /* send count must be an exact number of dwords */ 354 /* send count must be an exact number of dwords */
377 if (dp.len & 3) { 355 if (dp.len & 3) {
378 ret = -EINVAL; 356 ret = -EINVAL;
379 goto bail; 357 goto bail;
380 } 358 }
381 359
382 clen = dp.len >> 2; 360 plen = dp.len >> 2;
383 361
384 dd = ipath_lookup(dp.unit); 362 dd = ipath_lookup(dp.unit);
385 if (!dd || !(dd->ipath_flags & IPATH_PRESENT) || 363 if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
@@ -422,16 +400,22 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
422 goto bail; 400 goto bail;
423 } 401 }
424 402
425 /* need total length before first word written */ 403 /*
426 /* +1 word is for the qword padding */ 404 * need total length before first word written, plus 2 Dwords. One Dword
427 plen = sizeof(u32) + dp.len; 405 * is for padding so we get the full user data when not aligned on
428 406 * a word boundary. The other Dword is to make sure we have room for the
429 if ((plen + 4) > dd->ipath_ibmaxlen) { 407 * ICRC which gets tacked on later.
408 */
409 maxlen_reserve = 2 * sizeof(u32);
410 if (dp.len > dd->ipath_ibmaxlen - maxlen_reserve) {
430 ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n", 411 ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
431 plen - 4, dd->ipath_ibmaxlen); 412 dp.len, dd->ipath_ibmaxlen);
432 ret = -EINVAL; 413 ret = -EINVAL;
433 goto bail; /* before writing pbc */ 414 goto bail;
434 } 415 }
416
417 plen = sizeof(u32) + dp.len;
418
435 tmpbuf = vmalloc(plen); 419 tmpbuf = vmalloc(plen);
436 if (!tmpbuf) { 420 if (!tmpbuf) {
437 dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, " 421 dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
@@ -473,11 +457,11 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
473 */ 457 */
474 if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) { 458 if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
475 ipath_flush_wc(); 459 ipath_flush_wc();
476 __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1); 460 __iowrite32_copy(piobuf + 2, tmpbuf, plen - 1);
477 ipath_flush_wc(); 461 ipath_flush_wc();
478 __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1); 462 __raw_writel(tmpbuf[plen - 1], piobuf + plen + 1);
479 } else 463 } else
480 __iowrite32_copy(piobuf + 2, tmpbuf, clen); 464 __iowrite32_copy(piobuf + 2, tmpbuf, plen);
481 465
482 ipath_flush_wc(); 466 ipath_flush_wc();
483 467