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 53int ipath_diag_inuse; 54static int diag_set_link; 55 56static int ipath_diag_open(struct inode *in, struct file *fp); 57static int ipath_diag_release(struct inode *in, struct file *fp); 58static ssize_t ipath_diag_read(struct file *fp, char __user *data, 59 size_t count, loff_t *off); 60static ssize_t ipath_diag_write(struct file *fp, const char __user *data, 61 size_t count, loff_t *off); 62 63static 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 71static ssize_t ipath_diagpkt_write(struct file *fp, 72 const char __user *data, 73 size_t count, loff_t *off); 74 75static const struct file_operations diagpkt_file_ops = { 76 .owner = THIS_MODULE, 77 .write = ipath_diagpkt_write, 78}; 79 80static atomic_t diagpkt_count = ATOMIC_INIT(0); 81static struct cdev *diagpkt_cdev; 82static struct device *diagpkt_dev; 83 84int 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 110done: 111 return ret; 112} 113 114void 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 */ 135static 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; 157bail: 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 172static 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; 196bail: 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 */ 210static 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; 235bail: 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 250static 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; 274bail: 275 return ret; 276} 277 278static 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 308bail: 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 */ 321static 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 483bail: 484 vfree(tmpbuf); 485 return ret; 486} 487 488static 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 497static 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 529static 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} 561