aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBryan O'Sullivan <bos@pathscale.com>2006-08-25 14:24:36 -0400
committerRoland Dreier <rolandd@cisco.com>2006-09-22 18:22:34 -0400
commit98341f261893acd7bc5abee5ddc35337ef49e457 (patch)
tree44393b654275fbb4324da3b6622808e36f6c3dbd /drivers
parent32c0a26c8f91dbc2797175c2bdff42b54f66c71d (diff)
IB/ipath: add new minor device to allow sending of diag packets
Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/infiniband/hw/ipath/ipath_common.h7
-rw-r--r--drivers/infiniband/hw/ipath/ipath_diag.c153
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c12
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h4
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. */
467struct 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
277static ssize_t ipath_diagpkt_write(struct file *fp,
278 const char __user *data,
279 size_t count, loff_t *off);
280
281static struct file_operations diagpkt_file_ops = {
282 .owner = THIS_MODULE,
283 .write = ipath_diagpkt_write,
284};
285
286static struct cdev *diagpkt_cdev;
287static struct class_device *diagpkt_class_dev;
288
289int __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
296void __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 */
308static 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
424bail:
425 vfree(tmpbuf);
426 return ret;
427}
428
276static int ipath_diag_release(struct inode *in, struct file *fp) 429static 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
1893bail_ipathfs:
1894 ipath_exit_ipathfs();
1895
1886bail_group: 1896bail_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 *);
789void ipath_device_remove_group(struct device *, struct ipath_devdata *); 789void ipath_device_remove_group(struct device *, struct ipath_devdata *);
790int ipath_expose_reset(struct device *); 790int ipath_expose_reset(struct device *);
791 791
792int ipath_diagpkt_add(void);
793void ipath_diagpkt_remove(void);
794
792int ipath_init_ipathfs(void); 795int ipath_init_ipathfs(void);
793void ipath_exit_ipathfs(void); 796void ipath_exit_ipathfs(void);
794int ipathfs_add_device(struct ipath_devdata *); 797int 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