aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/hw/ipath/ipath_common.h19
-rw-r--r--drivers/infiniband/hw/ipath/ipath_diag.c39
2 files changed, 52 insertions, 6 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h
index 12e1349cd03e..f70788c25ea6 100644
--- a/drivers/infiniband/hw/ipath/ipath_common.h
+++ b/drivers/infiniband/hw/ipath/ipath_common.h
@@ -501,13 +501,30 @@ struct __ipath_sendpkt {
501 struct ipath_iovec sps_iov[4]; 501 struct ipath_iovec sps_iov[4];
502}; 502};
503 503
504/* Passed into diag data special file's ->write method. */ 504/*
505 * diagnostics can send a packet by "writing" one of the following
506 * two structs to diag data special file
507 * The first is the legacy version for backward compatibility
508 */
505struct ipath_diag_pkt { 509struct ipath_diag_pkt {
506 __u32 unit; 510 __u32 unit;
507 __u64 data; 511 __u64 data;
508 __u32 len; 512 __u32 len;
509}; 513};
510 514
515/* The second diag_pkt struct is the expanded version that allows
516 * more control over the packet, specifically, by allowing a custom
517 * pbc (+ extra) qword, so that special modes and deliberate
518 * changes to CRCs can be used. The elements were also re-ordered
519 * for better alignment and to avoid padding issues.
520 */
521struct ipath_diag_xpkt {
522 __u64 data;
523 __u64 pbc_wd;
524 __u32 unit;
525 __u32 len;
526};
527
511/* 528/*
512 * Data layout in I2C flash (for GUID, etc.) 529 * Data layout in I2C flash (for GUID, etc.)
513 * All fields are little-endian binary unless otherwise stated 530 * All fields are little-endian binary unless otherwise stated
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index 63e8368b0e95..aab21c1b822d 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -323,13 +323,14 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
323{ 323{
324 u32 __iomem *piobuf; 324 u32 __iomem *piobuf;
325 u32 plen, clen, pbufn; 325 u32 plen, clen, pbufn;
326 struct ipath_diag_pkt dp; 326 struct ipath_diag_pkt odp;
327 struct ipath_diag_xpkt dp;
327 u32 *tmpbuf = NULL; 328 u32 *tmpbuf = NULL;
328 struct ipath_devdata *dd; 329 struct ipath_devdata *dd;
329 ssize_t ret = 0; 330 ssize_t ret = 0;
330 u64 val; 331 u64 val;
331 332
332 if (count < sizeof(dp)) { 333 if (count != sizeof(dp)) {
333 ret = -EINVAL; 334 ret = -EINVAL;
334 goto bail; 335 goto bail;
335 } 336 }
@@ -339,6 +340,29 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
339 goto bail; 340 goto bail;
340 } 341 }
341 342
343 /*
344 * Due to padding/alignment issues (lessened with new struct)
345 * the old and new structs are the same length. We need to
346 * disambiguate them, which we can do because odp.len has never
347 * been less than the total of LRH+BTH+DETH so far, while
348 * dp.unit (same offset) unit is unlikely to get that high.
349 * Similarly, dp.data, the pointer to user at the same offset
350 * as odp.unit, is almost certainly at least one (512byte)page
351 * "above" NULL. The if-block below can be omitted if compatibility
352 * between a new driver and older diagnostic code is unimportant.
353 * compatibility the other direction (new diags, old driver) is
354 * handled in the diagnostic code, with a warning.
355 */
356 if (dp.unit >= 20 && dp.data < 512) {
357 /* very probable version mismatch. Fix it up */
358 memcpy(&odp, &dp, sizeof(odp));
359 /* We got a legacy dp, copy elements to dp */
360 dp.unit = odp.unit;
361 dp.data = odp.data;
362 dp.len = odp.len;
363 dp.pbc_wd = 0; /* Indicate we need to compute PBC wd */
364 }
365
342 /* send count must be an exact number of dwords */ 366 /* send count must be an exact number of dwords */
343 if (dp.len & 3) { 367 if (dp.len & 3) {
344 ret = -EINVAL; 368 ret = -EINVAL;
@@ -371,9 +395,10 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
371 ret = -ENODEV; 395 ret = -ENODEV;
372 goto bail; 396 goto bail;
373 } 397 }
398 /* Check link state, but not if we have custom PBC */
374 val = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK; 399 val = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK;
375 if (val != IPATH_IBSTATE_INIT && val != IPATH_IBSTATE_ARM && 400 if (!dp.pbc_wd && val != IPATH_IBSTATE_INIT &&
376 val != IPATH_IBSTATE_ACTIVE) { 401 val != IPATH_IBSTATE_ARM && val != IPATH_IBSTATE_ACTIVE) {
377 ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n", 402 ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n",
378 dd->ipath_unit, (unsigned long long) val); 403 dd->ipath_unit, (unsigned long long) val);
379 ret = -EINVAL; 404 ret = -EINVAL;
@@ -419,9 +444,13 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
419 ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n", 444 ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n",
420 dd->ipath_unit, plen - 1, pbufn); 445 dd->ipath_unit, plen - 1, pbufn);
421 446
447 if (dp.pbc_wd == 0)
448 /* Legacy operation, use computed pbc_wd */
449 dp.pbc_wd = plen;
450
422 /* we have to flush after the PBC for correctness on some cpus 451 /* we have to flush after the PBC for correctness on some cpus
423 * or WC buffer can be written out of order */ 452 * or WC buffer can be written out of order */
424 writeq(plen, piobuf); 453 writeq(dp.pbc_wd, piobuf);
425 ipath_flush_wc(); 454 ipath_flush_wc();
426 /* copy all by the trigger word, then flush, so it's written 455 /* copy all by the trigger word, then flush, so it's written
427 * to chip before trigger word, then write trigger word, then 456 * to chip before trigger word, then write trigger word, then