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