Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/infiniband/hw/ipath/ipath_diag.c
15112 views
1
/*
2
* Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
3
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
4
*
5
* This software is available to you under a choice of one of two
6
* licenses. You may choose to be licensed under the terms of the GNU
7
* General Public License (GPL) Version 2, available from the file
8
* COPYING in the main directory of this source tree, or the
9
* OpenIB.org BSD license below:
10
*
11
* Redistribution and use in source and binary forms, with or
12
* without modification, are permitted provided that the following
13
* conditions are met:
14
*
15
* - Redistributions of source code must retain the above
16
* copyright notice, this list of conditions and the following
17
* disclaimer.
18
*
19
* - Redistributions in binary form must reproduce the above
20
* copyright notice, this list of conditions and the following
21
* disclaimer in the documentation and/or other materials
22
* provided with the distribution.
23
*
24
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
* SOFTWARE.
32
*/
33
34
/*
35
* This file contains support for diagnostic functions. It is accessed by
36
* opening the ipath_diag device, normally minor number 129. Diagnostic use
37
* of the InfiniPath chip may render the chip or board unusable until the
38
* driver is unloaded, or in some cases, until the system is rebooted.
39
*
40
* Accesses to the chip through this interface are not similar to going
41
* through the /sys/bus/pci resource mmap interface.
42
*/
43
44
#include <linux/io.h>
45
#include <linux/pci.h>
46
#include <linux/vmalloc.h>
47
#include <linux/fs.h>
48
#include <asm/uaccess.h>
49
50
#include "ipath_kernel.h"
51
#include "ipath_common.h"
52
53
int ipath_diag_inuse;
54
static int diag_set_link;
55
56
static int ipath_diag_open(struct inode *in, struct file *fp);
57
static int ipath_diag_release(struct inode *in, struct file *fp);
58
static ssize_t ipath_diag_read(struct file *fp, char __user *data,
59
size_t count, loff_t *off);
60
static ssize_t ipath_diag_write(struct file *fp, const char __user *data,
61
size_t count, loff_t *off);
62
63
static const struct file_operations diag_file_ops = {
64
.owner = THIS_MODULE,
65
.write = ipath_diag_write,
66
.read = ipath_diag_read,
67
.open = ipath_diag_open,
68
.release = ipath_diag_release,
69
.llseek = default_llseek,
70
};
71
72
static ssize_t ipath_diagpkt_write(struct file *fp,
73
const char __user *data,
74
size_t count, loff_t *off);
75
76
static const struct file_operations diagpkt_file_ops = {
77
.owner = THIS_MODULE,
78
.write = ipath_diagpkt_write,
79
.llseek = noop_llseek,
80
};
81
82
static atomic_t diagpkt_count = ATOMIC_INIT(0);
83
static struct cdev *diagpkt_cdev;
84
static struct device *diagpkt_dev;
85
86
int ipath_diag_add(struct ipath_devdata *dd)
87
{
88
char name[16];
89
int ret = 0;
90
91
if (atomic_inc_return(&diagpkt_count) == 1) {
92
ret = ipath_cdev_init(IPATH_DIAGPKT_MINOR,
93
"ipath_diagpkt", &diagpkt_file_ops,
94
&diagpkt_cdev, &diagpkt_dev);
95
96
if (ret) {
97
ipath_dev_err(dd, "Couldn't create ipath_diagpkt "
98
"device: %d", ret);
99
goto done;
100
}
101
}
102
103
snprintf(name, sizeof(name), "ipath_diag%d", dd->ipath_unit);
104
105
ret = ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name,
106
&diag_file_ops, &dd->diag_cdev,
107
&dd->diag_dev);
108
if (ret)
109
ipath_dev_err(dd, "Couldn't create %s device: %d",
110
name, ret);
111
112
done:
113
return ret;
114
}
115
116
void ipath_diag_remove(struct ipath_devdata *dd)
117
{
118
if (atomic_dec_and_test(&diagpkt_count))
119
ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_dev);
120
121
ipath_cdev_cleanup(&dd->diag_cdev, &dd->diag_dev);
122
}
123
124
/**
125
* ipath_read_umem64 - read a 64-bit quantity from the chip into user space
126
* @dd: the infinipath device
127
* @uaddr: the location to store the data in user memory
128
* @caddr: the source chip address (full pointer, not offset)
129
* @count: number of bytes to copy (multiple of 32 bits)
130
*
131
* This function also localizes all chip memory accesses.
132
* The copy should be written such that we read full cacheline packets
133
* from the chip. This is usually used for a single qword
134
*
135
* NOTE: This assumes the chip address is 64-bit aligned.
136
*/
137
static int ipath_read_umem64(struct ipath_devdata *dd, void __user *uaddr,
138
const void __iomem *caddr, size_t count)
139
{
140
const u64 __iomem *reg_addr = caddr;
141
const u64 __iomem *reg_end = reg_addr + (count / sizeof(u64));
142
int ret;
143
144
/* not very efficient, but it works for now */
145
if (reg_addr < dd->ipath_kregbase || reg_end > dd->ipath_kregend) {
146
ret = -EINVAL;
147
goto bail;
148
}
149
while (reg_addr < reg_end) {
150
u64 data = readq(reg_addr);
151
if (copy_to_user(uaddr, &data, sizeof(u64))) {
152
ret = -EFAULT;
153
goto bail;
154
}
155
reg_addr++;
156
uaddr += sizeof(u64);
157
}
158
ret = 0;
159
bail:
160
return ret;
161
}
162
163
/**
164
* ipath_write_umem64 - write a 64-bit quantity to the chip from user space
165
* @dd: the infinipath device
166
* @caddr: the destination chip address (full pointer, not offset)
167
* @uaddr: the source of the data in user memory
168
* @count: the number of bytes to copy (multiple of 32 bits)
169
*
170
* This is usually used for a single qword
171
* NOTE: This assumes the chip address is 64-bit aligned.
172
*/
173
174
static int ipath_write_umem64(struct ipath_devdata *dd, void __iomem *caddr,
175
const void __user *uaddr, size_t count)
176
{
177
u64 __iomem *reg_addr = caddr;
178
const u64 __iomem *reg_end = reg_addr + (count / sizeof(u64));
179
int ret;
180
181
/* not very efficient, but it works for now */
182
if (reg_addr < dd->ipath_kregbase || reg_end > dd->ipath_kregend) {
183
ret = -EINVAL;
184
goto bail;
185
}
186
while (reg_addr < reg_end) {
187
u64 data;
188
if (copy_from_user(&data, uaddr, sizeof(data))) {
189
ret = -EFAULT;
190
goto bail;
191
}
192
writeq(data, reg_addr);
193
194
reg_addr++;
195
uaddr += sizeof(u64);
196
}
197
ret = 0;
198
bail:
199
return ret;
200
}
201
202
/**
203
* ipath_read_umem32 - read a 32-bit quantity from the chip into user space
204
* @dd: the infinipath device
205
* @uaddr: the location to store the data in user memory
206
* @caddr: the source chip address (full pointer, not offset)
207
* @count: number of bytes to copy
208
*
209
* read 32 bit values, not 64 bit; for memories that only
210
* support 32 bit reads; usually a single dword.
211
*/
212
static int ipath_read_umem32(struct ipath_devdata *dd, void __user *uaddr,
213
const void __iomem *caddr, size_t count)
214
{
215
const u32 __iomem *reg_addr = caddr;
216
const u32 __iomem *reg_end = reg_addr + (count / sizeof(u32));
217
int ret;
218
219
if (reg_addr < (u32 __iomem *) dd->ipath_kregbase ||
220
reg_end > (u32 __iomem *) dd->ipath_kregend) {
221
ret = -EINVAL;
222
goto bail;
223
}
224
/* not very efficient, but it works for now */
225
while (reg_addr < reg_end) {
226
u32 data = readl(reg_addr);
227
if (copy_to_user(uaddr, &data, sizeof(data))) {
228
ret = -EFAULT;
229
goto bail;
230
}
231
232
reg_addr++;
233
uaddr += sizeof(u32);
234
235
}
236
ret = 0;
237
bail:
238
return ret;
239
}
240
241
/**
242
* ipath_write_umem32 - write a 32-bit quantity to the chip from user space
243
* @dd: the infinipath device
244
* @caddr: the destination chip address (full pointer, not offset)
245
* @uaddr: the source of the data in user memory
246
* @count: number of bytes to copy
247
*
248
* write 32 bit values, not 64 bit; for memories that only
249
* support 32 bit write; usually a single dword.
250
*/
251
252
static int ipath_write_umem32(struct ipath_devdata *dd, void __iomem *caddr,
253
const void __user *uaddr, size_t count)
254
{
255
u32 __iomem *reg_addr = caddr;
256
const u32 __iomem *reg_end = reg_addr + (count / sizeof(u32));
257
int ret;
258
259
if (reg_addr < (u32 __iomem *) dd->ipath_kregbase ||
260
reg_end > (u32 __iomem *) dd->ipath_kregend) {
261
ret = -EINVAL;
262
goto bail;
263
}
264
while (reg_addr < reg_end) {
265
u32 data;
266
if (copy_from_user(&data, uaddr, sizeof(data))) {
267
ret = -EFAULT;
268
goto bail;
269
}
270
writel(data, reg_addr);
271
272
reg_addr++;
273
uaddr += sizeof(u32);
274
}
275
ret = 0;
276
bail:
277
return ret;
278
}
279
280
static int ipath_diag_open(struct inode *in, struct file *fp)
281
{
282
int unit = iminor(in) - IPATH_DIAG_MINOR_BASE;
283
struct ipath_devdata *dd;
284
int ret;
285
286
mutex_lock(&ipath_mutex);
287
288
if (ipath_diag_inuse) {
289
ret = -EBUSY;
290
goto bail;
291
}
292
293
dd = ipath_lookup(unit);
294
295
if (dd == NULL || !(dd->ipath_flags & IPATH_PRESENT) ||
296
!dd->ipath_kregbase) {
297
ret = -ENODEV;
298
goto bail;
299
}
300
301
fp->private_data = dd;
302
ipath_diag_inuse = -2;
303
diag_set_link = 0;
304
ret = 0;
305
306
/* Only expose a way to reset the device if we
307
make it into diag mode. */
308
ipath_expose_reset(&dd->pcidev->dev);
309
310
bail:
311
mutex_unlock(&ipath_mutex);
312
313
return ret;
314
}
315
316
/**
317
* ipath_diagpkt_write - write an IB packet
318
* @fp: the diag data device file pointer
319
* @data: ipath_diag_pkt structure saying where to get the packet
320
* @count: size of data to write
321
* @off: unused by this code
322
*/
323
static ssize_t ipath_diagpkt_write(struct file *fp,
324
const char __user *data,
325
size_t count, loff_t *off)
326
{
327
u32 __iomem *piobuf;
328
u32 plen, clen, pbufn;
329
struct ipath_diag_pkt odp;
330
struct ipath_diag_xpkt dp;
331
u32 *tmpbuf = NULL;
332
struct ipath_devdata *dd;
333
ssize_t ret = 0;
334
u64 val;
335
u32 l_state, lt_state; /* LinkState, LinkTrainingState */
336
337
if (count < sizeof(odp)) {
338
ret = -EINVAL;
339
goto bail;
340
}
341
342
if (count == sizeof(dp)) {
343
if (copy_from_user(&dp, data, sizeof(dp))) {
344
ret = -EFAULT;
345
goto bail;
346
}
347
} else if (copy_from_user(&odp, data, sizeof(odp))) {
348
ret = -EFAULT;
349
goto bail;
350
}
351
352
/*
353
* Due to padding/alignment issues (lessened with new struct)
354
* the old and new structs are the same length. We need to
355
* disambiguate them, which we can do because odp.len has never
356
* been less than the total of LRH+BTH+DETH so far, while
357
* dp.unit (same offset) unit is unlikely to get that high.
358
* Similarly, dp.data, the pointer to user at the same offset
359
* as odp.unit, is almost certainly at least one (512byte)page
360
* "above" NULL. The if-block below can be omitted if compatibility
361
* between a new driver and older diagnostic code is unimportant.
362
* compatibility the other direction (new diags, old driver) is
363
* handled in the diagnostic code, with a warning.
364
*/
365
if (dp.unit >= 20 && dp.data < 512) {
366
/* very probable version mismatch. Fix it up */
367
memcpy(&odp, &dp, sizeof(odp));
368
/* We got a legacy dp, copy elements to dp */
369
dp.unit = odp.unit;
370
dp.data = odp.data;
371
dp.len = odp.len;
372
dp.pbc_wd = 0; /* Indicate we need to compute PBC wd */
373
}
374
375
/* send count must be an exact number of dwords */
376
if (dp.len & 3) {
377
ret = -EINVAL;
378
goto bail;
379
}
380
381
clen = dp.len >> 2;
382
383
dd = ipath_lookup(dp.unit);
384
if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
385
!dd->ipath_kregbase) {
386
ipath_cdbg(VERBOSE, "illegal unit %u for diag data send\n",
387
dp.unit);
388
ret = -ENODEV;
389
goto bail;
390
}
391
392
if (ipath_diag_inuse && !diag_set_link &&
393
!(dd->ipath_flags & IPATH_LINKACTIVE)) {
394
diag_set_link = 1;
395
ipath_cdbg(VERBOSE, "Trying to set to set link active for "
396
"diag pkt\n");
397
ipath_set_linkstate(dd, IPATH_IB_LINKARM);
398
ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
399
}
400
401
if (!(dd->ipath_flags & IPATH_INITTED)) {
402
/* no hardware, freeze, etc. */
403
ipath_cdbg(VERBOSE, "unit %u not usable\n", dd->ipath_unit);
404
ret = -ENODEV;
405
goto bail;
406
}
407
/*
408
* Want to skip check for l_state if using custom PBC,
409
* because we might be trying to force an SM packet out.
410
* first-cut, skip _all_ state checking in that case.
411
*/
412
val = ipath_ib_state(dd, dd->ipath_lastibcstat);
413
lt_state = ipath_ib_linktrstate(dd, dd->ipath_lastibcstat);
414
l_state = ipath_ib_linkstate(dd, dd->ipath_lastibcstat);
415
if (!dp.pbc_wd && (lt_state != INFINIPATH_IBCS_LT_STATE_LINKUP ||
416
(val != dd->ib_init && val != dd->ib_arm &&
417
val != dd->ib_active))) {
418
ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n",
419
dd->ipath_unit, (unsigned long long) val);
420
ret = -EINVAL;
421
goto bail;
422
}
423
424
/* need total length before first word written */
425
/* +1 word is for the qword padding */
426
plen = sizeof(u32) + dp.len;
427
428
if ((plen + 4) > dd->ipath_ibmaxlen) {
429
ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
430
plen - 4, dd->ipath_ibmaxlen);
431
ret = -EINVAL;
432
goto bail; /* before writing pbc */
433
}
434
tmpbuf = vmalloc(plen);
435
if (!tmpbuf) {
436
dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
437
"failing\n");
438
ret = -ENOMEM;
439
goto bail;
440
}
441
442
if (copy_from_user(tmpbuf,
443
(const void __user *) (unsigned long) dp.data,
444
dp.len)) {
445
ret = -EFAULT;
446
goto bail;
447
}
448
449
plen >>= 2; /* in dwords */
450
451
piobuf = ipath_getpiobuf(dd, plen, &pbufn);
452
if (!piobuf) {
453
ipath_cdbg(VERBOSE, "No PIO buffers avail unit for %u\n",
454
dd->ipath_unit);
455
ret = -EBUSY;
456
goto bail;
457
}
458
/* disarm it just to be extra sure */
459
ipath_disarm_piobufs(dd, pbufn, 1);
460
461
if (ipath_debug & __IPATH_PKTDBG)
462
ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n",
463
dd->ipath_unit, plen - 1, pbufn);
464
465
if (dp.pbc_wd == 0)
466
dp.pbc_wd = plen;
467
writeq(dp.pbc_wd, piobuf);
468
/*
469
* Copy all by the trigger word, then flush, so it's written
470
* to chip before trigger word, then write trigger word, then
471
* flush again, so packet is sent.
472
*/
473
if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
474
ipath_flush_wc();
475
__iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
476
ipath_flush_wc();
477
__raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
478
} else
479
__iowrite32_copy(piobuf + 2, tmpbuf, clen);
480
481
ipath_flush_wc();
482
483
ret = sizeof(dp);
484
485
bail:
486
vfree(tmpbuf);
487
return ret;
488
}
489
490
static int ipath_diag_release(struct inode *in, struct file *fp)
491
{
492
mutex_lock(&ipath_mutex);
493
ipath_diag_inuse = 0;
494
fp->private_data = NULL;
495
mutex_unlock(&ipath_mutex);
496
return 0;
497
}
498
499
static ssize_t ipath_diag_read(struct file *fp, char __user *data,
500
size_t count, loff_t *off)
501
{
502
struct ipath_devdata *dd = fp->private_data;
503
void __iomem *kreg_base;
504
ssize_t ret;
505
506
kreg_base = dd->ipath_kregbase;
507
508
if (count == 0)
509
ret = 0;
510
else if ((count % 4) || (*off % 4))
511
/* address or length is not 32-bit aligned, hence invalid */
512
ret = -EINVAL;
513
else if (ipath_diag_inuse < 1 && (*off || count != 8))
514
ret = -EINVAL; /* prevent cat /dev/ipath_diag* */
515
else if ((count % 8) || (*off % 8))
516
/* address or length not 64-bit aligned; do 32-bit reads */
517
ret = ipath_read_umem32(dd, data, kreg_base + *off, count);
518
else
519
ret = ipath_read_umem64(dd, data, kreg_base + *off, count);
520
521
if (ret >= 0) {
522
*off += count;
523
ret = count;
524
if (ipath_diag_inuse == -2)
525
ipath_diag_inuse++;
526
}
527
528
return ret;
529
}
530
531
static ssize_t ipath_diag_write(struct file *fp, const char __user *data,
532
size_t count, loff_t *off)
533
{
534
struct ipath_devdata *dd = fp->private_data;
535
void __iomem *kreg_base;
536
ssize_t ret;
537
538
kreg_base = dd->ipath_kregbase;
539
540
if (count == 0)
541
ret = 0;
542
else if ((count % 4) || (*off % 4))
543
/* address or length is not 32-bit aligned, hence invalid */
544
ret = -EINVAL;
545
else if ((ipath_diag_inuse == -1 && (*off || count != 8)) ||
546
ipath_diag_inuse == -2) /* read qw off 0, write qw off 0 */
547
ret = -EINVAL; /* before any other write allowed */
548
else if ((count % 8) || (*off % 8))
549
/* address or length not 64-bit aligned; do 32-bit writes */
550
ret = ipath_write_umem32(dd, kreg_base + *off, data, count);
551
else
552
ret = ipath_write_umem64(dd, kreg_base + *off, data, count);
553
554
if (ret >= 0) {
555
*off += count;
556
ret = count;
557
if (ipath_diag_inuse == -1)
558
ipath_diag_inuse = 1; /* all read/write OK now */
559
}
560
561
return ret;
562
}
563
564