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 if (tc->peers[pidx].outmws == NULL) 1002 return -ENOMEM; 1003 1004 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) { 1005 tc->peers[pidx].outmws[widx].pidx = pidx; 1006 tc->peers[pidx].outmws[widx].mw = &tc->outmws[widx]; 1007 } 1008 } 1009 1010 return 0; 1011 } 1012 1013 static void tool_clear_mws(struct tool_ctx *tc) 1014 { 1015 int widx, pidx; 1016 1017 /* Free outbound memory windows */ 1018 for (widx = 0; widx < tc->outmw_cnt; widx++) 1019 tool_free_peer_mw(tc, widx); 1020 1021 /* Free outbound memory windows */ 1022 for (pidx = 0; pidx < tc->peer_cnt; pidx++) 1023 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) 1024 tool_free_mw(tc, pidx, widx); 1025 } 1026 1027 /*============================================================================== 1028 * Doorbell read/write methods 1029 *============================================================================== 1030 */ 1031 1032 static ssize_t tool_db_read(struct file *filep, char __user *ubuf, 1033 size_t size, loff_t *offp) 1034 { 1035 struct tool_ctx *tc = filep->private_data; 1036 1037 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read); 1038 } 1039 1040 static ssize_t tool_db_write(struct file *filep, const char __user *ubuf, 1041 size_t size, loff_t *offp) 1042 { 1043 struct tool_ctx *tc = filep->private_data; 1044 1045 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set, 1046 tc->ntb->ops->db_clear); 1047 } 1048 1049 static TOOL_FOPS_RDWR(tool_db_fops, 1050 tool_db_read, 1051 tool_db_write); 1052 1053 static ssize_t tool_db_valid_mask_read(struct file *filep, char __user *ubuf, 1054 size_t size, loff_t *offp) 1055 { 1056 struct tool_ctx *tc = filep->private_data; 1057 1058 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_valid_mask); 1059 } 1060 1061 static TOOL_FOPS_RDWR(tool_db_valid_mask_fops, 1062 tool_db_valid_mask_read, 1063 NULL); 1064 1065 static ssize_t tool_db_mask_read(struct file *filep, char __user *ubuf, 1066 size_t size, loff_t *offp) 1067 { 1068 struct tool_ctx *tc = filep->private_data; 1069 1070 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read_mask); 1071 } 1072 1073 static ssize_t tool_db_mask_write(struct file *filep, const char __user *ubuf, 1074 size_t size, loff_t *offp) 1075 { 1076 struct tool_ctx *tc = filep->private_data; 1077 1078 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set_mask, 1079 tc->ntb->ops->db_clear_mask); 1080 } 1081 1082 static TOOL_FOPS_RDWR(tool_db_mask_fops, 1083 tool_db_mask_read, 1084 tool_db_mask_write); 1085 1086 static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf, 1087 size_t size, loff_t *offp) 1088 { 1089 struct tool_ctx *tc = filep->private_data; 1090 1091 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->peer_db_read); 1092 } 1093 1094 static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf, 1095 size_t size, loff_t *offp) 1096 { 1097 struct tool_ctx *tc = filep->private_data; 1098 1099 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->peer_db_set, 1100 tc->ntb->ops->peer_db_clear); 1101 } 1102 1103 static TOOL_FOPS_RDWR(tool_peer_db_fops, 1104 tool_peer_db_read, 1105 tool_peer_db_write); 1106 1107 static ssize_t tool_peer_db_mask_read(struct file *filep, char __user *ubuf, 1108 size_t size, loff_t *offp) 1109 { 1110 struct tool_ctx *tc = filep->private_data; 1111 1112 return tool_fn_read(tc, ubuf, size, offp, 1113 tc->ntb->ops->peer_db_read_mask); 1114 } 1115 1116 static ssize_t tool_peer_db_mask_write(struct file *filep, 1117 const char __user *ubuf, 1118 size_t size, loff_t *offp) 1119 { 1120 struct tool_ctx *tc = filep->private_data; 1121 1122 return tool_fn_write(tc, ubuf, size, offp, 1123 tc->ntb->ops->peer_db_set_mask, 1124 tc->ntb->ops->peer_db_clear_mask); 1125 } 1126 1127 static TOOL_FOPS_RDWR(tool_peer_db_mask_fops, 1128 tool_peer_db_mask_read, 1129 tool_peer_db_mask_write); 1130 1131 static ssize_t tool_db_event_write(struct file *filep, 1132 const char __user *ubuf, 1133 size_t size, loff_t *offp) 1134 { 1135 struct tool_ctx *tc = filep->private_data; 1136 u64 val; 1137 int ret; 1138 1139 ret = kstrtou64_from_user(ubuf, size, 0, &val); 1140 if (ret) 1141 return ret; 1142 1143 if (wait_event_interruptible(tc->db_wq, ntb_db_read(tc->ntb) == val)) 1144 return -ERESTART; 1145 1146 return size; 1147 } 1148 1149 static TOOL_FOPS_RDWR(tool_db_event_fops, 1150 NULL, 1151 tool_db_event_write); 1152 1153 /*============================================================================== 1154 * Scratchpads read/write methods 1155 *============================================================================== 1156 */ 1157 1158 static ssize_t tool_spad_read(struct file *filep, char __user *ubuf, 1159 size_t size, loff_t *offp) 1160 { 1161 struct tool_spad *spad = filep->private_data; 1162 char buf[TOOL_BUF_LEN]; 1163 ssize_t pos; 1164 1165 if (!spad->tc->ntb->ops->spad_read) 1166 return -EINVAL; 1167 1168 pos = scnprintf(buf, sizeof(buf), "%#x\n", 1169 ntb_spad_read(spad->tc->ntb, spad->sidx)); 1170 1171 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 1172 } 1173 1174 static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf, 1175 size_t size, loff_t *offp) 1176 { 1177 struct tool_spad *spad = filep->private_data; 1178 u32 val; 1179 int ret; 1180 1181 if (!spad->tc->ntb->ops->spad_write) { 1182 dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n"); 1183 return -EINVAL; 1184 } 1185 1186 ret = kstrtou32_from_user(ubuf, size, 0, &val); 1187 if (ret) 1188 return ret; 1189 1190 ret = ntb_spad_write(spad->tc->ntb, spad->sidx, val); 1191 1192 return ret ?: size; 1193 } 1194 1195 static TOOL_FOPS_RDWR(tool_spad_fops, 1196 tool_spad_read, 1197 tool_spad_write); 1198 1199 static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf, 1200 size_t size, loff_t *offp) 1201 { 1202 struct tool_spad *spad = filep->private_data; 1203 char buf[TOOL_BUF_LEN]; 1204 ssize_t pos; 1205 1206 if (!spad->tc->ntb->ops->peer_spad_read) 1207 return -EINVAL; 1208 1209 pos = scnprintf(buf, sizeof(buf), "%#x\n", 1210 ntb_peer_spad_read(spad->tc->ntb, spad->pidx, spad->sidx)); 1211 1212 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 1213 } 1214 1215 static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf, 1216 size_t size, loff_t *offp) 1217 { 1218 struct tool_spad *spad = filep->private_data; 1219 u32 val; 1220 int ret; 1221 1222 if (!spad->tc->ntb->ops->peer_spad_write) { 1223 dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n"); 1224 return -EINVAL; 1225 } 1226 1227 ret = kstrtou32_from_user(ubuf, size, 0, &val); 1228 if (ret) 1229 return ret; 1230 1231 ret = ntb_peer_spad_write(spad->tc->ntb, spad->pidx, spad->sidx, val); 1232 1233 return ret ?: size; 1234 } 1235 1236 static TOOL_FOPS_RDWR(tool_peer_spad_fops, 1237 tool_peer_spad_read, 1238 tool_peer_spad_write); 1239 1240 static int tool_init_spads(struct tool_ctx *tc) 1241 { 1242 int sidx, pidx; 1243 1244 /* Initialize inbound scratchpad structures */ 1245 tc->inspad_cnt = ntb_spad_count(tc->ntb); 1246 tc->inspads = devm_kcalloc(&tc->ntb->dev, tc->inspad_cnt, 1247 sizeof(*tc->inspads), GFP_KERNEL); 1248 if (tc->inspads == NULL) 1249 return -ENOMEM; 1250 1251 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 1252 tc->inspads[sidx].sidx = sidx; 1253 tc->inspads[sidx].pidx = -1; 1254 tc->inspads[sidx].tc = tc; 1255 } 1256 1257 /* Initialize outbound scratchpad structures */ 1258 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1259 tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->ntb); 1260 tc->peers[pidx].outspads = 1261 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outspad_cnt, 1262 sizeof(*tc->peers[pidx].outspads), GFP_KERNEL); 1263 if (tc->peers[pidx].outspads == NULL) 1264 return -ENOMEM; 1265 1266 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 1267 tc->peers[pidx].outspads[sidx].sidx = sidx; 1268 tc->peers[pidx].outspads[sidx].pidx = pidx; 1269 tc->peers[pidx].outspads[sidx].tc = tc; 1270 } 1271 } 1272 1273 return 0; 1274 } 1275 1276 /*============================================================================== 1277 * Messages read/write methods 1278 *============================================================================== 1279 */ 1280 1281 static ssize_t tool_inmsg_read(struct file *filep, char __user *ubuf, 1282 size_t size, loff_t *offp) 1283 { 1284 struct tool_msg *msg = filep->private_data; 1285 char buf[TOOL_BUF_LEN]; 1286 ssize_t pos; 1287 u32 data; 1288 int pidx; 1289 1290 data = ntb_msg_read(msg->tc->ntb, &pidx, msg->midx); 1291 1292 pos = scnprintf(buf, sizeof(buf), "0x%08x<-%d\n", data, pidx); 1293 1294 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 1295 } 1296 1297 static TOOL_FOPS_RDWR(tool_inmsg_fops, 1298 tool_inmsg_read, 1299 NULL); 1300 1301 static ssize_t tool_outmsg_write(struct file *filep, 1302 const char __user *ubuf, 1303 size_t size, loff_t *offp) 1304 { 1305 struct tool_msg *msg = filep->private_data; 1306 u32 val; 1307 int ret; 1308 1309 ret = kstrtou32_from_user(ubuf, size, 0, &val); 1310 if (ret) 1311 return ret; 1312 1313 ret = ntb_peer_msg_write(msg->tc->ntb, msg->pidx, msg->midx, val); 1314 1315 return ret ? : size; 1316 } 1317 1318 static TOOL_FOPS_RDWR(tool_outmsg_fops, 1319 NULL, 1320 tool_outmsg_write); 1321 1322 static ssize_t tool_msg_sts_read(struct file *filep, char __user *ubuf, 1323 size_t size, loff_t *offp) 1324 { 1325 struct tool_ctx *tc = filep->private_data; 1326 1327 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_read_sts); 1328 } 1329 1330 static ssize_t tool_msg_sts_write(struct file *filep, const char __user *ubuf, 1331 size_t size, loff_t *offp) 1332 { 1333 struct tool_ctx *tc = filep->private_data; 1334 1335 return tool_fn_write(tc, ubuf, size, offp, NULL, 1336 tc->ntb->ops->msg_clear_sts); 1337 } 1338 1339 static TOOL_FOPS_RDWR(tool_msg_sts_fops, 1340 tool_msg_sts_read, 1341 tool_msg_sts_write); 1342 1343 static ssize_t tool_msg_inbits_read(struct file *filep, char __user *ubuf, 1344 size_t size, loff_t *offp) 1345 { 1346 struct tool_ctx *tc = filep->private_data; 1347 1348 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_inbits); 1349 } 1350 1351 static TOOL_FOPS_RDWR(tool_msg_inbits_fops, 1352 tool_msg_inbits_read, 1353 NULL); 1354 1355 static ssize_t tool_msg_outbits_read(struct file *filep, char __user *ubuf, 1356 size_t size, loff_t *offp) 1357 { 1358 struct tool_ctx *tc = filep->private_data; 1359 1360 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_outbits); 1361 } 1362 1363 static TOOL_FOPS_RDWR(tool_msg_outbits_fops, 1364 tool_msg_outbits_read, 1365 NULL); 1366 1367 static ssize_t tool_msg_mask_write(struct file *filep, const char __user *ubuf, 1368 size_t size, loff_t *offp) 1369 { 1370 struct tool_ctx *tc = filep->private_data; 1371 1372 return tool_fn_write(tc, ubuf, size, offp, 1373 tc->ntb->ops->msg_set_mask, 1374 tc->ntb->ops->msg_clear_mask); 1375 } 1376 1377 static TOOL_FOPS_RDWR(tool_msg_mask_fops, 1378 NULL, 1379 tool_msg_mask_write); 1380 1381 static ssize_t tool_msg_event_write(struct file *filep, 1382 const char __user *ubuf, 1383 size_t size, loff_t *offp) 1384 { 1385 struct tool_ctx *tc = filep->private_data; 1386 u64 val; 1387 int ret; 1388 1389 ret = kstrtou64_from_user(ubuf, size, 0, &val); 1390 if (ret) 1391 return ret; 1392 1393 if (wait_event_interruptible(tc->msg_wq, 1394 ntb_msg_read_sts(tc->ntb) == val)) 1395 return -ERESTART; 1396 1397 return size; 1398 } 1399 1400 static TOOL_FOPS_RDWR(tool_msg_event_fops, 1401 NULL, 1402 tool_msg_event_write); 1403 1404 static int tool_init_msgs(struct tool_ctx *tc) 1405 { 1406 int midx, pidx; 1407 1408 /* Initialize inbound message structures */ 1409 tc->inmsg_cnt = ntb_msg_count(tc->ntb); 1410 tc->inmsgs = devm_kcalloc(&tc->ntb->dev, tc->inmsg_cnt, 1411 sizeof(*tc->inmsgs), GFP_KERNEL); 1412 if (tc->inmsgs == NULL) 1413 return -ENOMEM; 1414 1415 for (midx = 0; midx < tc->inmsg_cnt; midx++) { 1416 tc->inmsgs[midx].midx = midx; 1417 tc->inmsgs[midx].pidx = -1; 1418 tc->inmsgs[midx].tc = tc; 1419 } 1420 1421 /* Initialize outbound message structures */ 1422 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1423 tc->peers[pidx].outmsg_cnt = ntb_msg_count(tc->ntb); 1424 tc->peers[pidx].outmsgs = 1425 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmsg_cnt, 1426 sizeof(*tc->peers[pidx].outmsgs), GFP_KERNEL); 1427 if (tc->peers[pidx].outmsgs == NULL) 1428 return -ENOMEM; 1429 1430 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) { 1431 tc->peers[pidx].outmsgs[midx].midx = midx; 1432 tc->peers[pidx].outmsgs[midx].pidx = pidx; 1433 tc->peers[pidx].outmsgs[midx].tc = tc; 1434 } 1435 } 1436 1437 return 0; 1438 } 1439 1440 /*============================================================================== 1441 * Initialization methods 1442 *============================================================================== 1443 */ 1444 1445 static struct tool_ctx *tool_create_data(struct ntb_dev *ntb) 1446 { 1447 struct tool_ctx *tc; 1448 1449 tc = devm_kzalloc(&ntb->dev, sizeof(*tc), GFP_KERNEL); 1450 if (tc == NULL) 1451 return ERR_PTR(-ENOMEM); 1452 1453 tc->ntb = ntb; 1454 init_waitqueue_head(&tc->link_wq); 1455 init_waitqueue_head(&tc->db_wq); 1456 init_waitqueue_head(&tc->msg_wq); 1457 1458 if (ntb_db_is_unsafe(ntb)) 1459 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 1460 1461 if (ntb_spad_is_unsafe(ntb)) 1462 dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 1463 1464 return tc; 1465 } 1466 1467 static void tool_clear_data(struct tool_ctx *tc) 1468 { 1469 wake_up(&tc->link_wq); 1470 wake_up(&tc->db_wq); 1471 wake_up(&tc->msg_wq); 1472 } 1473 1474 static int tool_init_ntb(struct tool_ctx *tc) 1475 { 1476 return ntb_set_ctx(tc->ntb, tc, &tool_ops); 1477 } 1478 1479 static void tool_clear_ntb(struct tool_ctx *tc) 1480 { 1481 ntb_clear_ctx(tc->ntb); 1482 ntb_link_disable(tc->ntb); 1483 } 1484 1485 static void tool_setup_dbgfs(struct tool_ctx *tc) 1486 { 1487 int pidx, widx, sidx, midx; 1488 char buf[TOOL_BUF_LEN]; 1489 1490 /* This modules is useless without dbgfs... */ 1491 if (!tool_dbgfs_topdir) { 1492 tc->dbgfs_dir = NULL; 1493 return; 1494 } 1495 1496 tc->dbgfs_dir = debugfs_create_dir(dev_name(&tc->ntb->dev), 1497 tool_dbgfs_topdir); 1498 if (!tc->dbgfs_dir) 1499 return; 1500 1501 debugfs_create_file("port", 0600, tc->dbgfs_dir, 1502 tc, &tool_port_fops); 1503 1504 debugfs_create_file("link", 0600, tc->dbgfs_dir, 1505 tc, &tool_link_fops); 1506 1507 debugfs_create_file("db", 0600, tc->dbgfs_dir, 1508 tc, &tool_db_fops); 1509 1510 debugfs_create_file("db_valid_mask", 0600, tc->dbgfs_dir, 1511 tc, &tool_db_valid_mask_fops); 1512 1513 debugfs_create_file("db_mask", 0600, tc->dbgfs_dir, 1514 tc, &tool_db_mask_fops); 1515 1516 debugfs_create_file("db_event", 0600, tc->dbgfs_dir, 1517 tc, &tool_db_event_fops); 1518 1519 debugfs_create_file("peer_db", 0600, tc->dbgfs_dir, 1520 tc, &tool_peer_db_fops); 1521 1522 debugfs_create_file("peer_db_mask", 0600, tc->dbgfs_dir, 1523 tc, &tool_peer_db_mask_fops); 1524 1525 if (tc->inspad_cnt != 0) { 1526 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 1527 snprintf(buf, sizeof(buf), "spad%d", sidx); 1528 1529 debugfs_create_file(buf, 0600, tc->dbgfs_dir, 1530 &tc->inspads[sidx], &tool_spad_fops); 1531 } 1532 } 1533 1534 if (tc->inmsg_cnt != 0) { 1535 for (midx = 0; midx < tc->inmsg_cnt; midx++) { 1536 snprintf(buf, sizeof(buf), "msg%d", midx); 1537 debugfs_create_file(buf, 0600, tc->dbgfs_dir, 1538 &tc->inmsgs[midx], &tool_inmsg_fops); 1539 } 1540 1541 debugfs_create_file("msg_sts", 0600, tc->dbgfs_dir, 1542 tc, &tool_msg_sts_fops); 1543 1544 debugfs_create_file("msg_inbits", 0600, tc->dbgfs_dir, 1545 tc, &tool_msg_inbits_fops); 1546 1547 debugfs_create_file("msg_outbits", 0600, tc->dbgfs_dir, 1548 tc, &tool_msg_outbits_fops); 1549 1550 debugfs_create_file("msg_mask", 0600, tc->dbgfs_dir, 1551 tc, &tool_msg_mask_fops); 1552 1553 debugfs_create_file("msg_event", 0600, tc->dbgfs_dir, 1554 tc, &tool_msg_event_fops); 1555 } 1556 1557 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1558 snprintf(buf, sizeof(buf), "peer%d", pidx); 1559 tc->peers[pidx].dbgfs_dir = 1560 debugfs_create_dir(buf, tc->dbgfs_dir); 1561 1562 debugfs_create_file("port", 0600, 1563 tc->peers[pidx].dbgfs_dir, 1564 &tc->peers[pidx], &tool_peer_port_fops); 1565 1566 debugfs_create_file("link", 0200, 1567 tc->peers[pidx].dbgfs_dir, 1568 &tc->peers[pidx], &tool_peer_link_fops); 1569 1570 debugfs_create_file("link_event", 0200, 1571 tc->peers[pidx].dbgfs_dir, 1572 &tc->peers[pidx], &tool_peer_link_event_fops); 1573 1574 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 1575 snprintf(buf, sizeof(buf), "mw_trans%d", widx); 1576 debugfs_create_file(buf, 0600, 1577 tc->peers[pidx].dbgfs_dir, 1578 &tc->peers[pidx].inmws[widx], 1579 &tool_mw_trans_fops); 1580 } 1581 1582 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) { 1583 snprintf(buf, sizeof(buf), "peer_mw_trans%d", widx); 1584 debugfs_create_file(buf, 0600, 1585 tc->peers[pidx].dbgfs_dir, 1586 &tc->peers[pidx].outmws[widx], 1587 &tool_peer_mw_trans_fops); 1588 } 1589 1590 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 1591 snprintf(buf, sizeof(buf), "spad%d", sidx); 1592 1593 debugfs_create_file(buf, 0600, 1594 tc->peers[pidx].dbgfs_dir, 1595 &tc->peers[pidx].outspads[sidx], 1596 &tool_peer_spad_fops); 1597 } 1598 1599 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) { 1600 snprintf(buf, sizeof(buf), "msg%d", midx); 1601 debugfs_create_file(buf, 0600, 1602 tc->peers[pidx].dbgfs_dir, 1603 &tc->peers[pidx].outmsgs[midx], 1604 &tool_outmsg_fops); 1605 } 1606 } 1607 } 1608 1609 static void tool_clear_dbgfs(struct tool_ctx *tc) 1610 { 1611 debugfs_remove_recursive(tc->dbgfs_dir); 1612 } 1613 1614 static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) 1615 { 1616 struct tool_ctx *tc; 1617 int ret; 1618 1619 tc = tool_create_data(ntb); 1620 if (IS_ERR(tc)) 1621 return PTR_ERR(tc); 1622 1623 ret = tool_init_peers(tc); 1624 if (ret != 0) 1625 goto err_clear_data; 1626 1627 ret = tool_init_mws(tc); 1628 if (ret != 0) 1629 goto err_clear_data; 1630 1631 ret = tool_init_spads(tc); 1632 if (ret != 0) 1633 goto err_clear_mws; 1634 1635 ret = tool_init_msgs(tc); 1636 if (ret != 0) 1637 goto err_clear_mws; 1638 1639 ret = tool_init_ntb(tc); 1640 if (ret != 0) 1641 goto err_clear_mws; 1642 1643 tool_setup_dbgfs(tc); 1644 1645 return 0; 1646 1647 err_clear_mws: 1648 tool_clear_mws(tc); 1649 1650 err_clear_data: 1651 tool_clear_data(tc); 1652 1653 return ret; 1654 } 1655 1656 static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb) 1657 { 1658 struct tool_ctx *tc = ntb->ctx; 1659 1660 tool_clear_dbgfs(tc); 1661 1662 tool_clear_ntb(tc); 1663 1664 tool_clear_mws(tc); 1665 1666 tool_clear_data(tc); 1667 } 1668 1669 static struct ntb_client tool_client = { 1670 .ops = { 1671 .probe = tool_probe, 1672 .remove = tool_remove, 1673 } 1674 }; 1675 1676 static int __init tool_init(void) 1677 { 1678 int ret; 1679 1680 if (debugfs_initialized()) 1681 tool_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL); 1682 1683 ret = ntb_register_client(&tool_client); 1684 if (ret) 1685 debugfs_remove_recursive(tool_dbgfs_topdir); 1686 1687 return ret; 1688 } 1689 module_init(tool_init); 1690 1691 static void __exit tool_exit(void) 1692 { 1693 ntb_unregister_client(&tool_client); 1694 debugfs_remove_recursive(tool_dbgfs_topdir); 1695 } 1696 module_exit(tool_exit); 1697