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 * Copyright (C) 2017 T-Platforms All Rights Reserved. 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of version 2 of the GNU General Public License as 12 * published by the Free Software Foundation. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * General Public License for more details. 18 * 19 * BSD LICENSE 20 * 21 * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 22 * Copyright (C) 2017 T-Platforms All Rights Reserved. 23 * 24 * Redistribution and use in source and binary forms, with or without 25 * modification, are permitted provided that the following conditions 26 * are met: 27 * 28 * * Redistributions of source code must retain the above copyright 29 * notice, this list of conditions and the following disclaimer. 30 * * Redistributions in binary form must reproduce the above copy 31 * notice, this list of conditions and the following disclaimer in 32 * the documentation and/or other materials provided with the 33 * distribution. 34 * * Neither the name of Intel Corporation nor the names of its 35 * contributors may be used to endorse or promote products derived 36 * from this software without specific prior written permission. 37 * 38 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 39 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 40 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 41 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 42 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 44 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 45 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 46 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 47 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 48 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 49 * 50 * PCIe NTB Debugging Tool Linux driver 51 */ 52 53 /* 54 * How to use this tool, by example. 55 * 56 * Assuming $DBG_DIR is something like: 57 * '/sys/kernel/debug/ntb_tool/0000:00:03.0' 58 * Suppose aside from local device there is at least one remote device 59 * connected to NTB with index 0. 60 *----------------------------------------------------------------------------- 61 * Eg: check local/peer device information. 62 * 63 * # Get local device port number 64 * root@self# cat $DBG_DIR/port 65 * 66 * # Check local device functionality 67 * root@self# ls $DBG_DIR 68 * db msg1 msg_sts peer4/ port 69 * db_event msg2 peer0/ peer5/ spad0 70 * db_mask msg3 peer1/ peer_db spad1 71 * link msg_event peer2/ peer_db_mask spad2 72 * msg0 msg_mask peer3/ peer_spad spad3 73 * # As one can see it supports: 74 * # 1) four inbound message registers 75 * # 2) four inbound scratchpads 76 * # 3) up to six peer devices 77 * 78 * # Check peer device port number 79 * root@self# cat $DBG_DIR/peer0/port 80 * 81 * # Check peer device(s) functionality to be used 82 * root@self# ls $DBG_DIR/peer0 83 * link mw_trans0 mw_trans6 port 84 * link_event mw_trans1 mw_trans7 spad0 85 * msg0 mw_trans2 peer_mw_trans0 spad1 86 * msg1 mw_trans3 peer_mw_trans1 spad2 87 * msg2 mw_trans4 peer_mw_trans2 spad3 88 * msg3 mw_trans5 peer_mw_trans3 89 * # As one can see we got: 90 * # 1) four outbound message registers 91 * # 2) four outbound scratchpads 92 * # 3) eight inbound memory windows 93 * # 4) four outbound memory windows 94 *----------------------------------------------------------------------------- 95 * Eg: NTB link tests 96 * 97 * # Set local link up/down 98 * root@self# echo Y > $DBG_DIR/link 99 * root@self# echo N > $DBG_DIR/link 100 * 101 * # Check if link with peer device is up/down: 102 * root@self# cat $DBG_DIR/peer0/link 103 * 104 * # Block until the link is up/down 105 * root@self# echo Y > $DBG_DIR/peer0/link_event 106 * root@self# echo N > $DBG_DIR/peer0/link_event 107 *----------------------------------------------------------------------------- 108 * Eg: Doorbell registers tests (some functionality might be absent) 109 * 110 * # Set/clear/get local doorbell 111 * root@self# echo 's 1' > $DBG_DIR/db 112 * root@self# echo 'c 1' > $DBG_DIR/db 113 * root@self# cat $DBG_DIR/db 114 * 115 * # Set/clear/get local doorbell mask 116 * root@self# echo 's 1' > $DBG_DIR/db_mask 117 * root@self# echo 'c 1' > $DBG_DIR/db_mask 118 * root@self# cat $DBG_DIR/db_mask 119 * 120 * # Ring/clear/get peer doorbell 121 * root@peer# echo 's 1' > $DBG_DIR/peer_db 122 * root@peer# echo 'c 1' > $DBG_DIR/peer_db 123 * root@peer# cat $DBG_DIR/peer_db 124 * 125 * # Set/clear/get peer doorbell mask 126 * root@self# echo 's 1' > $DBG_DIR/peer_db_mask 127 * root@self# echo 'c 1' > $DBG_DIR/peer_db_mask 128 * root@self# cat $DBG_DIR/peer_db_mask 129 * 130 * # Block until local doorbell is set with specified value 131 * root@self# echo 1 > $DBG_DIR/db_event 132 *----------------------------------------------------------------------------- 133 * Eg: Message registers tests (functionality might be absent) 134 * 135 * # Set/clear/get in/out message registers status 136 * root@self# echo 's 1' > $DBG_DIR/msg_sts 137 * root@self# echo 'c 1' > $DBG_DIR/msg_sts 138 * root@self# cat $DBG_DIR/msg_sts 139 * 140 * # Set/clear in/out message registers mask 141 * root@self# echo 's 1' > $DBG_DIR/msg_mask 142 * root@self# echo 'c 1' > $DBG_DIR/msg_mask 143 * 144 * # Get inbound message register #0 value and source of port index 145 * root@self# cat $DBG_DIR/msg0 146 * 147 * # Send some data to peer over outbound message register #0 148 * root@self# echo 0x01020304 > $DBG_DIR/peer0/msg0 149 *----------------------------------------------------------------------------- 150 * Eg: Scratchpad registers tests (functionality might be absent) 151 * 152 * # Write/read to/from local scratchpad register #0 153 * root@peer# echo 0x01020304 > $DBG_DIR/spad0 154 * root@peer# cat $DBG_DIR/spad0 155 * 156 * # Write/read to/from peer scratchpad register #0 157 * root@peer# echo 0x01020304 > $DBG_DIR/peer0/spad0 158 * root@peer# cat $DBG_DIR/peer0/spad0 159 *----------------------------------------------------------------------------- 160 * Eg: Memory windows tests 161 * 162 * # Create inbound memory window buffer of specified size/get its base address 163 * root@peer# echo 16384 > $DBG_DIR/peer0/mw_trans0 164 * root@peer# cat $DBG_DIR/peer0/mw_trans0 165 * 166 * # Write/read data to/from inbound memory window 167 * root@peer# echo Hello > $DBG_DIR/peer0/mw0 168 * root@peer# head -c 7 $DBG_DIR/peer0/mw0 169 * 170 * # Map outbound memory window/check it settings (on peer device) 171 * root@peer# echo 0xADD0BA5E:16384 > $DBG_DIR/peer0/peer_mw_trans0 172 * root@peer# cat $DBG_DIR/peer0/peer_mw_trans0 173 * 174 * # Write/read data to/from outbound memory window (on peer device) 175 * root@peer# echo olleH > $DBG_DIR/peer0/peer_mw0 176 * root@peer# head -c 7 $DBG_DIR/peer0/peer_mw0 177 */ 178 179 #include <linux/init.h> 180 #include <linux/kernel.h> 181 #include <linux/module.h> 182 183 #include <linux/debugfs.h> 184 #include <linux/dma-mapping.h> 185 #include <linux/pci.h> 186 #include <linux/slab.h> 187 #include <linux/uaccess.h> 188 189 #include <linux/ntb.h> 190 191 #define DRIVER_NAME "ntb_tool" 192 #define DRIVER_VERSION "2.0" 193 194 MODULE_LICENSE("Dual BSD/GPL"); 195 MODULE_VERSION(DRIVER_VERSION); 196 MODULE_AUTHOR("Allen Hubbe <Allen.Hubbe@emc.com>"); 197 MODULE_DESCRIPTION("PCIe NTB Debugging Tool"); 198 199 /* 200 * Inbound and outbound memory windows descriptor. Union members selection 201 * depends on the MW type the structure describes. mm_base/dma_base are the 202 * virtual and DMA address of an inbound MW. io_base/tr_base are the MMIO 203 * mapped virtual and xlat addresses of an outbound MW respectively. 204 */ 205 struct tool_mw { 206 int widx; 207 int pidx; 208 struct tool_ctx *tc; 209 union { 210 u8 *mm_base; 211 u8 __iomem *io_base; 212 }; 213 union { 214 dma_addr_t dma_base; 215 u64 tr_base; 216 }; 217 resource_size_t size; 218 struct dentry *dbgfs_file; 219 }; 220 221 /* 222 * Wrapper structure is used to distinguish the outbound MW peers reference 223 * within the corresponding DebugFS directory IO operation. 224 */ 225 struct tool_mw_wrap { 226 int pidx; 227 struct tool_mw *mw; 228 }; 229 230 struct tool_msg { 231 int midx; 232 int pidx; 233 struct tool_ctx *tc; 234 }; 235 236 struct tool_spad { 237 int sidx; 238 int pidx; 239 struct tool_ctx *tc; 240 }; 241 242 struct tool_peer { 243 int pidx; 244 struct tool_ctx *tc; 245 int inmw_cnt; 246 struct tool_mw *inmws; 247 int outmw_cnt; 248 struct tool_mw_wrap *outmws; 249 int outmsg_cnt; 250 struct tool_msg *outmsgs; 251 int outspad_cnt; 252 struct tool_spad *outspads; 253 struct dentry *dbgfs_dir; 254 }; 255 256 struct tool_ctx { 257 struct ntb_dev *ntb; 258 wait_queue_head_t link_wq; 259 wait_queue_head_t db_wq; 260 wait_queue_head_t msg_wq; 261 int outmw_cnt; 262 struct tool_mw *outmws; 263 int peer_cnt; 264 struct tool_peer *peers; 265 int inmsg_cnt; 266 struct tool_msg *inmsgs; 267 int inspad_cnt; 268 struct tool_spad *inspads; 269 struct dentry *dbgfs_dir; 270 }; 271 272 #define TOOL_FOPS_RDWR(__name, __read, __write) \ 273 const struct file_operations __name = { \ 274 .owner = THIS_MODULE, \ 275 .open = simple_open, \ 276 .read = __read, \ 277 .write = __write, \ 278 } 279 280 #define TOOL_BUF_LEN 32 281 282 static struct dentry *tool_dbgfs_topdir; 283 284 /*============================================================================== 285 * NTB events handlers 286 *============================================================================== 287 */ 288 289 static void tool_link_event(void *ctx) 290 { 291 struct tool_ctx *tc = ctx; 292 enum ntb_speed speed; 293 enum ntb_width width; 294 int up; 295 296 up = ntb_link_is_up(tc->ntb, &speed, &width); 297 298 dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n", 299 up ? "up" : "down", speed, width); 300 301 wake_up(&tc->link_wq); 302 } 303 304 static void tool_db_event(void *ctx, int vec) 305 { 306 struct tool_ctx *tc = ctx; 307 u64 db_bits, db_mask; 308 309 db_mask = ntb_db_vector_mask(tc->ntb, vec); 310 db_bits = ntb_db_read(tc->ntb); 311 312 dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n", 313 vec, db_mask, db_bits); 314 315 wake_up(&tc->db_wq); 316 } 317 318 static void tool_msg_event(void *ctx) 319 { 320 struct tool_ctx *tc = ctx; 321 u64 msg_sts; 322 323 msg_sts = ntb_msg_read_sts(tc->ntb); 324 325 dev_dbg(&tc->ntb->dev, "message bits %#llx\n", msg_sts); 326 327 wake_up(&tc->msg_wq); 328 } 329 330 static const struct ntb_ctx_ops tool_ops = { 331 .link_event = tool_link_event, 332 .db_event = tool_db_event, 333 .msg_event = tool_msg_event 334 }; 335 336 /*============================================================================== 337 * Common read/write methods 338 *============================================================================== 339 */ 340 341 static ssize_t tool_fn_read(struct tool_ctx *tc, char __user *ubuf, 342 size_t size, loff_t *offp, 343 u64 (*fn_read)(struct ntb_dev *)) 344 { 345 size_t buf_size; 346 char buf[TOOL_BUF_LEN]; 347 ssize_t pos; 348 349 if (!fn_read) 350 return -EINVAL; 351 352 buf_size = min(size, sizeof(buf)); 353 354 pos = scnprintf(buf, buf_size, "%#llx\n", fn_read(tc->ntb)); 355 356 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 357 } 358 359 static ssize_t tool_fn_write(struct tool_ctx *tc, 360 const char __user *ubuf, 361 size_t size, loff_t *offp, 362 int (*fn_set)(struct ntb_dev *, u64), 363 int (*fn_clear)(struct ntb_dev *, u64)) 364 { 365 char *buf, cmd; 366 ssize_t ret; 367 u64 bits; 368 int n; 369 370 if (*offp) 371 return 0; 372 373 buf = kmalloc(size + 1, GFP_KERNEL); 374 if (!buf) 375 return -ENOMEM; 376 377 if (copy_from_user(buf, ubuf, size)) { 378 kfree(buf); 379 return -EFAULT; 380 } 381 382 buf[size] = 0; 383 384 n = sscanf(buf, "%c %lli", &cmd, &bits); 385 386 kfree(buf); 387 388 if (n != 2) { 389 ret = -EINVAL; 390 } else if (cmd == 's') { 391 if (!fn_set) 392 ret = -EINVAL; 393 else 394 ret = fn_set(tc->ntb, bits); 395 } else if (cmd == 'c') { 396 if (!fn_clear) 397 ret = -EINVAL; 398 else 399 ret = fn_clear(tc->ntb, bits); 400 } else { 401 ret = -EINVAL; 402 } 403 404 return ret ? : size; 405 } 406 407 /*============================================================================== 408 * Port read/write methods 409 *============================================================================== 410 */ 411 412 static ssize_t tool_port_read(struct file *filep, char __user *ubuf, 413 size_t size, loff_t *offp) 414 { 415 struct tool_ctx *tc = filep->private_data; 416 char buf[TOOL_BUF_LEN]; 417 int pos; 418 419 pos = scnprintf(buf, sizeof(buf), "%d\n", ntb_port_number(tc->ntb)); 420 421 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 422 } 423 424 static TOOL_FOPS_RDWR(tool_port_fops, 425 tool_port_read, 426 NULL); 427 428 static ssize_t tool_peer_port_read(struct file *filep, char __user *ubuf, 429 size_t size, loff_t *offp) 430 { 431 struct tool_peer *peer = filep->private_data; 432 struct tool_ctx *tc = peer->tc; 433 char buf[TOOL_BUF_LEN]; 434 int pos; 435 436 pos = scnprintf(buf, sizeof(buf), "%d\n", 437 ntb_peer_port_number(tc->ntb, peer->pidx)); 438 439 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 440 } 441 442 static TOOL_FOPS_RDWR(tool_peer_port_fops, 443 tool_peer_port_read, 444 NULL); 445 446 static int tool_init_peers(struct tool_ctx *tc) 447 { 448 int pidx; 449 450 tc->peer_cnt = ntb_peer_port_count(tc->ntb); 451 tc->peers = devm_kcalloc(&tc->ntb->dev, tc->peer_cnt, 452 sizeof(*tc->peers), GFP_KERNEL); 453 if (tc->peers == NULL) 454 return -ENOMEM; 455 456 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 457 tc->peers[pidx].pidx = pidx; 458 tc->peers[pidx].tc = tc; 459 } 460 461 return 0; 462 } 463 464 /*============================================================================== 465 * Link state read/write methods 466 *============================================================================== 467 */ 468 469 static ssize_t tool_link_write(struct file *filep, const char __user *ubuf, 470 size_t size, loff_t *offp) 471 { 472 struct tool_ctx *tc = filep->private_data; 473 bool val; 474 int ret; 475 476 ret = kstrtobool_from_user(ubuf, size, &val); 477 if (ret) 478 return ret; 479 480 if (val) 481 ret = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 482 else 483 ret = ntb_link_disable(tc->ntb); 484 485 if (ret) 486 return ret; 487 488 return size; 489 } 490 491 static TOOL_FOPS_RDWR(tool_link_fops, 492 NULL, 493 tool_link_write); 494 495 static ssize_t tool_peer_link_read(struct file *filep, char __user *ubuf, 496 size_t size, loff_t *offp) 497 { 498 struct tool_peer *peer = filep->private_data; 499 struct tool_ctx *tc = peer->tc; 500 char buf[3]; 501 502 if (ntb_link_is_up(tc->ntb, NULL, NULL) & BIT(peer->pidx)) 503 buf[0] = 'Y'; 504 else 505 buf[0] = 'N'; 506 buf[1] = '\n'; 507 buf[2] = '\0'; 508 509 return simple_read_from_buffer(ubuf, size, offp, buf, 2); 510 } 511 512 static TOOL_FOPS_RDWR(tool_peer_link_fops, 513 tool_peer_link_read, 514 NULL); 515 516 static ssize_t tool_peer_link_event_write(struct file *filep, 517 const char __user *ubuf, 518 size_t size, loff_t *offp) 519 { 520 struct tool_peer *peer = filep->private_data; 521 struct tool_ctx *tc = peer->tc; 522 u64 link_msk; 523 bool val; 524 int ret; 525 526 ret = kstrtobool_from_user(ubuf, size, &val); 527 if (ret) 528 return ret; 529 530 link_msk = BIT_ULL_MASK(peer->pidx); 531 532 if (wait_event_interruptible(tc->link_wq, 533 !!(ntb_link_is_up(tc->ntb, NULL, NULL) & link_msk) == val)) 534 return -ERESTART; 535 536 return size; 537 } 538 539 static TOOL_FOPS_RDWR(tool_peer_link_event_fops, 540 NULL, 541 tool_peer_link_event_write); 542 543 /*============================================================================== 544 * Memory windows read/write/setting methods 545 *============================================================================== 546 */ 547 548 static ssize_t tool_mw_read(struct file *filep, char __user *ubuf, 549 size_t size, loff_t *offp) 550 { 551 struct tool_mw *inmw = filep->private_data; 552 553 if (inmw->mm_base == NULL) 554 return -ENXIO; 555 556 return simple_read_from_buffer(ubuf, size, offp, 557 inmw->mm_base, inmw->size); 558 } 559 560 static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf, 561 size_t size, loff_t *offp) 562 { 563 struct tool_mw *inmw = filep->private_data; 564 565 if (inmw->mm_base == NULL) 566 return -ENXIO; 567 568 return simple_write_to_buffer(inmw->mm_base, inmw->size, offp, 569 ubuf, size); 570 } 571 572 static TOOL_FOPS_RDWR(tool_mw_fops, 573 tool_mw_read, 574 tool_mw_write); 575 576 static int tool_setup_mw(struct tool_ctx *tc, int pidx, int widx, 577 size_t req_size) 578 { 579 resource_size_t size, addr_align, size_align; 580 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; 581 char buf[TOOL_BUF_LEN]; 582 int ret; 583 584 if (inmw->mm_base != NULL) 585 return 0; 586 587 ret = ntb_mw_get_align(tc->ntb, pidx, widx, &addr_align, 588 &size_align, &size); 589 if (ret) 590 return ret; 591 592 inmw->size = min_t(resource_size_t, req_size, size); 593 inmw->size = round_up(inmw->size, addr_align); 594 inmw->size = round_up(inmw->size, size_align); 595 inmw->mm_base = dma_alloc_coherent(&tc->ntb->pdev->dev, inmw->size, 596 &inmw->dma_base, GFP_KERNEL); 597 if (!inmw->mm_base) 598 return -ENOMEM; 599 600 if (!IS_ALIGNED(inmw->dma_base, addr_align)) { 601 ret = -ENOMEM; 602 goto err_free_dma; 603 } 604 605 ret = ntb_mw_set_trans(tc->ntb, pidx, widx, inmw->dma_base, inmw->size); 606 if (ret) 607 goto err_free_dma; 608 609 snprintf(buf, sizeof(buf), "mw%d", widx); 610 inmw->dbgfs_file = debugfs_create_file(buf, 0600, 611 tc->peers[pidx].dbgfs_dir, inmw, 612 &tool_mw_fops); 613 614 return 0; 615 616 err_free_dma: 617 dma_free_coherent(&tc->ntb->pdev->dev, inmw->size, inmw->mm_base, 618 inmw->dma_base); 619 inmw->mm_base = NULL; 620 inmw->dma_base = 0; 621 inmw->size = 0; 622 623 return ret; 624 } 625 626 static void tool_free_mw(struct tool_ctx *tc, int pidx, int widx) 627 { 628 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; 629 630 debugfs_remove(inmw->dbgfs_file); 631 632 if (inmw->mm_base != NULL) { 633 ntb_mw_clear_trans(tc->ntb, pidx, widx); 634 dma_free_coherent(&tc->ntb->pdev->dev, inmw->size, 635 inmw->mm_base, inmw->dma_base); 636 } 637 638 inmw->mm_base = NULL; 639 inmw->dma_base = 0; 640 inmw->size = 0; 641 inmw->dbgfs_file = NULL; 642 } 643 644 static ssize_t tool_mw_trans_read(struct file *filep, char __user *ubuf, 645 size_t size, loff_t *offp) 646 { 647 struct tool_mw *inmw = filep->private_data; 648 resource_size_t addr_align; 649 resource_size_t size_align; 650 resource_size_t size_max; 651 ssize_t ret, off = 0; 652 size_t buf_size; 653 char *buf; 654 655 buf_size = min_t(size_t, size, 512); 656 657 buf = kmalloc(buf_size, GFP_KERNEL); 658 if (!buf) 659 return -ENOMEM; 660 661 ret = ntb_mw_get_align(inmw->tc->ntb, inmw->pidx, inmw->widx, 662 &addr_align, &size_align, &size_max); 663 if (ret) 664 goto err; 665 666 off += scnprintf(buf + off, buf_size - off, 667 "Inbound MW \t%d\n", 668 inmw->widx); 669 670 off += scnprintf(buf + off, buf_size - off, 671 "Port \t%d (%d)\n", 672 ntb_peer_port_number(inmw->tc->ntb, inmw->pidx), 673 inmw->pidx); 674 675 off += scnprintf(buf + off, buf_size - off, 676 "Window Address \t0x%pK\n", inmw->mm_base); 677 678 off += scnprintf(buf + off, buf_size - off, 679 "DMA Address \t%pad\n", 680 &inmw->dma_base); 681 682 off += scnprintf(buf + off, buf_size - off, 683 "Window Size \t%pap\n", 684 &inmw->size); 685 686 off += scnprintf(buf + off, buf_size - off, 687 "Alignment \t%pap\n", 688 &addr_align); 689 690 off += scnprintf(buf + off, buf_size - off, 691 "Size Alignment \t%pap\n", 692 &size_align); 693 694 off += scnprintf(buf + off, buf_size - off, 695 "Size Max \t%pap\n", 696 &size_max); 697 698 ret = simple_read_from_buffer(ubuf, size, offp, buf, off); 699 700 err: 701 kfree(buf); 702 703 return ret; 704 } 705 706 static ssize_t tool_mw_trans_write(struct file *filep, const char __user *ubuf, 707 size_t size, loff_t *offp) 708 { 709 struct tool_mw *inmw = filep->private_data; 710 unsigned int val; 711 int ret; 712 713 ret = kstrtouint_from_user(ubuf, size, 0, &val); 714 if (ret) 715 return ret; 716 717 tool_free_mw(inmw->tc, inmw->pidx, inmw->widx); 718 if (val) { 719 ret = tool_setup_mw(inmw->tc, inmw->pidx, inmw->widx, val); 720 if (ret) 721 return ret; 722 } 723 724 return size; 725 } 726 727 static TOOL_FOPS_RDWR(tool_mw_trans_fops, 728 tool_mw_trans_read, 729 tool_mw_trans_write); 730 731 static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf, 732 size_t size, loff_t *offp) 733 { 734 struct tool_mw *outmw = filep->private_data; 735 loff_t pos = *offp; 736 ssize_t ret; 737 void *buf; 738 739 if (outmw->io_base == NULL) 740 return -EIO; 741 742 if (pos >= outmw->size || !size) 743 return 0; 744 745 if (size > outmw->size - pos) 746 size = outmw->size - pos; 747 748 buf = kmalloc(size, GFP_KERNEL); 749 if (!buf) 750 return -ENOMEM; 751 752 memcpy_fromio(buf, outmw->io_base + pos, size); 753 ret = copy_to_user(ubuf, buf, size); 754 if (ret == size) { 755 ret = -EFAULT; 756 goto err_free; 757 } 758 759 size -= ret; 760 *offp = pos + size; 761 ret = size; 762 763 err_free: 764 kfree(buf); 765 766 return ret; 767 } 768 769 static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf, 770 size_t size, loff_t *offp) 771 { 772 struct tool_mw *outmw = filep->private_data; 773 ssize_t ret; 774 loff_t pos = *offp; 775 void *buf; 776 777 if (outmw->io_base == NULL) 778 return -EIO; 779 780 if (pos >= outmw->size || !size) 781 return 0; 782 if (size > outmw->size - pos) 783 size = outmw->size - pos; 784 785 buf = kmalloc(size, GFP_KERNEL); 786 if (!buf) 787 return -ENOMEM; 788 789 ret = copy_from_user(buf, ubuf, size); 790 if (ret == size) { 791 ret = -EFAULT; 792 goto err_free; 793 } 794 795 size -= ret; 796 *offp = pos + size; 797 ret = size; 798 799 memcpy_toio(outmw->io_base + pos, buf, size); 800 801 err_free: 802 kfree(buf); 803 804 return ret; 805 } 806 807 static TOOL_FOPS_RDWR(tool_peer_mw_fops, 808 tool_peer_mw_read, 809 tool_peer_mw_write); 810 811 static int tool_setup_peer_mw(struct tool_ctx *tc, int pidx, int widx, 812 u64 req_addr, size_t req_size) 813 { 814 struct tool_mw *outmw = &tc->outmws[widx]; 815 resource_size_t map_size; 816 phys_addr_t map_base; 817 char buf[TOOL_BUF_LEN]; 818 int ret; 819 820 if (outmw->io_base != NULL) 821 return 0; 822 823 ret = ntb_peer_mw_get_addr(tc->ntb, widx, &map_base, &map_size); 824 if (ret) 825 return ret; 826 827 ret = ntb_peer_mw_set_trans(tc->ntb, pidx, widx, req_addr, req_size); 828 if (ret) 829 return ret; 830 831 outmw->io_base = ioremap_wc(map_base, map_size); 832 if (outmw->io_base == NULL) { 833 ret = -EFAULT; 834 goto err_clear_trans; 835 } 836 837 outmw->tr_base = req_addr; 838 outmw->size = req_size; 839 outmw->pidx = pidx; 840 841 snprintf(buf, sizeof(buf), "peer_mw%d", widx); 842 outmw->dbgfs_file = debugfs_create_file(buf, 0600, 843 tc->peers[pidx].dbgfs_dir, outmw, 844 &tool_peer_mw_fops); 845 846 return 0; 847 848 err_clear_trans: 849 ntb_peer_mw_clear_trans(tc->ntb, pidx, widx); 850 851 return ret; 852 } 853 854 static void tool_free_peer_mw(struct tool_ctx *tc, int widx) 855 { 856 struct tool_mw *outmw = &tc->outmws[widx]; 857 858 debugfs_remove(outmw->dbgfs_file); 859 860 if (outmw->io_base != NULL) { 861 iounmap(tc->outmws[widx].io_base); 862 ntb_peer_mw_clear_trans(tc->ntb, outmw->pidx, widx); 863 } 864 865 outmw->io_base = NULL; 866 outmw->tr_base = 0; 867 outmw->size = 0; 868 outmw->pidx = -1; 869 outmw->dbgfs_file = NULL; 870 } 871 872 static ssize_t tool_peer_mw_trans_read(struct file *filep, char __user *ubuf, 873 size_t size, loff_t *offp) 874 { 875 struct tool_mw_wrap *outmw_wrap = filep->private_data; 876 struct tool_mw *outmw = outmw_wrap->mw; 877 resource_size_t map_size; 878 phys_addr_t map_base; 879 ssize_t off = 0; 880 size_t buf_size; 881 char *buf; 882 int ret; 883 884 ret = ntb_peer_mw_get_addr(outmw->tc->ntb, outmw->widx, 885 &map_base, &map_size); 886 if (ret) 887 return ret; 888 889 buf_size = min_t(size_t, size, 512); 890 891 buf = kmalloc(buf_size, GFP_KERNEL); 892 if (!buf) 893 return -ENOMEM; 894 895 off += scnprintf(buf + off, buf_size - off, 896 "Outbound MW: \t%d\n", outmw->widx); 897 898 if (outmw->io_base != NULL) { 899 off += scnprintf(buf + off, buf_size - off, 900 "Port attached \t%d (%d)\n", 901 ntb_peer_port_number(outmw->tc->ntb, outmw->pidx), 902 outmw->pidx); 903 } else { 904 off += scnprintf(buf + off, buf_size - off, 905 "Port attached \t-1 (-1)\n"); 906 } 907 908 off += scnprintf(buf + off, buf_size - off, 909 "Virtual address \t0x%pK\n", outmw->io_base); 910 911 off += scnprintf(buf + off, buf_size - off, 912 "Phys Address \t%pap\n", &map_base); 913 914 off += scnprintf(buf + off, buf_size - off, 915 "Mapping Size \t%pap\n", &map_size); 916 917 off += scnprintf(buf + off, buf_size - off, 918 "Translation Address \t0x%016llx\n", outmw->tr_base); 919 920 off += scnprintf(buf + off, buf_size - off, 921 "Window Size \t%pap\n", &outmw->size); 922 923 ret = simple_read_from_buffer(ubuf, size, offp, buf, off); 924 kfree(buf); 925 926 return ret; 927 } 928 929 static ssize_t tool_peer_mw_trans_write(struct file *filep, 930 const char __user *ubuf, 931 size_t size, loff_t *offp) 932 { 933 struct tool_mw_wrap *outmw_wrap = filep->private_data; 934 struct tool_mw *outmw = outmw_wrap->mw; 935 size_t buf_size, wsize; 936 char buf[TOOL_BUF_LEN]; 937 int ret, n; 938 u64 addr; 939 940 buf_size = min(size, (sizeof(buf) - 1)); 941 if (copy_from_user(buf, ubuf, buf_size)) 942 return -EFAULT; 943 944 buf[buf_size] = '\0'; 945 946 n = sscanf(buf, "%lli:%zi", &addr, &wsize); 947 if (n != 2) 948 return -EINVAL; 949 950 tool_free_peer_mw(outmw->tc, outmw->widx); 951 if (wsize) { 952 ret = tool_setup_peer_mw(outmw->tc, outmw_wrap->pidx, 953 outmw->widx, addr, wsize); 954 if (ret) 955 return ret; 956 } 957 958 return size; 959 } 960 961 static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops, 962 tool_peer_mw_trans_read, 963 tool_peer_mw_trans_write); 964 965 static int tool_init_mws(struct tool_ctx *tc) 966 { 967 int widx, pidx; 968 969 /* Initialize outbound memory windows */ 970 tc->outmw_cnt = ntb_peer_mw_count(tc->ntb); 971 tc->outmws = devm_kcalloc(&tc->ntb->dev, tc->outmw_cnt, 972 sizeof(*tc->outmws), GFP_KERNEL); 973 if (tc->outmws == NULL) 974 return -ENOMEM; 975 976 for (widx = 0; widx < tc->outmw_cnt; widx++) { 977 tc->outmws[widx].widx = widx; 978 tc->outmws[widx].pidx = -1; 979 tc->outmws[widx].tc = tc; 980 } 981 982 /* Initialize inbound memory windows and outbound MWs wrapper */ 983 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 984 tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->ntb, pidx); 985 tc->peers[pidx].inmws = 986 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].inmw_cnt, 987 sizeof(*tc->peers[pidx].inmws), GFP_KERNEL); 988 if (tc->peers[pidx].inmws == NULL) 989 return -ENOMEM; 990 991 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 992 tc->peers[pidx].inmws[widx].widx = widx; 993 tc->peers[pidx].inmws[widx].pidx = pidx; 994 tc->peers[pidx].inmws[widx].tc = tc; 995 } 996 997 tc->peers[pidx].outmw_cnt = ntb_peer_mw_count(tc->ntb); 998 tc->peers[pidx].outmws = 999 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmw_cnt, 1000 sizeof(*tc->peers[pidx].outmws), GFP_KERNEL); 1001 1002 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) { 1003 tc->peers[pidx].outmws[widx].pidx = pidx; 1004 tc->peers[pidx].outmws[widx].mw = &tc->outmws[widx]; 1005 } 1006 } 1007 1008 return 0; 1009 } 1010 1011 static void tool_clear_mws(struct tool_ctx *tc) 1012 { 1013 int widx, pidx; 1014 1015 /* Free outbound memory windows */ 1016 for (widx = 0; widx < tc->outmw_cnt; widx++) 1017 tool_free_peer_mw(tc, widx); 1018 1019 /* Free outbound memory windows */ 1020 for (pidx = 0; pidx < tc->peer_cnt; pidx++) 1021 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) 1022 tool_free_mw(tc, pidx, widx); 1023 } 1024 1025 /*============================================================================== 1026 * Doorbell read/write methods 1027 *============================================================================== 1028 */ 1029 1030 static ssize_t tool_db_read(struct file *filep, char __user *ubuf, 1031 size_t size, loff_t *offp) 1032 { 1033 struct tool_ctx *tc = filep->private_data; 1034 1035 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read); 1036 } 1037 1038 static ssize_t tool_db_write(struct file *filep, const char __user *ubuf, 1039 size_t size, loff_t *offp) 1040 { 1041 struct tool_ctx *tc = filep->private_data; 1042 1043 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set, 1044 tc->ntb->ops->db_clear); 1045 } 1046 1047 static TOOL_FOPS_RDWR(tool_db_fops, 1048 tool_db_read, 1049 tool_db_write); 1050 1051 static ssize_t tool_db_valid_mask_read(struct file *filep, char __user *ubuf, 1052 size_t size, loff_t *offp) 1053 { 1054 struct tool_ctx *tc = filep->private_data; 1055 1056 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_valid_mask); 1057 } 1058 1059 static TOOL_FOPS_RDWR(tool_db_valid_mask_fops, 1060 tool_db_valid_mask_read, 1061 NULL); 1062 1063 static ssize_t tool_db_mask_read(struct file *filep, char __user *ubuf, 1064 size_t size, loff_t *offp) 1065 { 1066 struct tool_ctx *tc = filep->private_data; 1067 1068 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read_mask); 1069 } 1070 1071 static ssize_t tool_db_mask_write(struct file *filep, const char __user *ubuf, 1072 size_t size, loff_t *offp) 1073 { 1074 struct tool_ctx *tc = filep->private_data; 1075 1076 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set_mask, 1077 tc->ntb->ops->db_clear_mask); 1078 } 1079 1080 static TOOL_FOPS_RDWR(tool_db_mask_fops, 1081 tool_db_mask_read, 1082 tool_db_mask_write); 1083 1084 static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf, 1085 size_t size, loff_t *offp) 1086 { 1087 struct tool_ctx *tc = filep->private_data; 1088 1089 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->peer_db_read); 1090 } 1091 1092 static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf, 1093 size_t size, loff_t *offp) 1094 { 1095 struct tool_ctx *tc = filep->private_data; 1096 1097 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->peer_db_set, 1098 tc->ntb->ops->peer_db_clear); 1099 } 1100 1101 static TOOL_FOPS_RDWR(tool_peer_db_fops, 1102 tool_peer_db_read, 1103 tool_peer_db_write); 1104 1105 static ssize_t tool_peer_db_mask_read(struct file *filep, char __user *ubuf, 1106 size_t size, loff_t *offp) 1107 { 1108 struct tool_ctx *tc = filep->private_data; 1109 1110 return tool_fn_read(tc, ubuf, size, offp, 1111 tc->ntb->ops->peer_db_read_mask); 1112 } 1113 1114 static ssize_t tool_peer_db_mask_write(struct file *filep, 1115 const char __user *ubuf, 1116 size_t size, loff_t *offp) 1117 { 1118 struct tool_ctx *tc = filep->private_data; 1119 1120 return tool_fn_write(tc, ubuf, size, offp, 1121 tc->ntb->ops->peer_db_set_mask, 1122 tc->ntb->ops->peer_db_clear_mask); 1123 } 1124 1125 static TOOL_FOPS_RDWR(tool_peer_db_mask_fops, 1126 tool_peer_db_mask_read, 1127 tool_peer_db_mask_write); 1128 1129 static ssize_t tool_db_event_write(struct file *filep, 1130 const char __user *ubuf, 1131 size_t size, loff_t *offp) 1132 { 1133 struct tool_ctx *tc = filep->private_data; 1134 u64 val; 1135 int ret; 1136 1137 ret = kstrtou64_from_user(ubuf, size, 0, &val); 1138 if (ret) 1139 return ret; 1140 1141 if (wait_event_interruptible(tc->db_wq, ntb_db_read(tc->ntb) == val)) 1142 return -ERESTART; 1143 1144 return size; 1145 } 1146 1147 static TOOL_FOPS_RDWR(tool_db_event_fops, 1148 NULL, 1149 tool_db_event_write); 1150 1151 /*============================================================================== 1152 * Scratchpads read/write methods 1153 *============================================================================== 1154 */ 1155 1156 static ssize_t tool_spad_read(struct file *filep, char __user *ubuf, 1157 size_t size, loff_t *offp) 1158 { 1159 struct tool_spad *spad = filep->private_data; 1160 char buf[TOOL_BUF_LEN]; 1161 ssize_t pos; 1162 1163 if (!spad->tc->ntb->ops->spad_read) 1164 return -EINVAL; 1165 1166 pos = scnprintf(buf, sizeof(buf), "%#x\n", 1167 ntb_spad_read(spad->tc->ntb, spad->sidx)); 1168 1169 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 1170 } 1171 1172 static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf, 1173 size_t size, loff_t *offp) 1174 { 1175 struct tool_spad *spad = filep->private_data; 1176 u32 val; 1177 int ret; 1178 1179 if (!spad->tc->ntb->ops->spad_write) { 1180 dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n"); 1181 return -EINVAL; 1182 } 1183 1184 ret = kstrtou32_from_user(ubuf, size, 0, &val); 1185 if (ret) 1186 return ret; 1187 1188 ret = ntb_spad_write(spad->tc->ntb, spad->sidx, val); 1189 1190 return ret ?: size; 1191 } 1192 1193 static TOOL_FOPS_RDWR(tool_spad_fops, 1194 tool_spad_read, 1195 tool_spad_write); 1196 1197 static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf, 1198 size_t size, loff_t *offp) 1199 { 1200 struct tool_spad *spad = filep->private_data; 1201 char buf[TOOL_BUF_LEN]; 1202 ssize_t pos; 1203 1204 if (!spad->tc->ntb->ops->peer_spad_read) 1205 return -EINVAL; 1206 1207 pos = scnprintf(buf, sizeof(buf), "%#x\n", 1208 ntb_peer_spad_read(spad->tc->ntb, spad->pidx, spad->sidx)); 1209 1210 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 1211 } 1212 1213 static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf, 1214 size_t size, loff_t *offp) 1215 { 1216 struct tool_spad *spad = filep->private_data; 1217 u32 val; 1218 int ret; 1219 1220 if (!spad->tc->ntb->ops->peer_spad_write) { 1221 dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n"); 1222 return -EINVAL; 1223 } 1224 1225 ret = kstrtou32_from_user(ubuf, size, 0, &val); 1226 if (ret) 1227 return ret; 1228 1229 ret = ntb_peer_spad_write(spad->tc->ntb, spad->pidx, spad->sidx, val); 1230 1231 return ret ?: size; 1232 } 1233 1234 static TOOL_FOPS_RDWR(tool_peer_spad_fops, 1235 tool_peer_spad_read, 1236 tool_peer_spad_write); 1237 1238 static int tool_init_spads(struct tool_ctx *tc) 1239 { 1240 int sidx, pidx; 1241 1242 /* Initialize inbound scratchpad structures */ 1243 tc->inspad_cnt = ntb_spad_count(tc->ntb); 1244 tc->inspads = devm_kcalloc(&tc->ntb->dev, tc->inspad_cnt, 1245 sizeof(*tc->inspads), GFP_KERNEL); 1246 if (tc->inspads == NULL) 1247 return -ENOMEM; 1248 1249 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 1250 tc->inspads[sidx].sidx = sidx; 1251 tc->inspads[sidx].pidx = -1; 1252 tc->inspads[sidx].tc = tc; 1253 } 1254 1255 /* Initialize outbound scratchpad structures */ 1256 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1257 tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->ntb); 1258 tc->peers[pidx].outspads = 1259 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outspad_cnt, 1260 sizeof(*tc->peers[pidx].outspads), GFP_KERNEL); 1261 if (tc->peers[pidx].outspads == NULL) 1262 return -ENOMEM; 1263 1264 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 1265 tc->peers[pidx].outspads[sidx].sidx = sidx; 1266 tc->peers[pidx].outspads[sidx].pidx = pidx; 1267 tc->peers[pidx].outspads[sidx].tc = tc; 1268 } 1269 } 1270 1271 return 0; 1272 } 1273 1274 /*============================================================================== 1275 * Messages read/write methods 1276 *============================================================================== 1277 */ 1278 1279 static ssize_t tool_inmsg_read(struct file *filep, char __user *ubuf, 1280 size_t size, loff_t *offp) 1281 { 1282 struct tool_msg *msg = filep->private_data; 1283 char buf[TOOL_BUF_LEN]; 1284 ssize_t pos; 1285 u32 data; 1286 int pidx; 1287 1288 data = ntb_msg_read(msg->tc->ntb, &pidx, msg->midx); 1289 1290 pos = scnprintf(buf, sizeof(buf), "0x%08x<-%d\n", data, pidx); 1291 1292 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 1293 } 1294 1295 static TOOL_FOPS_RDWR(tool_inmsg_fops, 1296 tool_inmsg_read, 1297 NULL); 1298 1299 static ssize_t tool_outmsg_write(struct file *filep, 1300 const char __user *ubuf, 1301 size_t size, loff_t *offp) 1302 { 1303 struct tool_msg *msg = filep->private_data; 1304 u32 val; 1305 int ret; 1306 1307 ret = kstrtou32_from_user(ubuf, size, 0, &val); 1308 if (ret) 1309 return ret; 1310 1311 ret = ntb_peer_msg_write(msg->tc->ntb, msg->pidx, msg->midx, val); 1312 1313 return ret ? : size; 1314 } 1315 1316 static TOOL_FOPS_RDWR(tool_outmsg_fops, 1317 NULL, 1318 tool_outmsg_write); 1319 1320 static ssize_t tool_msg_sts_read(struct file *filep, char __user *ubuf, 1321 size_t size, loff_t *offp) 1322 { 1323 struct tool_ctx *tc = filep->private_data; 1324 1325 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_read_sts); 1326 } 1327 1328 static ssize_t tool_msg_sts_write(struct file *filep, const char __user *ubuf, 1329 size_t size, loff_t *offp) 1330 { 1331 struct tool_ctx *tc = filep->private_data; 1332 1333 return tool_fn_write(tc, ubuf, size, offp, NULL, 1334 tc->ntb->ops->msg_clear_sts); 1335 } 1336 1337 static TOOL_FOPS_RDWR(tool_msg_sts_fops, 1338 tool_msg_sts_read, 1339 tool_msg_sts_write); 1340 1341 static ssize_t tool_msg_inbits_read(struct file *filep, char __user *ubuf, 1342 size_t size, loff_t *offp) 1343 { 1344 struct tool_ctx *tc = filep->private_data; 1345 1346 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_inbits); 1347 } 1348 1349 static TOOL_FOPS_RDWR(tool_msg_inbits_fops, 1350 tool_msg_inbits_read, 1351 NULL); 1352 1353 static ssize_t tool_msg_outbits_read(struct file *filep, char __user *ubuf, 1354 size_t size, loff_t *offp) 1355 { 1356 struct tool_ctx *tc = filep->private_data; 1357 1358 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_outbits); 1359 } 1360 1361 static TOOL_FOPS_RDWR(tool_msg_outbits_fops, 1362 tool_msg_outbits_read, 1363 NULL); 1364 1365 static ssize_t tool_msg_mask_write(struct file *filep, const char __user *ubuf, 1366 size_t size, loff_t *offp) 1367 { 1368 struct tool_ctx *tc = filep->private_data; 1369 1370 return tool_fn_write(tc, ubuf, size, offp, 1371 tc->ntb->ops->msg_set_mask, 1372 tc->ntb->ops->msg_clear_mask); 1373 } 1374 1375 static TOOL_FOPS_RDWR(tool_msg_mask_fops, 1376 NULL, 1377 tool_msg_mask_write); 1378 1379 static ssize_t tool_msg_event_write(struct file *filep, 1380 const char __user *ubuf, 1381 size_t size, loff_t *offp) 1382 { 1383 struct tool_ctx *tc = filep->private_data; 1384 u64 val; 1385 int ret; 1386 1387 ret = kstrtou64_from_user(ubuf, size, 0, &val); 1388 if (ret) 1389 return ret; 1390 1391 if (wait_event_interruptible(tc->msg_wq, 1392 ntb_msg_read_sts(tc->ntb) == val)) 1393 return -ERESTART; 1394 1395 return size; 1396 } 1397 1398 static TOOL_FOPS_RDWR(tool_msg_event_fops, 1399 NULL, 1400 tool_msg_event_write); 1401 1402 static int tool_init_msgs(struct tool_ctx *tc) 1403 { 1404 int midx, pidx; 1405 1406 /* Initialize inbound message structures */ 1407 tc->inmsg_cnt = ntb_msg_count(tc->ntb); 1408 tc->inmsgs = devm_kcalloc(&tc->ntb->dev, tc->inmsg_cnt, 1409 sizeof(*tc->inmsgs), GFP_KERNEL); 1410 if (tc->inmsgs == NULL) 1411 return -ENOMEM; 1412 1413 for (midx = 0; midx < tc->inmsg_cnt; midx++) { 1414 tc->inmsgs[midx].midx = midx; 1415 tc->inmsgs[midx].pidx = -1; 1416 tc->inmsgs[midx].tc = tc; 1417 } 1418 1419 /* Initialize outbound message structures */ 1420 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1421 tc->peers[pidx].outmsg_cnt = ntb_msg_count(tc->ntb); 1422 tc->peers[pidx].outmsgs = 1423 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmsg_cnt, 1424 sizeof(*tc->peers[pidx].outmsgs), GFP_KERNEL); 1425 if (tc->peers[pidx].outmsgs == NULL) 1426 return -ENOMEM; 1427 1428 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) { 1429 tc->peers[pidx].outmsgs[midx].midx = midx; 1430 tc->peers[pidx].outmsgs[midx].pidx = pidx; 1431 tc->peers[pidx].outmsgs[midx].tc = tc; 1432 } 1433 } 1434 1435 return 0; 1436 } 1437 1438 /*============================================================================== 1439 * Initialization methods 1440 *============================================================================== 1441 */ 1442 1443 static struct tool_ctx *tool_create_data(struct ntb_dev *ntb) 1444 { 1445 struct tool_ctx *tc; 1446 1447 tc = devm_kzalloc(&ntb->dev, sizeof(*tc), GFP_KERNEL); 1448 if (tc == NULL) 1449 return ERR_PTR(-ENOMEM); 1450 1451 tc->ntb = ntb; 1452 init_waitqueue_head(&tc->link_wq); 1453 init_waitqueue_head(&tc->db_wq); 1454 init_waitqueue_head(&tc->msg_wq); 1455 1456 if (ntb_db_is_unsafe(ntb)) 1457 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 1458 1459 if (ntb_spad_is_unsafe(ntb)) 1460 dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 1461 1462 return tc; 1463 } 1464 1465 static void tool_clear_data(struct tool_ctx *tc) 1466 { 1467 wake_up(&tc->link_wq); 1468 wake_up(&tc->db_wq); 1469 wake_up(&tc->msg_wq); 1470 } 1471 1472 static int tool_init_ntb(struct tool_ctx *tc) 1473 { 1474 return ntb_set_ctx(tc->ntb, tc, &tool_ops); 1475 } 1476 1477 static void tool_clear_ntb(struct tool_ctx *tc) 1478 { 1479 ntb_clear_ctx(tc->ntb); 1480 ntb_link_disable(tc->ntb); 1481 } 1482 1483 static void tool_setup_dbgfs(struct tool_ctx *tc) 1484 { 1485 int pidx, widx, sidx, midx; 1486 char buf[TOOL_BUF_LEN]; 1487 1488 /* This modules is useless without dbgfs... */ 1489 if (!tool_dbgfs_topdir) { 1490 tc->dbgfs_dir = NULL; 1491 return; 1492 } 1493 1494 tc->dbgfs_dir = debugfs_create_dir(dev_name(&tc->ntb->dev), 1495 tool_dbgfs_topdir); 1496 if (!tc->dbgfs_dir) 1497 return; 1498 1499 debugfs_create_file("port", 0600, tc->dbgfs_dir, 1500 tc, &tool_port_fops); 1501 1502 debugfs_create_file("link", 0600, tc->dbgfs_dir, 1503 tc, &tool_link_fops); 1504 1505 debugfs_create_file("db", 0600, tc->dbgfs_dir, 1506 tc, &tool_db_fops); 1507 1508 debugfs_create_file("db_valid_mask", 0600, tc->dbgfs_dir, 1509 tc, &tool_db_valid_mask_fops); 1510 1511 debugfs_create_file("db_mask", 0600, tc->dbgfs_dir, 1512 tc, &tool_db_mask_fops); 1513 1514 debugfs_create_file("db_event", 0600, tc->dbgfs_dir, 1515 tc, &tool_db_event_fops); 1516 1517 debugfs_create_file("peer_db", 0600, tc->dbgfs_dir, 1518 tc, &tool_peer_db_fops); 1519 1520 debugfs_create_file("peer_db_mask", 0600, tc->dbgfs_dir, 1521 tc, &tool_peer_db_mask_fops); 1522 1523 if (tc->inspad_cnt != 0) { 1524 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 1525 snprintf(buf, sizeof(buf), "spad%d", sidx); 1526 1527 debugfs_create_file(buf, 0600, tc->dbgfs_dir, 1528 &tc->inspads[sidx], &tool_spad_fops); 1529 } 1530 } 1531 1532 if (tc->inmsg_cnt != 0) { 1533 for (midx = 0; midx < tc->inmsg_cnt; midx++) { 1534 snprintf(buf, sizeof(buf), "msg%d", midx); 1535 debugfs_create_file(buf, 0600, tc->dbgfs_dir, 1536 &tc->inmsgs[midx], &tool_inmsg_fops); 1537 } 1538 1539 debugfs_create_file("msg_sts", 0600, tc->dbgfs_dir, 1540 tc, &tool_msg_sts_fops); 1541 1542 debugfs_create_file("msg_inbits", 0600, tc->dbgfs_dir, 1543 tc, &tool_msg_inbits_fops); 1544 1545 debugfs_create_file("msg_outbits", 0600, tc->dbgfs_dir, 1546 tc, &tool_msg_outbits_fops); 1547 1548 debugfs_create_file("msg_mask", 0600, tc->dbgfs_dir, 1549 tc, &tool_msg_mask_fops); 1550 1551 debugfs_create_file("msg_event", 0600, tc->dbgfs_dir, 1552 tc, &tool_msg_event_fops); 1553 } 1554 1555 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1556 snprintf(buf, sizeof(buf), "peer%d", pidx); 1557 tc->peers[pidx].dbgfs_dir = 1558 debugfs_create_dir(buf, tc->dbgfs_dir); 1559 1560 debugfs_create_file("port", 0600, 1561 tc->peers[pidx].dbgfs_dir, 1562 &tc->peers[pidx], &tool_peer_port_fops); 1563 1564 debugfs_create_file("link", 0200, 1565 tc->peers[pidx].dbgfs_dir, 1566 &tc->peers[pidx], &tool_peer_link_fops); 1567 1568 debugfs_create_file("link_event", 0200, 1569 tc->peers[pidx].dbgfs_dir, 1570 &tc->peers[pidx], &tool_peer_link_event_fops); 1571 1572 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 1573 snprintf(buf, sizeof(buf), "mw_trans%d", widx); 1574 debugfs_create_file(buf, 0600, 1575 tc->peers[pidx].dbgfs_dir, 1576 &tc->peers[pidx].inmws[widx], 1577 &tool_mw_trans_fops); 1578 } 1579 1580 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) { 1581 snprintf(buf, sizeof(buf), "peer_mw_trans%d", widx); 1582 debugfs_create_file(buf, 0600, 1583 tc->peers[pidx].dbgfs_dir, 1584 &tc->peers[pidx].outmws[widx], 1585 &tool_peer_mw_trans_fops); 1586 } 1587 1588 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 1589 snprintf(buf, sizeof(buf), "spad%d", sidx); 1590 1591 debugfs_create_file(buf, 0600, 1592 tc->peers[pidx].dbgfs_dir, 1593 &tc->peers[pidx].outspads[sidx], 1594 &tool_peer_spad_fops); 1595 } 1596 1597 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) { 1598 snprintf(buf, sizeof(buf), "msg%d", midx); 1599 debugfs_create_file(buf, 0600, 1600 tc->peers[pidx].dbgfs_dir, 1601 &tc->peers[pidx].outmsgs[midx], 1602 &tool_outmsg_fops); 1603 } 1604 } 1605 } 1606 1607 static void tool_clear_dbgfs(struct tool_ctx *tc) 1608 { 1609 debugfs_remove_recursive(tc->dbgfs_dir); 1610 } 1611 1612 static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) 1613 { 1614 struct tool_ctx *tc; 1615 int ret; 1616 1617 tc = tool_create_data(ntb); 1618 if (IS_ERR(tc)) 1619 return PTR_ERR(tc); 1620 1621 ret = tool_init_peers(tc); 1622 if (ret != 0) 1623 goto err_clear_data; 1624 1625 ret = tool_init_mws(tc); 1626 if (ret != 0) 1627 goto err_clear_data; 1628 1629 ret = tool_init_spads(tc); 1630 if (ret != 0) 1631 goto err_clear_mws; 1632 1633 ret = tool_init_msgs(tc); 1634 if (ret != 0) 1635 goto err_clear_mws; 1636 1637 ret = tool_init_ntb(tc); 1638 if (ret != 0) 1639 goto err_clear_mws; 1640 1641 tool_setup_dbgfs(tc); 1642 1643 return 0; 1644 1645 err_clear_mws: 1646 tool_clear_mws(tc); 1647 1648 err_clear_data: 1649 tool_clear_data(tc); 1650 1651 return ret; 1652 } 1653 1654 static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb) 1655 { 1656 struct tool_ctx *tc = ntb->ctx; 1657 1658 tool_clear_dbgfs(tc); 1659 1660 tool_clear_ntb(tc); 1661 1662 tool_clear_mws(tc); 1663 1664 tool_clear_data(tc); 1665 } 1666 1667 static struct ntb_client tool_client = { 1668 .ops = { 1669 .probe = tool_probe, 1670 .remove = tool_remove, 1671 } 1672 }; 1673 1674 static int __init tool_init(void) 1675 { 1676 int ret; 1677 1678 if (debugfs_initialized()) 1679 tool_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL); 1680 1681 ret = ntb_register_client(&tool_client); 1682 if (ret) 1683 debugfs_remove_recursive(tool_dbgfs_topdir); 1684 1685 return ret; 1686 } 1687 module_init(tool_init); 1688 1689 static void __exit tool_exit(void) 1690 { 1691 ntb_unregister_client(&tool_client); 1692 debugfs_remove_recursive(tool_dbgfs_topdir); 1693 } 1694 module_exit(tool_exit); 1695