diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_common.h | 7 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_diag.c | 153 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_driver.c | 12 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_kernel.h | 4 |
4 files changed, 176 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h index f8df3b771c26..f577905e3aca 100644 --- a/drivers/infiniband/hw/ipath/ipath_common.h +++ b/drivers/infiniband/hw/ipath/ipath_common.h | |||
@@ -463,6 +463,13 @@ struct __ipath_sendpkt { | |||
463 | struct ipath_iovec sps_iov[4]; | 463 | struct ipath_iovec sps_iov[4]; |
464 | }; | 464 | }; |
465 | 465 | ||
466 | /* Passed into diag data special file's ->write method. */ | ||
467 | struct ipath_diag_pkt { | ||
468 | __u32 unit; | ||
469 | __u64 data; | ||
470 | __u32 len; | ||
471 | }; | ||
472 | |||
466 | /* | 473 | /* |
467 | * Data layout in I2C flash (for GUID, etc.) | 474 | * Data layout in I2C flash (for GUID, etc.) |
468 | * All fields are little-endian binary unless otherwise stated | 475 | * 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 5d77a74aa57b..28b6b46c106a 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c | |||
@@ -41,6 +41,7 @@ | |||
41 | * through the /sys/bus/pci resource mmap interface. | 41 | * through the /sys/bus/pci resource mmap interface. |
42 | */ | 42 | */ |
43 | 43 | ||
44 | #include <linux/io.h> | ||
44 | #include <linux/pci.h> | 45 | #include <linux/pci.h> |
45 | #include <asm/uaccess.h> | 46 | #include <asm/uaccess.h> |
46 | 47 | ||
@@ -273,6 +274,158 @@ bail: | |||
273 | return ret; | 274 | return ret; |
274 | } | 275 | } |
275 | 276 | ||
277 | static ssize_t ipath_diagpkt_write(struct file *fp, | ||
278 | const char __user *data, | ||
279 | size_t count, loff_t *off); | ||
280 | |||
281 | static struct file_operations diagpkt_file_ops = { | ||
282 | .owner = THIS_MODULE, | ||
283 | .write = ipath_diagpkt_write, | ||
284 | }; | ||
285 | |||
286 | static struct cdev *diagpkt_cdev; | ||
287 | static struct class_device *diagpkt_class_dev; | ||
288 | |||
289 | int __init ipath_diagpkt_add(void) | ||
290 | { | ||
291 | return ipath_cdev_init(IPATH_DIAGPKT_MINOR, | ||
292 | "ipath_diagpkt", &diagpkt_file_ops, | ||
293 | &diagpkt_cdev, &diagpkt_class_dev); | ||
294 | } | ||
295 | |||
296 | void __exit ipath_diagpkt_remove(void) | ||
297 | { | ||
298 | ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_class_dev); | ||
299 | } | ||
300 | |||
301 | /** | ||
302 | * ipath_diagpkt_write - write an IB packet | ||
303 | * @fp: the diag data device file pointer | ||
304 | * @data: ipath_diag_pkt structure saying where to get the packet | ||
305 | * @count: size of data to write | ||
306 | * @off: unused by this code | ||
307 | */ | ||
308 | static ssize_t ipath_diagpkt_write(struct file *fp, | ||
309 | const char __user *data, | ||
310 | size_t count, loff_t *off) | ||
311 | { | ||
312 | u32 __iomem *piobuf; | ||
313 | u32 plen, clen, pbufn; | ||
314 | struct ipath_diag_pkt dp; | ||
315 | u32 *tmpbuf = NULL; | ||
316 | struct ipath_devdata *dd; | ||
317 | ssize_t ret = 0; | ||
318 | u64 val; | ||
319 | |||
320 | if (count < sizeof(dp)) { | ||
321 | ret = -EINVAL; | ||
322 | goto bail; | ||
323 | } | ||
324 | |||
325 | if (copy_from_user(&dp, data, sizeof(dp))) { | ||
326 | ret = -EFAULT; | ||
327 | goto bail; | ||
328 | } | ||
329 | |||
330 | /* send count must be an exact number of dwords */ | ||
331 | if (dp.len & 3) { | ||
332 | ret = -EINVAL; | ||
333 | goto bail; | ||
334 | } | ||
335 | |||
336 | clen = dp.len >> 2; | ||
337 | |||
338 | dd = ipath_lookup(dp.unit); | ||
339 | if (!dd || !(dd->ipath_flags & IPATH_PRESENT) || | ||
340 | !dd->ipath_kregbase) { | ||
341 | ipath_cdbg(VERBOSE, "illegal unit %u for diag data send\n", | ||
342 | dp.unit); | ||
343 | ret = -ENODEV; | ||
344 | goto bail; | ||
345 | } | ||
346 | |||
347 | if (ipath_diag_inuse && !diag_set_link && | ||
348 | !(dd->ipath_flags & IPATH_LINKACTIVE)) { | ||
349 | diag_set_link = 1; | ||
350 | ipath_cdbg(VERBOSE, "Trying to set to set link active for " | ||
351 | "diag pkt\n"); | ||
352 | ipath_set_linkstate(dd, IPATH_IB_LINKARM); | ||
353 | ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE); | ||
354 | } | ||
355 | |||
356 | if (!(dd->ipath_flags & IPATH_INITTED)) { | ||
357 | /* no hardware, freeze, etc. */ | ||
358 | ipath_cdbg(VERBOSE, "unit %u not usable\n", dd->ipath_unit); | ||
359 | ret = -ENODEV; | ||
360 | goto bail; | ||
361 | } | ||
362 | val = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK; | ||
363 | if (val != IPATH_IBSTATE_INIT && val != IPATH_IBSTATE_ARM && | ||
364 | val != IPATH_IBSTATE_ACTIVE) { | ||
365 | ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n", | ||
366 | dd->ipath_unit, (unsigned long long) val); | ||
367 | ret = -EINVAL; | ||
368 | goto bail; | ||
369 | } | ||
370 | |||
371 | /* need total length before first word written */ | ||
372 | /* +1 word is for the qword padding */ | ||
373 | plen = sizeof(u32) + dp.len; | ||
374 | |||
375 | if ((plen + 4) > dd->ipath_ibmaxlen) { | ||
376 | ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n", | ||
377 | plen - 4, dd->ipath_ibmaxlen); | ||
378 | ret = -EINVAL; | ||
379 | goto bail; /* before writing pbc */ | ||
380 | } | ||
381 | tmpbuf = vmalloc(plen); | ||
382 | if (!tmpbuf) { | ||
383 | dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, " | ||
384 | "failing\n"); | ||
385 | ret = -ENOMEM; | ||
386 | goto bail; | ||
387 | } | ||
388 | |||
389 | if (copy_from_user(tmpbuf, | ||
390 | (const void __user *) (unsigned long) dp.data, | ||
391 | dp.len)) { | ||
392 | ret = -EFAULT; | ||
393 | goto bail; | ||
394 | } | ||
395 | |||
396 | piobuf = ipath_getpiobuf(dd, &pbufn); | ||
397 | if (!piobuf) { | ||
398 | ipath_cdbg(VERBOSE, "No PIO buffers avail unit for %u\n", | ||
399 | dd->ipath_unit); | ||
400 | ret = -EBUSY; | ||
401 | goto bail; | ||
402 | } | ||
403 | |||
404 | plen >>= 2; /* in dwords */ | ||
405 | |||
406 | if (ipath_debug & __IPATH_PKTDBG) | ||
407 | ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n", | ||
408 | dd->ipath_unit, plen - 1, pbufn); | ||
409 | |||
410 | /* we have to flush after the PBC for correctness on some cpus | ||
411 | * or WC buffer can be written out of order */ | ||
412 | writeq(plen, piobuf); | ||
413 | ipath_flush_wc(); | ||
414 | /* copy all by the trigger word, then flush, so it's written | ||
415 | * to chip before trigger word, then write trigger word, then | ||
416 | * flush again, so packet is sent. */ | ||
417 | __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1); | ||
418 | ipath_flush_wc(); | ||
419 | __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1); | ||
420 | ipath_flush_wc(); | ||
421 | |||
422 | ret = sizeof(dp); | ||
423 | |||
424 | bail: | ||
425 | vfree(tmpbuf); | ||
426 | return ret; | ||
427 | } | ||
428 | |||
276 | static int ipath_diag_release(struct inode *in, struct file *fp) | 429 | static int ipath_diag_release(struct inode *in, struct file *fp) |
277 | { | 430 | { |
278 | mutex_lock(&ipath_mutex); | 431 | mutex_lock(&ipath_mutex); |
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 520c38f13868..8c908b30984e 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c | |||
@@ -1881,8 +1881,18 @@ static int __init infinipath_init(void) | |||
1881 | goto bail_group; | 1881 | goto bail_group; |
1882 | } | 1882 | } |
1883 | 1883 | ||
1884 | ret = ipath_diagpkt_add(); | ||
1885 | if (ret < 0) { | ||
1886 | printk(KERN_ERR IPATH_DRV_NAME ": Unable to create " | ||
1887 | "diag data device: error %d\n", -ret); | ||
1888 | goto bail_ipathfs; | ||
1889 | } | ||
1890 | |||
1884 | goto bail; | 1891 | goto bail; |
1885 | 1892 | ||
1893 | bail_ipathfs: | ||
1894 | ipath_exit_ipathfs(); | ||
1895 | |||
1886 | bail_group: | 1896 | bail_group: |
1887 | ipath_driver_remove_group(&ipath_driver.driver); | 1897 | ipath_driver_remove_group(&ipath_driver.driver); |
1888 | 1898 | ||
@@ -1993,6 +2003,8 @@ static void __exit infinipath_cleanup(void) | |||
1993 | struct ipath_devdata *dd, *tmp; | 2003 | struct ipath_devdata *dd, *tmp; |
1994 | unsigned long flags; | 2004 | unsigned long flags; |
1995 | 2005 | ||
2006 | ipath_diagpkt_remove(); | ||
2007 | |||
1996 | ipath_exit_ipathfs(); | 2008 | ipath_exit_ipathfs(); |
1997 | 2009 | ||
1998 | ipath_driver_remove_group(&ipath_driver.driver); | 2010 | ipath_driver_remove_group(&ipath_driver.driver); |
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 0ae2729c7ea2..f8accc79b92f 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h | |||
@@ -789,6 +789,9 @@ int ipath_device_create_group(struct device *, struct ipath_devdata *); | |||
789 | void ipath_device_remove_group(struct device *, struct ipath_devdata *); | 789 | void ipath_device_remove_group(struct device *, struct ipath_devdata *); |
790 | int ipath_expose_reset(struct device *); | 790 | int ipath_expose_reset(struct device *); |
791 | 791 | ||
792 | int ipath_diagpkt_add(void); | ||
793 | void ipath_diagpkt_remove(void); | ||
794 | |||
792 | int ipath_init_ipathfs(void); | 795 | int ipath_init_ipathfs(void); |
793 | void ipath_exit_ipathfs(void); | 796 | void ipath_exit_ipathfs(void); |
794 | int ipathfs_add_device(struct ipath_devdata *); | 797 | int ipathfs_add_device(struct ipath_devdata *); |
@@ -813,6 +816,7 @@ extern struct mutex ipath_mutex; | |||
813 | #define IPATH_DRV_NAME "ib_ipath" | 816 | #define IPATH_DRV_NAME "ib_ipath" |
814 | #define IPATH_MAJOR 233 | 817 | #define IPATH_MAJOR 233 |
815 | #define IPATH_USER_MINOR_BASE 0 | 818 | #define IPATH_USER_MINOR_BASE 0 |
819 | #define IPATH_DIAGPKT_MINOR 127 | ||
816 | #define IPATH_DIAG_MINOR_BASE 129 | 820 | #define IPATH_DIAG_MINOR_BASE 129 |
817 | #define IPATH_NMINORS 255 | 821 | #define IPATH_NMINORS 255 |
818 | 822 | ||