aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albaugh <Michael.Albaugh@qlogic.com>2007-06-18 17:24:47 -0400
committerRoland Dreier <rolandd@cisco.com>2007-07-09 23:12:26 -0400
commite8e7ad711509f576b1bffd92c3ae4672fe92ec48 (patch)
treebdb211849ca0354632882161ff46647bc4a1f015
parentbacf4013530e7fc230a8aa0c6ea3c17fc2f47665 (diff)
IB/ipath: Add capability to modify PBC word
During compliance testing and when debugging some interconnect issues, it is very useful to be able to send malformed packets, without having the device signal them as malformed (drop, or terminate with EBP). The hardware supports this, but the driver "diagnostic packet" interface did not. Extend capability to send specific malformed packets for testing. Signed-off-by: Michael Albaugh <Michael.Albaugh@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
-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