~ubuntu-branches/ubuntu/utopic/linux-ti-omap/utopic

« back to all changes in this revision

Viewing changes to drivers/infiniband/hw/ipath/ipath_diag.c

  • Committer: Bazaar Package Importer
  • Author(s): Amit Kucheria, Amit Kucheria
  • Date: 2010-03-10 02:28:15 UTC
  • Revision ID: james.westby@ubuntu.com-20100310022815-7sd3gwvn5kenaq33
Tags: 2.6.33-500.1
[ Amit Kucheria ]

* Initial release of a 2.6.33-based OMAP kernel
* UBUNTU: [Upstream] Fix omap 1-wire driver compilation
* UBUNTU: ubuntu: AppArmor -- update to mainline 2010-03-04

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
};
 
70
 
 
71
static ssize_t ipath_diagpkt_write(struct file *fp,
 
72
                                   const char __user *data,
 
73
                                   size_t count, loff_t *off);
 
74
 
 
75
static const struct file_operations diagpkt_file_ops = {
 
76
        .owner = THIS_MODULE,
 
77
        .write = ipath_diagpkt_write,
 
78
};
 
79
 
 
80
static atomic_t diagpkt_count = ATOMIC_INIT(0);
 
81
static struct cdev *diagpkt_cdev;
 
82
static struct device *diagpkt_dev;
 
83
 
 
84
int ipath_diag_add(struct ipath_devdata *dd)
 
85
{
 
86
        char name[16];
 
87
        int ret = 0;
 
88
 
 
89
        if (atomic_inc_return(&diagpkt_count) == 1) {
 
90
                ret = ipath_cdev_init(IPATH_DIAGPKT_MINOR,
 
91
                                      "ipath_diagpkt", &diagpkt_file_ops,
 
92
                                      &diagpkt_cdev, &diagpkt_dev);
 
93
 
 
94
                if (ret) {
 
95
                        ipath_dev_err(dd, "Couldn't create ipath_diagpkt "
 
96
                                      "device: %d", ret);
 
97
                        goto done;
 
98
                }
 
99
        }
 
100
 
 
101
        snprintf(name, sizeof(name), "ipath_diag%d", dd->ipath_unit);
 
102
 
 
103
        ret = ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name,
 
104
                              &diag_file_ops, &dd->diag_cdev,
 
105
                              &dd->diag_dev);
 
106
        if (ret)
 
107
                ipath_dev_err(dd, "Couldn't create %s device: %d",
 
108
                              name, ret);
 
109
 
 
110
done:
 
111
        return ret;
 
112
}
 
113
 
 
114
void ipath_diag_remove(struct ipath_devdata *dd)
 
115
{
 
116
        if (atomic_dec_and_test(&diagpkt_count))
 
117
                ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_dev);
 
118
 
 
119
        ipath_cdev_cleanup(&dd->diag_cdev, &dd->diag_dev);
 
120
}
 
121
 
 
122
/**
 
123
 * ipath_read_umem64 - read a 64-bit quantity from the chip into user space
 
124
 * @dd: the infinipath device
 
125
 * @uaddr: the location to store the data in user memory
 
126
 * @caddr: the source chip address (full pointer, not offset)
 
127
 * @count: number of bytes to copy (multiple of 32 bits)
 
128
 *
 
129
 * This function also localizes all chip memory accesses.
 
130
 * The copy should be written such that we read full cacheline packets
 
131
 * from the chip.  This is usually used for a single qword
 
132
 *
 
133
 * NOTE:  This assumes the chip address is 64-bit aligned.
 
134
 */
 
135
static int ipath_read_umem64(struct ipath_devdata *dd, void __user *uaddr,
 
136
                             const void __iomem *caddr, size_t count)
 
137
{
 
138
        const u64 __iomem *reg_addr = caddr;
 
139
        const u64 __iomem *reg_end = reg_addr + (count / sizeof(u64));
 
140
        int ret;
 
141
 
 
142
        /* not very efficient, but it works for now */
 
143
        if (reg_addr < dd->ipath_kregbase || reg_end > dd->ipath_kregend) {
 
144
                ret = -EINVAL;
 
145
                goto bail;
 
146
        }
 
147
        while (reg_addr < reg_end) {
 
148
                u64 data = readq(reg_addr);
 
149
                if (copy_to_user(uaddr, &data, sizeof(u64))) {
 
150
                        ret = -EFAULT;
 
151
                        goto bail;
 
152
                }
 
153
                reg_addr++;
 
154
                uaddr += sizeof(u64);
 
155
        }
 
156
        ret = 0;
 
157
bail:
 
158
        return ret;
 
159
}
 
160
 
 
161
/**
 
162
 * ipath_write_umem64 - write a 64-bit quantity to the chip from user space
 
163
 * @dd: the infinipath device
 
164
 * @caddr: the destination chip address (full pointer, not offset)
 
165
 * @uaddr: the source of the data in user memory
 
166
 * @count: the number of bytes to copy (multiple of 32 bits)
 
167
 *
 
168
 * This is usually used for a single qword
 
169
 * NOTE:  This assumes the chip address is 64-bit aligned.
 
170
 */
 
171
 
 
172
static int ipath_write_umem64(struct ipath_devdata *dd, void __iomem *caddr,
 
173
                              const void __user *uaddr, size_t count)
 
174
{
 
175
        u64 __iomem *reg_addr = caddr;
 
176
        const u64 __iomem *reg_end = reg_addr + (count / sizeof(u64));
 
177
        int ret;
 
178
 
 
179
        /* not very efficient, but it works for now */
 
180
        if (reg_addr < dd->ipath_kregbase || reg_end > dd->ipath_kregend) {
 
181
                ret = -EINVAL;
 
182
                goto bail;
 
183
        }
 
184
        while (reg_addr < reg_end) {
 
185
                u64 data;
 
186
                if (copy_from_user(&data, uaddr, sizeof(data))) {
 
187
                        ret = -EFAULT;
 
188
                        goto bail;
 
189
                }
 
190
                writeq(data, reg_addr);
 
191
 
 
192
                reg_addr++;
 
193
                uaddr += sizeof(u64);
 
194
        }
 
195
        ret = 0;
 
196
bail:
 
197
        return ret;
 
198
}
 
199
 
 
200
/**
 
201
 * ipath_read_umem32 - read a 32-bit quantity from the chip into user space
 
202
 * @dd: the infinipath device
 
203
 * @uaddr: the location to store the data in user memory
 
204
 * @caddr: the source chip address (full pointer, not offset)
 
205
 * @count: number of bytes to copy
 
206
 *
 
207
 * read 32 bit values, not 64 bit; for memories that only
 
208
 * support 32 bit reads; usually a single dword.
 
209
 */
 
210
static int ipath_read_umem32(struct ipath_devdata *dd, void __user *uaddr,
 
211
                             const void __iomem *caddr, size_t count)
 
212
{
 
213
        const u32 __iomem *reg_addr = caddr;
 
214
        const u32 __iomem *reg_end = reg_addr + (count / sizeof(u32));
 
215
        int ret;
 
216
 
 
217
        if (reg_addr < (u32 __iomem *) dd->ipath_kregbase ||
 
218
            reg_end > (u32 __iomem *) dd->ipath_kregend) {
 
219
                ret = -EINVAL;
 
220
                goto bail;
 
221
        }
 
222
        /* not very efficient, but it works for now */
 
223
        while (reg_addr < reg_end) {
 
224
                u32 data = readl(reg_addr);
 
225
                if (copy_to_user(uaddr, &data, sizeof(data))) {
 
226
                        ret = -EFAULT;
 
227
                        goto bail;
 
228
                }
 
229
 
 
230
                reg_addr++;
 
231
                uaddr += sizeof(u32);
 
232
 
 
233
        }
 
234
        ret = 0;
 
235
bail:
 
236
        return ret;
 
237
}
 
238
 
 
239
/**
 
240
 * ipath_write_umem32 - write a 32-bit quantity to the chip from user space
 
241
 * @dd: the infinipath device
 
242
 * @caddr: the destination chip address (full pointer, not offset)
 
243
 * @uaddr: the source of the data in user memory
 
244
 * @count: number of bytes to copy
 
245
 *
 
246
 * write 32 bit values, not 64 bit; for memories that only
 
247
 * support 32 bit write; usually a single dword.
 
248
 */
 
249
 
 
250
static int ipath_write_umem32(struct ipath_devdata *dd, void __iomem *caddr,
 
251
                              const void __user *uaddr, size_t count)
 
252
{
 
253
        u32 __iomem *reg_addr = caddr;
 
254
        const u32 __iomem *reg_end = reg_addr + (count / sizeof(u32));
 
255
        int ret;
 
256
 
 
257
        if (reg_addr < (u32 __iomem *) dd->ipath_kregbase ||
 
258
            reg_end > (u32 __iomem *) dd->ipath_kregend) {
 
259
                ret = -EINVAL;
 
260
                goto bail;
 
261
        }
 
262
        while (reg_addr < reg_end) {
 
263
                u32 data;
 
264
                if (copy_from_user(&data, uaddr, sizeof(data))) {
 
265
                        ret = -EFAULT;
 
266
                        goto bail;
 
267
                }
 
268
                writel(data, reg_addr);
 
269
 
 
270
                reg_addr++;
 
271
                uaddr += sizeof(u32);
 
272
        }
 
273
        ret = 0;
 
274
bail:
 
275
        return ret;
 
276
}
 
277
 
 
278
static int ipath_diag_open(struct inode *in, struct file *fp)
 
279
{
 
280
        int unit = iminor(in) - IPATH_DIAG_MINOR_BASE;
 
281
        struct ipath_devdata *dd;
 
282
        int ret;
 
283
 
 
284
        mutex_lock(&ipath_mutex);
 
285
 
 
286
        if (ipath_diag_inuse) {
 
287
                ret = -EBUSY;
 
288
                goto bail;
 
289
        }
 
290
 
 
291
        dd = ipath_lookup(unit);
 
292
 
 
293
        if (dd == NULL || !(dd->ipath_flags & IPATH_PRESENT) ||
 
294
            !dd->ipath_kregbase) {
 
295
                ret = -ENODEV;
 
296
                goto bail;
 
297
        }
 
298
 
 
299
        fp->private_data = dd;
 
300
        ipath_diag_inuse = -2;
 
301
        diag_set_link = 0;
 
302
        ret = 0;
 
303
 
 
304
        /* Only expose a way to reset the device if we
 
305
           make it into diag mode. */
 
306
        ipath_expose_reset(&dd->pcidev->dev);
 
307
 
 
308
bail:
 
309
        mutex_unlock(&ipath_mutex);
 
310
 
 
311
        return ret;
 
312
}
 
313
 
 
314
/**
 
315
 * ipath_diagpkt_write - write an IB packet
 
316
 * @fp: the diag data device file pointer
 
317
 * @data: ipath_diag_pkt structure saying where to get the packet
 
318
 * @count: size of data to write
 
319
 * @off: unused by this code
 
320
 */
 
321
static ssize_t ipath_diagpkt_write(struct file *fp,
 
322
                                   const char __user *data,
 
323
                                   size_t count, loff_t *off)
 
324
{
 
325
        u32 __iomem *piobuf;
 
326
        u32 plen, clen, pbufn;
 
327
        struct ipath_diag_pkt odp;
 
328
        struct ipath_diag_xpkt dp;
 
329
        u32 *tmpbuf = NULL;
 
330
        struct ipath_devdata *dd;
 
331
        ssize_t ret = 0;
 
332
        u64 val;
 
333
        u32 l_state, lt_state; /* LinkState, LinkTrainingState */
 
334
 
 
335
        if (count < sizeof(odp)) {
 
336
                ret = -EINVAL;
 
337
                goto bail;
 
338
        }
 
339
 
 
340
        if (count == sizeof(dp)) {
 
341
                if (copy_from_user(&dp, data, sizeof(dp))) {
 
342
                        ret = -EFAULT;
 
343
                        goto bail;
 
344
                }
 
345
        } else if (copy_from_user(&odp, data, sizeof(odp))) {
 
346
                ret = -EFAULT;
 
347
                goto bail;
 
348
        }
 
349
 
 
350
        /*
 
351
         * Due to padding/alignment issues (lessened with new struct)
 
352
         * the old and new structs are the same length. We need to
 
353
         * disambiguate them, which we can do because odp.len has never
 
354
         * been less than the total of LRH+BTH+DETH so far, while
 
355
         * dp.unit (same offset) unit is unlikely to get that high.
 
356
         * Similarly, dp.data, the pointer to user at the same offset
 
357
         * as odp.unit, is almost certainly at least one (512byte)page
 
358
         * "above" NULL. The if-block below can be omitted if compatibility
 
359
         * between a new driver and older diagnostic code is unimportant.
 
360
         * compatibility the other direction (new diags, old driver) is
 
361
         * handled in the diagnostic code, with a warning.
 
362
         */
 
363
        if (dp.unit >= 20 && dp.data < 512) {
 
364
                /* very probable version mismatch. Fix it up */
 
365
                memcpy(&odp, &dp, sizeof(odp));
 
366
                /* We got a legacy dp, copy elements to dp */
 
367
                dp.unit = odp.unit;
 
368
                dp.data = odp.data;
 
369
                dp.len = odp.len;
 
370
                dp.pbc_wd = 0; /* Indicate we need to compute PBC wd */
 
371
        }
 
372
 
 
373
        /* send count must be an exact number of dwords */
 
374
        if (dp.len & 3) {
 
375
                ret = -EINVAL;
 
376
                goto bail;
 
377
        }
 
378
 
 
379
        clen = dp.len >> 2;
 
380
 
 
381
        dd = ipath_lookup(dp.unit);
 
382
        if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
 
383
            !dd->ipath_kregbase) {
 
384
                ipath_cdbg(VERBOSE, "illegal unit %u for diag data send\n",
 
385
                           dp.unit);
 
386
                ret = -ENODEV;
 
387
                goto bail;
 
388
        }
 
389
 
 
390
        if (ipath_diag_inuse && !diag_set_link &&
 
391
            !(dd->ipath_flags & IPATH_LINKACTIVE)) {
 
392
                diag_set_link = 1;
 
393
                ipath_cdbg(VERBOSE, "Trying to set to set link active for "
 
394
                           "diag pkt\n");
 
395
                ipath_set_linkstate(dd, IPATH_IB_LINKARM);
 
396
                ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
 
397
        }
 
398
 
 
399
        if (!(dd->ipath_flags & IPATH_INITTED)) {
 
400
                /* no hardware, freeze, etc. */
 
401
                ipath_cdbg(VERBOSE, "unit %u not usable\n", dd->ipath_unit);
 
402
                ret = -ENODEV;
 
403
                goto bail;
 
404
        }
 
405
        /*
 
406
         * Want to skip check for l_state if using custom PBC,
 
407
         * because we might be trying to force an SM packet out.
 
408
         * first-cut, skip _all_ state checking in that case.
 
409
         */
 
410
        val = ipath_ib_state(dd, dd->ipath_lastibcstat);
 
411
        lt_state = ipath_ib_linktrstate(dd, dd->ipath_lastibcstat);
 
412
        l_state = ipath_ib_linkstate(dd, dd->ipath_lastibcstat);
 
413
        if (!dp.pbc_wd && (lt_state != INFINIPATH_IBCS_LT_STATE_LINKUP ||
 
414
            (val != dd->ib_init && val != dd->ib_arm &&
 
415
            val != dd->ib_active))) {
 
416
                ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n",
 
417
                           dd->ipath_unit, (unsigned long long) val);
 
418
                ret = -EINVAL;
 
419
                goto bail;
 
420
        }
 
421
 
 
422
        /* need total length before first word written */
 
423
        /* +1 word is for the qword padding */
 
424
        plen = sizeof(u32) + dp.len;
 
425
 
 
426
        if ((plen + 4) > dd->ipath_ibmaxlen) {
 
427
                ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
 
428
                          plen - 4, dd->ipath_ibmaxlen);
 
429
                ret = -EINVAL;
 
430
                goto bail;      /* before writing pbc */
 
431
        }
 
432
        tmpbuf = vmalloc(plen);
 
433
        if (!tmpbuf) {
 
434
                dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
 
435
                         "failing\n");
 
436
                ret = -ENOMEM;
 
437
                goto bail;
 
438
        }
 
439
 
 
440
        if (copy_from_user(tmpbuf,
 
441
                           (const void __user *) (unsigned long) dp.data,
 
442
                           dp.len)) {
 
443
                ret = -EFAULT;
 
444
                goto bail;
 
445
        }
 
446
 
 
447
        plen >>= 2;             /* in dwords */
 
448
 
 
449
        piobuf = ipath_getpiobuf(dd, plen, &pbufn);
 
450
        if (!piobuf) {
 
451
                ipath_cdbg(VERBOSE, "No PIO buffers avail unit for %u\n",
 
452
                           dd->ipath_unit);
 
453
                ret = -EBUSY;
 
454
                goto bail;
 
455
        }
 
456
        /* disarm it just to be extra sure */
 
457
        ipath_disarm_piobufs(dd, pbufn, 1);
 
458
 
 
459
        if (ipath_debug & __IPATH_PKTDBG)
 
460
                ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n",
 
461
                           dd->ipath_unit, plen - 1, pbufn);
 
462
 
 
463
        if (dp.pbc_wd == 0)
 
464
                dp.pbc_wd = plen;
 
465
        writeq(dp.pbc_wd, piobuf);
 
466
        /*
 
467
         * Copy all by the trigger word, then flush, so it's written
 
468
         * to chip before trigger word, then write trigger word, then
 
469
         * flush again, so packet is sent.
 
470
         */
 
471
        if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
 
472
                ipath_flush_wc();
 
473
                __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
 
474
                ipath_flush_wc();
 
475
                __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
 
476
        } else
 
477
                __iowrite32_copy(piobuf + 2, tmpbuf, clen);
 
478
 
 
479
        ipath_flush_wc();
 
480
 
 
481
        ret = sizeof(dp);
 
482
 
 
483
bail:
 
484
        vfree(tmpbuf);
 
485
        return ret;
 
486
}
 
487
 
 
488
static int ipath_diag_release(struct inode *in, struct file *fp)
 
489
{
 
490
        mutex_lock(&ipath_mutex);
 
491
        ipath_diag_inuse = 0;
 
492
        fp->private_data = NULL;
 
493
        mutex_unlock(&ipath_mutex);
 
494
        return 0;
 
495
}
 
496
 
 
497
static ssize_t ipath_diag_read(struct file *fp, char __user *data,
 
498
                               size_t count, loff_t *off)
 
499
{
 
500
        struct ipath_devdata *dd = fp->private_data;
 
501
        void __iomem *kreg_base;
 
502
        ssize_t ret;
 
503
 
 
504
        kreg_base = dd->ipath_kregbase;
 
505
 
 
506
        if (count == 0)
 
507
                ret = 0;
 
508
        else if ((count % 4) || (*off % 4))
 
509
                /* address or length is not 32-bit aligned, hence invalid */
 
510
                ret = -EINVAL;
 
511
        else if (ipath_diag_inuse < 1 && (*off || count != 8))
 
512
                ret = -EINVAL;  /* prevent cat /dev/ipath_diag* */
 
513
        else if ((count % 8) || (*off % 8))
 
514
                /* address or length not 64-bit aligned; do 32-bit reads */
 
515
                ret = ipath_read_umem32(dd, data, kreg_base + *off, count);
 
516
        else
 
517
                ret = ipath_read_umem64(dd, data, kreg_base + *off, count);
 
518
 
 
519
        if (ret >= 0) {
 
520
                *off += count;
 
521
                ret = count;
 
522
                if (ipath_diag_inuse == -2)
 
523
                        ipath_diag_inuse++;
 
524
        }
 
525
 
 
526
        return ret;
 
527
}
 
528
 
 
529
static ssize_t ipath_diag_write(struct file *fp, const char __user *data,
 
530
                                size_t count, loff_t *off)
 
531
{
 
532
        struct ipath_devdata *dd = fp->private_data;
 
533
        void __iomem *kreg_base;
 
534
        ssize_t ret;
 
535
 
 
536
        kreg_base = dd->ipath_kregbase;
 
537
 
 
538
        if (count == 0)
 
539
                ret = 0;
 
540
        else if ((count % 4) || (*off % 4))
 
541
                /* address or length is not 32-bit aligned, hence invalid */
 
542
                ret = -EINVAL;
 
543
        else if ((ipath_diag_inuse == -1 && (*off || count != 8)) ||
 
544
                 ipath_diag_inuse == -2)  /* read qw off 0, write qw off 0 */
 
545
                ret = -EINVAL;  /* before any other write allowed */
 
546
        else if ((count % 8) || (*off % 8))
 
547
                /* address or length not 64-bit aligned; do 32-bit writes */
 
548
                ret = ipath_write_umem32(dd, kreg_base + *off, data, count);
 
549
        else
 
550
                ret = ipath_write_umem64(dd, kreg_base + *off, data, count);
 
551
 
 
552
        if (ret >= 0) {
 
553
                *off += count;
 
554
                ret = count;
 
555
                if (ipath_diag_inuse == -1)
 
556
                        ipath_diag_inuse = 1; /* all read/write OK now */
 
557
        }
 
558
 
 
559
        return ret;
 
560
}