diff options
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_diag.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_diag.c | 154 |
1 files changed, 153 insertions, 1 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index 147dd89e21c9..28b6b46c106a 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c | |||
@@ -41,11 +41,11 @@ | |||
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 | ||
47 | #include "ipath_kernel.h" | 48 | #include "ipath_kernel.h" |
48 | #include "ipath_layer.h" | ||
49 | #include "ipath_common.h" | 49 | #include "ipath_common.h" |
50 | 50 | ||
51 | int ipath_diag_inuse; | 51 | int ipath_diag_inuse; |
@@ -274,6 +274,158 @@ bail: | |||
274 | return ret; | 274 | return ret; |
275 | } | 275 | } |
276 | 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 | |||
277 | static int ipath_diag_release(struct inode *in, struct file *fp) | 429 | static int ipath_diag_release(struct inode *in, struct file *fp) |
278 | { | 430 | { |
279 | mutex_lock(&ipath_mutex); | 431 | mutex_lock(&ipath_mutex); |