1 /* 2 * This file is provided under a dual BSD/GPLv2 license. When using or 3 * redistributing this file, you may do so under either license. 4 * 5 * GPL LICENSE SUMMARY 6 * 7 * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of version 2 of the GNU General Public License as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * BSD LICENSE 19 * 20 * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 26 * * Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * * Redistributions in binary form must reproduce the above copy 29 * notice, this list of conditions and the following disclaimer in 30 * the documentation and/or other materials provided with the 31 * distribution. 32 * * Neither the name of Intel Corporation nor the names of its 33 * contributors may be used to endorse or promote products derived 34 * from this software without specific prior written permission. 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 37 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 38 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 39 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 40 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 43 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 44 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 45 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 46 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 47 * 48 * PCIe NTB Debugging Tool Linux driver 49 * 50 * Contact Information: 51 * Allen Hubbe <Allen.Hubbe@emc.com> 52 */ 53 54 /* 55 * How to use this tool, by example. 56 * 57 * Assuming $DBG_DIR is something like: 58 * '/sys/kernel/debug/ntb_tool/0000:00:03.0' 59 * 60 * Eg: check if clearing the doorbell mask generates an interrupt. 61 * 62 * # Check the link status 63 * root@self# cat $DBG_DIR/link 64 * 65 * # Block until the link is up 66 * root@self# echo Y > $DBG_DIR/link_event 67 * 68 * # Set the doorbell mask 69 * root@self# echo 's 1' > $DBG_DIR/mask 70 * 71 * # Ring the doorbell from the peer 72 * root@peer# echo 's 1' > $DBG_DIR/peer_db 73 * 74 * # Clear the doorbell mask 75 * root@self# echo 'c 1' > $DBG_DIR/mask 76 * 77 * Observe debugging output in dmesg or your console. You should see a 78 * doorbell event triggered by clearing the mask. If not, this may indicate an 79 * issue with the hardware that needs to be worked around in the driver. 80 * 81 * Eg: read and write scratchpad registers 82 * 83 * root@peer# echo '0 0x01010101 1 0x7f7f7f7f' > $DBG_DIR/peer_spad 84 * 85 * root@self# cat $DBG_DIR/spad 86 * 87 * Observe that spad 0 and 1 have the values set by the peer. 88 * 89 * # Check the memory window translation info 90 * cat $DBG_DIR/peer_trans0 91 * 92 * # Setup a 16k memory window buffer 93 * echo 16384 > $DBG_DIR/peer_trans0 94 * 95 */ 96 97 #include <linux/init.h> 98 #include <linux/kernel.h> 99 #include <linux/module.h> 100 101 #include <linux/debugfs.h> 102 #include <linux/dma-mapping.h> 103 #include <linux/pci.h> 104 #include <linux/slab.h> 105 #include <linux/uaccess.h> 106 107 #include <linux/ntb.h> 108 109 #define DRIVER_NAME "ntb_tool" 110 #define DRIVER_DESCRIPTION "PCIe NTB Debugging Tool" 111 112 #define DRIVER_LICENSE "Dual BSD/GPL" 113 #define DRIVER_VERSION "1.0" 114 #define DRIVER_RELDATE "22 April 2015" 115 #define DRIVER_AUTHOR "Allen Hubbe <Allen.Hubbe@emc.com>" 116 117 MODULE_LICENSE(DRIVER_LICENSE); 118 MODULE_VERSION(DRIVER_VERSION); 119 MODULE_AUTHOR(DRIVER_AUTHOR); 120 MODULE_DESCRIPTION(DRIVER_DESCRIPTION); 121 122 /* It is rare to have hadrware with greater than six MWs */ 123 #define MAX_MWS 6 124 /* Only two-ports devices are supported */ 125 #define PIDX NTB_DEF_PEER_IDX 126 127 static struct dentry *tool_dbgfs; 128 129 struct tool_mw { 130 int idx; 131 struct tool_ctx *tc; 132 resource_size_t win_size; 133 resource_size_t size; 134 u8 __iomem *local; 135 u8 *peer; 136 dma_addr_t peer_dma; 137 struct dentry *peer_dbg_file; 138 }; 139 140 struct tool_ctx { 141 struct ntb_dev *ntb; 142 struct dentry *dbgfs; 143 wait_queue_head_t link_wq; 144 int mw_count; 145 struct tool_mw mws[MAX_MWS]; 146 }; 147 148 #define SPAD_FNAME_SIZE 0x10 149 #define INT_PTR(x) ((void *)(unsigned long)x) 150 #define PTR_INT(x) ((int)(unsigned long)x) 151 152 #define TOOL_FOPS_RDWR(__name, __read, __write) \ 153 const struct file_operations __name = { \ 154 .owner = THIS_MODULE, \ 155 .open = simple_open, \ 156 .read = __read, \ 157 .write = __write, \ 158 } 159 160 static void tool_link_event(void *ctx) 161 { 162 struct tool_ctx *tc = ctx; 163 enum ntb_speed speed; 164 enum ntb_width width; 165 int up; 166 167 up = ntb_link_is_up(tc->ntb, &speed, &width); 168 169 dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n", 170 up ? "up" : "down", speed, width); 171 172 wake_up(&tc->link_wq); 173 } 174 175 static void tool_db_event(void *ctx, int vec) 176 { 177 struct tool_ctx *tc = ctx; 178 u64 db_bits, db_mask; 179 180 db_mask = ntb_db_vector_mask(tc->ntb, vec); 181 db_bits = ntb_db_read(tc->ntb); 182 183 dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n", 184 vec, db_mask, db_bits); 185 } 186 187 static const struct ntb_ctx_ops tool_ops = { 188 .link_event = tool_link_event, 189 .db_event = tool_db_event, 190 }; 191 192 static ssize_t tool_dbfn_read(struct tool_ctx *tc, char __user *ubuf, 193 size_t size, loff_t *offp, 194 u64 (*db_read_fn)(struct ntb_dev *)) 195 { 196 size_t buf_size; 197 char *buf; 198 ssize_t pos, rc; 199 200 if (!db_read_fn) 201 return -EINVAL; 202 203 buf_size = min_t(size_t, size, 0x20); 204 205 buf = kmalloc(buf_size, GFP_KERNEL); 206 if (!buf) 207 return -ENOMEM; 208 209 pos = scnprintf(buf, buf_size, "%#llx\n", 210 db_read_fn(tc->ntb)); 211 212 rc = simple_read_from_buffer(ubuf, size, offp, buf, pos); 213 214 kfree(buf); 215 216 return rc; 217 } 218 219 static ssize_t tool_dbfn_write(struct tool_ctx *tc, 220 const char __user *ubuf, 221 size_t size, loff_t *offp, 222 int (*db_set_fn)(struct ntb_dev *, u64), 223 int (*db_clear_fn)(struct ntb_dev *, u64)) 224 { 225 u64 db_bits; 226 char *buf, cmd; 227 ssize_t rc; 228 int n; 229 230 buf = kmalloc(size + 1, GFP_KERNEL); 231 if (!buf) 232 return -ENOMEM; 233 234 rc = simple_write_to_buffer(buf, size, offp, ubuf, size); 235 if (rc < 0) { 236 kfree(buf); 237 return rc; 238 } 239 240 buf[size] = 0; 241 242 n = sscanf(buf, "%c %lli", &cmd, &db_bits); 243 244 kfree(buf); 245 246 if (n != 2) { 247 rc = -EINVAL; 248 } else if (cmd == 's') { 249 if (!db_set_fn) 250 rc = -EINVAL; 251 else 252 rc = db_set_fn(tc->ntb, db_bits); 253 } else if (cmd == 'c') { 254 if (!db_clear_fn) 255 rc = -EINVAL; 256 else 257 rc = db_clear_fn(tc->ntb, db_bits); 258 } else { 259 rc = -EINVAL; 260 } 261 262 return rc ? : size; 263 } 264 265 static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf, 266 size_t size, loff_t *offp, 267 u32 (*spad_read_fn)(struct ntb_dev *, int)) 268 { 269 size_t buf_size; 270 char *buf; 271 ssize_t pos, rc; 272 int i, spad_count; 273 274 if (!spad_read_fn) 275 return -EINVAL; 276 277 spad_count = ntb_spad_count(tc->ntb); 278 279 /* 280 * We multiply the number of spads by 15 to get the buffer size 281 * this is from 3 for the %d, 10 for the largest hex value 282 * (0x00000000) and 2 for the tab and line feed. 283 */ 284 buf_size = min_t(size_t, size, spad_count * 15); 285 286 buf = kmalloc(buf_size, GFP_KERNEL); 287 if (!buf) 288 return -ENOMEM; 289 290 pos = 0; 291 292 for (i = 0; i < spad_count; ++i) { 293 pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n", 294 i, spad_read_fn(tc->ntb, i)); 295 } 296 297 rc = simple_read_from_buffer(ubuf, size, offp, buf, pos); 298 299 kfree(buf); 300 301 return rc; 302 } 303 304 static ssize_t tool_spadfn_write(struct tool_ctx *tc, 305 const char __user *ubuf, 306 size_t size, loff_t *offp, 307 int (*spad_write_fn)(struct ntb_dev *, 308 int, u32)) 309 { 310 int spad_idx; 311 u32 spad_val; 312 char *buf, *buf_ptr; 313 int pos, n; 314 ssize_t rc; 315 316 if (!spad_write_fn) { 317 dev_dbg(&tc->ntb->dev, "no spad write fn\n"); 318 return -EINVAL; 319 } 320 321 buf = kmalloc(size + 1, GFP_KERNEL); 322 if (!buf) 323 return -ENOMEM; 324 325 rc = simple_write_to_buffer(buf, size, offp, ubuf, size); 326 if (rc < 0) { 327 kfree(buf); 328 return rc; 329 } 330 331 buf[size] = 0; 332 buf_ptr = buf; 333 n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos); 334 while (n == 2) { 335 buf_ptr += pos; 336 rc = spad_write_fn(tc->ntb, spad_idx, spad_val); 337 if (rc) 338 break; 339 340 n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos); 341 } 342 343 if (n < 0) 344 rc = n; 345 346 kfree(buf); 347 348 return rc ? : size; 349 } 350 351 static ssize_t tool_db_read(struct file *filep, char __user *ubuf, 352 size_t size, loff_t *offp) 353 { 354 struct tool_ctx *tc = filep->private_data; 355 356 return tool_dbfn_read(tc, ubuf, size, offp, 357 tc->ntb->ops->db_read); 358 } 359 360 static ssize_t tool_db_write(struct file *filep, const char __user *ubuf, 361 size_t size, loff_t *offp) 362 { 363 struct tool_ctx *tc = filep->private_data; 364 365 return tool_dbfn_write(tc, ubuf, size, offp, 366 tc->ntb->ops->db_set, 367 tc->ntb->ops->db_clear); 368 } 369 370 static TOOL_FOPS_RDWR(tool_db_fops, 371 tool_db_read, 372 tool_db_write); 373 374 static ssize_t tool_mask_read(struct file *filep, char __user *ubuf, 375 size_t size, loff_t *offp) 376 { 377 struct tool_ctx *tc = filep->private_data; 378 379 return tool_dbfn_read(tc, ubuf, size, offp, 380 tc->ntb->ops->db_read_mask); 381 } 382 383 static ssize_t tool_mask_write(struct file *filep, const char __user *ubuf, 384 size_t size, loff_t *offp) 385 { 386 struct tool_ctx *tc = filep->private_data; 387 388 return tool_dbfn_write(tc, ubuf, size, offp, 389 tc->ntb->ops->db_set_mask, 390 tc->ntb->ops->db_clear_mask); 391 } 392 393 static TOOL_FOPS_RDWR(tool_mask_fops, 394 tool_mask_read, 395 tool_mask_write); 396 397 static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf, 398 size_t size, loff_t *offp) 399 { 400 struct tool_ctx *tc = filep->private_data; 401 402 return tool_dbfn_read(tc, ubuf, size, offp, 403 tc->ntb->ops->peer_db_read); 404 } 405 406 static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf, 407 size_t size, loff_t *offp) 408 { 409 struct tool_ctx *tc = filep->private_data; 410 411 return tool_dbfn_write(tc, ubuf, size, offp, 412 tc->ntb->ops->peer_db_set, 413 tc->ntb->ops->peer_db_clear); 414 } 415 416 static TOOL_FOPS_RDWR(tool_peer_db_fops, 417 tool_peer_db_read, 418 tool_peer_db_write); 419 420 static ssize_t tool_peer_mask_read(struct file *filep, char __user *ubuf, 421 size_t size, loff_t *offp) 422 { 423 struct tool_ctx *tc = filep->private_data; 424 425 return tool_dbfn_read(tc, ubuf, size, offp, 426 tc->ntb->ops->peer_db_read_mask); 427 } 428 429 static ssize_t tool_peer_mask_write(struct file *filep, const char __user *ubuf, 430 size_t size, loff_t *offp) 431 { 432 struct tool_ctx *tc = filep->private_data; 433 434 return tool_dbfn_write(tc, ubuf, size, offp, 435 tc->ntb->ops->peer_db_set_mask, 436 tc->ntb->ops->peer_db_clear_mask); 437 } 438 439 static TOOL_FOPS_RDWR(tool_peer_mask_fops, 440 tool_peer_mask_read, 441 tool_peer_mask_write); 442 443 static ssize_t tool_spad_read(struct file *filep, char __user *ubuf, 444 size_t size, loff_t *offp) 445 { 446 struct tool_ctx *tc = filep->private_data; 447 448 return tool_spadfn_read(tc, ubuf, size, offp, 449 tc->ntb->ops->spad_read); 450 } 451 452 static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf, 453 size_t size, loff_t *offp) 454 { 455 struct tool_ctx *tc = filep->private_data; 456 457 return tool_spadfn_write(tc, ubuf, size, offp, 458 tc->ntb->ops->spad_write); 459 } 460 461 static TOOL_FOPS_RDWR(tool_spad_fops, 462 tool_spad_read, 463 tool_spad_write); 464 465 static u32 ntb_tool_peer_spad_read(struct ntb_dev *ntb, int sidx) 466 { 467 return ntb_peer_spad_read(ntb, PIDX, sidx); 468 } 469 470 static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf, 471 size_t size, loff_t *offp) 472 { 473 struct tool_ctx *tc = filep->private_data; 474 475 return tool_spadfn_read(tc, ubuf, size, offp, ntb_tool_peer_spad_read); 476 } 477 478 static int ntb_tool_peer_spad_write(struct ntb_dev *ntb, int sidx, u32 val) 479 { 480 return ntb_peer_spad_write(ntb, PIDX, sidx, val); 481 } 482 483 static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf, 484 size_t size, loff_t *offp) 485 { 486 struct tool_ctx *tc = filep->private_data; 487 488 return tool_spadfn_write(tc, ubuf, size, offp, 489 ntb_tool_peer_spad_write); 490 } 491 492 static TOOL_FOPS_RDWR(tool_peer_spad_fops, 493 tool_peer_spad_read, 494 tool_peer_spad_write); 495 496 static ssize_t tool_link_read(struct file *filep, char __user *ubuf, 497 size_t size, loff_t *offp) 498 { 499 struct tool_ctx *tc = filep->private_data; 500 char buf[3]; 501 502 buf[0] = ntb_link_is_up(tc->ntb, NULL, NULL) ? 'Y' : 'N'; 503 buf[1] = '\n'; 504 buf[2] = '\0'; 505 506 return simple_read_from_buffer(ubuf, size, offp, buf, 2); 507 } 508 509 static ssize_t tool_link_write(struct file *filep, const char __user *ubuf, 510 size_t size, loff_t *offp) 511 { 512 struct tool_ctx *tc = filep->private_data; 513 char buf[32]; 514 size_t buf_size; 515 bool val; 516 int rc; 517 518 buf_size = min(size, (sizeof(buf) - 1)); 519 if (copy_from_user(buf, ubuf, buf_size)) 520 return -EFAULT; 521 522 buf[buf_size] = '\0'; 523 524 rc = strtobool(buf, &val); 525 if (rc) 526 return rc; 527 528 if (val) 529 rc = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 530 else 531 rc = ntb_link_disable(tc->ntb); 532 533 if (rc) 534 return rc; 535 536 return size; 537 } 538 539 static TOOL_FOPS_RDWR(tool_link_fops, 540 tool_link_read, 541 tool_link_write); 542 543 static ssize_t tool_link_event_write(struct file *filep, 544 const char __user *ubuf, 545 size_t size, loff_t *offp) 546 { 547 struct tool_ctx *tc = filep->private_data; 548 char buf[32]; 549 size_t buf_size; 550 bool val; 551 int rc; 552 553 buf_size = min(size, (sizeof(buf) - 1)); 554 if (copy_from_user(buf, ubuf, buf_size)) 555 return -EFAULT; 556 557 buf[buf_size] = '\0'; 558 559 rc = strtobool(buf, &val); 560 if (rc) 561 return rc; 562 563 if (wait_event_interruptible(tc->link_wq, 564 ntb_link_is_up(tc->ntb, NULL, NULL) == val)) 565 return -ERESTART; 566 567 return size; 568 } 569 570 static TOOL_FOPS_RDWR(tool_link_event_fops, 571 NULL, 572 tool_link_event_write); 573 574 static ssize_t tool_mw_read(struct file *filep, char __user *ubuf, 575 size_t size, loff_t *offp) 576 { 577 struct tool_mw *mw = filep->private_data; 578 ssize_t rc; 579 loff_t pos = *offp; 580 void *buf; 581 582 if (mw->local == NULL) 583 return -EIO; 584 if (pos < 0) 585 return -EINVAL; 586 if (pos >= mw->win_size || !size) 587 return 0; 588 if (size > mw->win_size - pos) 589 size = mw->win_size - pos; 590 591 buf = kmalloc(size, GFP_KERNEL); 592 if (!buf) 593 return -ENOMEM; 594 595 memcpy_fromio(buf, mw->local + pos, size); 596 rc = copy_to_user(ubuf, buf, size); 597 if (rc == size) { 598 rc = -EFAULT; 599 goto err_free; 600 } 601 602 size -= rc; 603 *offp = pos + size; 604 rc = size; 605 606 err_free: 607 kfree(buf); 608 609 return rc; 610 } 611 612 static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf, 613 size_t size, loff_t *offp) 614 { 615 struct tool_mw *mw = filep->private_data; 616 ssize_t rc; 617 loff_t pos = *offp; 618 void *buf; 619 620 if (pos < 0) 621 return -EINVAL; 622 if (pos >= mw->win_size || !size) 623 return 0; 624 if (size > mw->win_size - pos) 625 size = mw->win_size - pos; 626 627 buf = kmalloc(size, GFP_KERNEL); 628 if (!buf) 629 return -ENOMEM; 630 631 rc = copy_from_user(buf, ubuf, size); 632 if (rc == size) { 633 rc = -EFAULT; 634 goto err_free; 635 } 636 637 size -= rc; 638 *offp = pos + size; 639 rc = size; 640 641 memcpy_toio(mw->local + pos, buf, size); 642 643 err_free: 644 kfree(buf); 645 646 return rc; 647 } 648 649 static TOOL_FOPS_RDWR(tool_mw_fops, 650 tool_mw_read, 651 tool_mw_write); 652 653 static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf, 654 size_t size, loff_t *offp) 655 { 656 struct tool_mw *mw = filep->private_data; 657 658 if (!mw->peer) 659 return -ENXIO; 660 661 return simple_read_from_buffer(ubuf, size, offp, mw->peer, mw->size); 662 } 663 664 static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf, 665 size_t size, loff_t *offp) 666 { 667 struct tool_mw *mw = filep->private_data; 668 669 if (!mw->peer) 670 return -ENXIO; 671 672 return simple_write_to_buffer(mw->peer, mw->size, offp, ubuf, size); 673 } 674 675 static TOOL_FOPS_RDWR(tool_peer_mw_fops, 676 tool_peer_mw_read, 677 tool_peer_mw_write); 678 679 static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size) 680 { 681 int rc; 682 struct tool_mw *mw = &tc->mws[idx]; 683 resource_size_t size, align_addr, align_size; 684 char buf[16]; 685 686 if (mw->peer) 687 return 0; 688 689 rc = ntb_mw_get_align(tc->ntb, PIDX, idx, &align_addr, 690 &align_size, &size); 691 if (rc) 692 return rc; 693 694 mw->size = min_t(resource_size_t, req_size, size); 695 mw->size = round_up(mw->size, align_addr); 696 mw->size = round_up(mw->size, align_size); 697 mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size, 698 &mw->peer_dma, GFP_KERNEL); 699 700 if (!mw->peer || !IS_ALIGNED(mw->peer_dma, align_addr)) 701 return -ENOMEM; 702 703 rc = ntb_mw_set_trans(tc->ntb, PIDX, idx, mw->peer_dma, mw->size); 704 if (rc) 705 goto err_free_dma; 706 707 snprintf(buf, sizeof(buf), "peer_mw%d", idx); 708 mw->peer_dbg_file = debugfs_create_file(buf, S_IRUSR | S_IWUSR, 709 mw->tc->dbgfs, mw, 710 &tool_peer_mw_fops); 711 712 return 0; 713 714 err_free_dma: 715 dma_free_coherent(&tc->ntb->pdev->dev, mw->size, 716 mw->peer, 717 mw->peer_dma); 718 mw->peer = NULL; 719 mw->peer_dma = 0; 720 mw->size = 0; 721 722 return rc; 723 } 724 725 static void tool_free_mw(struct tool_ctx *tc, int idx) 726 { 727 struct tool_mw *mw = &tc->mws[idx]; 728 729 if (mw->peer) { 730 ntb_mw_clear_trans(tc->ntb, PIDX, idx); 731 dma_free_coherent(&tc->ntb->pdev->dev, mw->size, 732 mw->peer, 733 mw->peer_dma); 734 } 735 736 mw->peer = NULL; 737 mw->peer_dma = 0; 738 739 debugfs_remove(mw->peer_dbg_file); 740 741 mw->peer_dbg_file = NULL; 742 } 743 744 static ssize_t tool_peer_mw_trans_read(struct file *filep, 745 char __user *ubuf, 746 size_t size, loff_t *offp) 747 { 748 struct tool_mw *mw = filep->private_data; 749 750 char *buf; 751 size_t buf_size; 752 ssize_t ret, off = 0; 753 754 phys_addr_t base; 755 resource_size_t mw_size; 756 resource_size_t align_addr; 757 resource_size_t align_size; 758 resource_size_t max_size; 759 760 buf_size = min_t(size_t, size, 512); 761 762 buf = kmalloc(buf_size, GFP_KERNEL); 763 if (!buf) 764 return -ENOMEM; 765 766 ntb_mw_get_align(mw->tc->ntb, PIDX, mw->idx, 767 &align_addr, &align_size, &max_size); 768 ntb_peer_mw_get_addr(mw->tc->ntb, mw->idx, &base, &mw_size); 769 770 off += scnprintf(buf + off, buf_size - off, 771 "Peer MW %d Information:\n", mw->idx); 772 773 off += scnprintf(buf + off, buf_size - off, 774 "Physical Address \t%pa[p]\n", 775 &base); 776 777 off += scnprintf(buf + off, buf_size - off, 778 "Window Size \t%lld\n", 779 (unsigned long long)mw_size); 780 781 off += scnprintf(buf + off, buf_size - off, 782 "Alignment \t%lld\n", 783 (unsigned long long)align_addr); 784 785 off += scnprintf(buf + off, buf_size - off, 786 "Size Alignment \t%lld\n", 787 (unsigned long long)align_size); 788 789 off += scnprintf(buf + off, buf_size - off, 790 "Size Max \t%lld\n", 791 (unsigned long long)max_size); 792 793 off += scnprintf(buf + off, buf_size - off, 794 "Ready \t%c\n", 795 (mw->peer) ? 'Y' : 'N'); 796 797 off += scnprintf(buf + off, buf_size - off, 798 "Allocated Size \t%zd\n", 799 (mw->peer) ? (size_t)mw->size : 0); 800 801 ret = simple_read_from_buffer(ubuf, size, offp, buf, off); 802 kfree(buf); 803 return ret; 804 } 805 806 static ssize_t tool_peer_mw_trans_write(struct file *filep, 807 const char __user *ubuf, 808 size_t size, loff_t *offp) 809 { 810 struct tool_mw *mw = filep->private_data; 811 812 char buf[32]; 813 size_t buf_size; 814 unsigned long long val; 815 int rc; 816 817 buf_size = min(size, (sizeof(buf) - 1)); 818 if (copy_from_user(buf, ubuf, buf_size)) 819 return -EFAULT; 820 821 buf[buf_size] = '\0'; 822 823 rc = kstrtoull(buf, 0, &val); 824 if (rc) 825 return rc; 826 827 tool_free_mw(mw->tc, mw->idx); 828 if (val) 829 rc = tool_setup_mw(mw->tc, mw->idx, val); 830 831 if (rc) 832 return rc; 833 834 return size; 835 } 836 837 static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops, 838 tool_peer_mw_trans_read, 839 tool_peer_mw_trans_write); 840 841 static int tool_init_mw(struct tool_ctx *tc, int idx) 842 { 843 struct tool_mw *mw = &tc->mws[idx]; 844 phys_addr_t base; 845 int rc; 846 847 rc = ntb_peer_mw_get_addr(tc->ntb, idx, &base, &mw->win_size); 848 if (rc) 849 return rc; 850 851 mw->tc = tc; 852 mw->idx = idx; 853 mw->local = ioremap_wc(base, mw->win_size); 854 if (!mw->local) 855 return -EFAULT; 856 857 return 0; 858 } 859 860 static void tool_free_mws(struct tool_ctx *tc) 861 { 862 int i; 863 864 for (i = 0; i < tc->mw_count; i++) { 865 tool_free_mw(tc, i); 866 867 if (tc->mws[i].local) 868 iounmap(tc->mws[i].local); 869 870 tc->mws[i].local = NULL; 871 } 872 } 873 874 static void tool_setup_dbgfs(struct tool_ctx *tc) 875 { 876 int i; 877 878 /* This modules is useless without dbgfs... */ 879 if (!tool_dbgfs) { 880 tc->dbgfs = NULL; 881 return; 882 } 883 884 tc->dbgfs = debugfs_create_dir(dev_name(&tc->ntb->dev), 885 tool_dbgfs); 886 if (!tc->dbgfs) 887 return; 888 889 debugfs_create_file("db", S_IRUSR | S_IWUSR, tc->dbgfs, 890 tc, &tool_db_fops); 891 892 debugfs_create_file("mask", S_IRUSR | S_IWUSR, tc->dbgfs, 893 tc, &tool_mask_fops); 894 895 debugfs_create_file("peer_db", S_IRUSR | S_IWUSR, tc->dbgfs, 896 tc, &tool_peer_db_fops); 897 898 debugfs_create_file("peer_mask", S_IRUSR | S_IWUSR, tc->dbgfs, 899 tc, &tool_peer_mask_fops); 900 901 debugfs_create_file("spad", S_IRUSR | S_IWUSR, tc->dbgfs, 902 tc, &tool_spad_fops); 903 904 debugfs_create_file("peer_spad", S_IRUSR | S_IWUSR, tc->dbgfs, 905 tc, &tool_peer_spad_fops); 906 907 debugfs_create_file("link", S_IRUSR | S_IWUSR, tc->dbgfs, 908 tc, &tool_link_fops); 909 910 debugfs_create_file("link_event", S_IWUSR, tc->dbgfs, 911 tc, &tool_link_event_fops); 912 913 for (i = 0; i < tc->mw_count; i++) { 914 char buf[30]; 915 916 snprintf(buf, sizeof(buf), "mw%d", i); 917 debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs, 918 &tc->mws[i], &tool_mw_fops); 919 920 snprintf(buf, sizeof(buf), "peer_trans%d", i); 921 debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs, 922 &tc->mws[i], &tool_peer_mw_trans_fops); 923 } 924 } 925 926 static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) 927 { 928 struct tool_ctx *tc; 929 int rc; 930 int i; 931 932 if (!ntb->ops->mw_set_trans) { 933 dev_dbg(&ntb->dev, "need inbound MW based NTB API\n"); 934 rc = -EINVAL; 935 goto err_tc; 936 } 937 938 if (ntb_spad_count(ntb) < 1) { 939 dev_dbg(&ntb->dev, "no enough scratchpads\n"); 940 rc = -EINVAL; 941 goto err_tc; 942 } 943 944 if (ntb_db_is_unsafe(ntb)) 945 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 946 947 if (ntb_spad_is_unsafe(ntb)) 948 dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 949 950 if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT) 951 dev_warn(&ntb->dev, "multi-port NTB is unsupported\n"); 952 953 tc = kzalloc(sizeof(*tc), GFP_KERNEL); 954 if (!tc) { 955 rc = -ENOMEM; 956 goto err_tc; 957 } 958 959 tc->ntb = ntb; 960 init_waitqueue_head(&tc->link_wq); 961 962 tc->mw_count = min(ntb_peer_mw_count(tc->ntb), MAX_MWS); 963 for (i = 0; i < tc->mw_count; i++) { 964 rc = tool_init_mw(tc, i); 965 if (rc) 966 goto err_ctx; 967 } 968 969 tool_setup_dbgfs(tc); 970 971 rc = ntb_set_ctx(ntb, tc, &tool_ops); 972 if (rc) 973 goto err_ctx; 974 975 ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 976 ntb_link_event(ntb); 977 978 return 0; 979 980 err_ctx: 981 tool_free_mws(tc); 982 debugfs_remove_recursive(tc->dbgfs); 983 kfree(tc); 984 err_tc: 985 return rc; 986 } 987 988 static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb) 989 { 990 struct tool_ctx *tc = ntb->ctx; 991 992 tool_free_mws(tc); 993 994 ntb_clear_ctx(ntb); 995 ntb_link_disable(ntb); 996 997 debugfs_remove_recursive(tc->dbgfs); 998 kfree(tc); 999 } 1000 1001 static struct ntb_client tool_client = { 1002 .ops = { 1003 .probe = tool_probe, 1004 .remove = tool_remove, 1005 }, 1006 }; 1007 1008 static int __init tool_init(void) 1009 { 1010 int rc; 1011 1012 if (debugfs_initialized()) 1013 tool_dbgfs = debugfs_create_dir(KBUILD_MODNAME, NULL); 1014 1015 rc = ntb_register_client(&tool_client); 1016 if (rc) 1017 goto err_client; 1018 1019 return 0; 1020 1021 err_client: 1022 debugfs_remove_recursive(tool_dbgfs); 1023 return rc; 1024 } 1025 module_init(tool_init); 1026 1027 static void __exit tool_exit(void) 1028 { 1029 ntb_unregister_client(&tool_client); 1030 debugfs_remove_recursive(tool_dbgfs); 1031 } 1032 module_exit(tool_exit); 1033