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