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 = memdup_user_nul(ubuf, size); 374 if (IS_ERR(buf)) 375 return PTR_ERR(buf); 376 377 n = sscanf(buf, "%c %lli", &cmd, &bits); 378 379 kfree(buf); 380 381 if (n != 2) { 382 ret = -EINVAL; 383 } else if (cmd == 's') { 384 if (!fn_set) 385 ret = -EINVAL; 386 else 387 ret = fn_set(tc->ntb, bits); 388 } else if (cmd == 'c') { 389 if (!fn_clear) 390 ret = -EINVAL; 391 else 392 ret = fn_clear(tc->ntb, bits); 393 } else { 394 ret = -EINVAL; 395 } 396 397 return ret ? : size; 398 } 399 400 /*============================================================================== 401 * Port read/write methods 402 *============================================================================== 403 */ 404 405 static ssize_t tool_port_read(struct file *filep, char __user *ubuf, 406 size_t size, loff_t *offp) 407 { 408 struct tool_ctx *tc = filep->private_data; 409 char buf[TOOL_BUF_LEN]; 410 int pos; 411 412 pos = scnprintf(buf, sizeof(buf), "%d\n", ntb_port_number(tc->ntb)); 413 414 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 415 } 416 417 static TOOL_FOPS_RDWR(tool_port_fops, 418 tool_port_read, 419 NULL); 420 421 static ssize_t tool_peer_port_read(struct file *filep, char __user *ubuf, 422 size_t size, loff_t *offp) 423 { 424 struct tool_peer *peer = filep->private_data; 425 struct tool_ctx *tc = peer->tc; 426 char buf[TOOL_BUF_LEN]; 427 int pos; 428 429 pos = scnprintf(buf, sizeof(buf), "%d\n", 430 ntb_peer_port_number(tc->ntb, peer->pidx)); 431 432 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 433 } 434 435 static TOOL_FOPS_RDWR(tool_peer_port_fops, 436 tool_peer_port_read, 437 NULL); 438 439 static int tool_init_peers(struct tool_ctx *tc) 440 { 441 int pidx; 442 443 tc->peer_cnt = ntb_peer_port_count(tc->ntb); 444 tc->peers = devm_kzalloc_objs(&tc->ntb->dev, *tc->peers, tc->peer_cnt); 445 if (tc->peers == NULL) 446 return -ENOMEM; 447 448 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 449 tc->peers[pidx].pidx = pidx; 450 tc->peers[pidx].tc = tc; 451 } 452 453 return 0; 454 } 455 456 /*============================================================================== 457 * Link state read/write methods 458 *============================================================================== 459 */ 460 461 static ssize_t tool_link_write(struct file *filep, const char __user *ubuf, 462 size_t size, loff_t *offp) 463 { 464 struct tool_ctx *tc = filep->private_data; 465 bool val; 466 int ret; 467 468 ret = kstrtobool_from_user(ubuf, size, &val); 469 if (ret) 470 return ret; 471 472 if (val) 473 ret = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 474 else 475 ret = ntb_link_disable(tc->ntb); 476 477 if (ret) 478 return ret; 479 480 return size; 481 } 482 483 static TOOL_FOPS_RDWR(tool_link_fops, 484 NULL, 485 tool_link_write); 486 487 static ssize_t tool_peer_link_read(struct file *filep, char __user *ubuf, 488 size_t size, loff_t *offp) 489 { 490 struct tool_peer *peer = filep->private_data; 491 struct tool_ctx *tc = peer->tc; 492 char buf[3]; 493 494 if (ntb_link_is_up(tc->ntb, NULL, NULL) & BIT(peer->pidx)) 495 buf[0] = 'Y'; 496 else 497 buf[0] = 'N'; 498 buf[1] = '\n'; 499 buf[2] = '\0'; 500 501 return simple_read_from_buffer(ubuf, size, offp, buf, 2); 502 } 503 504 static TOOL_FOPS_RDWR(tool_peer_link_fops, 505 tool_peer_link_read, 506 NULL); 507 508 static ssize_t tool_peer_link_event_write(struct file *filep, 509 const char __user *ubuf, 510 size_t size, loff_t *offp) 511 { 512 struct tool_peer *peer = filep->private_data; 513 struct tool_ctx *tc = peer->tc; 514 u64 link_msk; 515 bool val; 516 int ret; 517 518 ret = kstrtobool_from_user(ubuf, size, &val); 519 if (ret) 520 return ret; 521 522 link_msk = BIT_ULL_MASK(peer->pidx); 523 524 if (wait_event_interruptible(tc->link_wq, 525 !!(ntb_link_is_up(tc->ntb, NULL, NULL) & link_msk) == val)) 526 return -ERESTART; 527 528 return size; 529 } 530 531 static TOOL_FOPS_RDWR(tool_peer_link_event_fops, 532 NULL, 533 tool_peer_link_event_write); 534 535 /*============================================================================== 536 * Memory windows read/write/setting methods 537 *============================================================================== 538 */ 539 540 static ssize_t tool_mw_read(struct file *filep, char __user *ubuf, 541 size_t size, loff_t *offp) 542 { 543 struct tool_mw *inmw = filep->private_data; 544 545 if (inmw->mm_base == NULL) 546 return -ENXIO; 547 548 return simple_read_from_buffer(ubuf, size, offp, 549 inmw->mm_base, inmw->size); 550 } 551 552 static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf, 553 size_t size, loff_t *offp) 554 { 555 struct tool_mw *inmw = filep->private_data; 556 557 if (inmw->mm_base == NULL) 558 return -ENXIO; 559 560 return simple_write_to_buffer(inmw->mm_base, inmw->size, offp, 561 ubuf, size); 562 } 563 564 static TOOL_FOPS_RDWR(tool_mw_fops, 565 tool_mw_read, 566 tool_mw_write); 567 568 static int tool_setup_mw(struct tool_ctx *tc, int pidx, int widx, 569 size_t req_size) 570 { 571 resource_size_t size, addr_align, size_align; 572 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; 573 char buf[TOOL_BUF_LEN]; 574 int ret; 575 576 if (inmw->mm_base != NULL) 577 return 0; 578 579 ret = ntb_mw_get_align(tc->ntb, pidx, widx, &addr_align, 580 &size_align, &size); 581 if (ret) 582 return ret; 583 584 inmw->size = min_t(resource_size_t, req_size, size); 585 inmw->size = round_up(inmw->size, addr_align); 586 inmw->size = round_up(inmw->size, size_align); 587 inmw->mm_base = dma_alloc_coherent(&tc->ntb->pdev->dev, inmw->size, 588 &inmw->dma_base, GFP_KERNEL); 589 if (!inmw->mm_base) 590 return -ENOMEM; 591 592 if (!IS_ALIGNED(inmw->dma_base, addr_align)) { 593 ret = -ENOMEM; 594 goto err_free_dma; 595 } 596 597 ret = ntb_mw_set_trans(tc->ntb, pidx, widx, inmw->dma_base, inmw->size); 598 if (ret) 599 goto err_free_dma; 600 601 snprintf(buf, sizeof(buf), "mw%d", widx); 602 inmw->dbgfs_file = debugfs_create_file(buf, 0600, 603 tc->peers[pidx].dbgfs_dir, inmw, 604 &tool_mw_fops); 605 606 return 0; 607 608 err_free_dma: 609 dma_free_coherent(&tc->ntb->pdev->dev, inmw->size, inmw->mm_base, 610 inmw->dma_base); 611 inmw->mm_base = NULL; 612 inmw->dma_base = 0; 613 inmw->size = 0; 614 615 return ret; 616 } 617 618 static void tool_free_mw(struct tool_ctx *tc, int pidx, int widx) 619 { 620 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; 621 622 debugfs_remove(inmw->dbgfs_file); 623 624 if (inmw->mm_base != NULL) { 625 ntb_mw_clear_trans(tc->ntb, pidx, widx); 626 dma_free_coherent(&tc->ntb->pdev->dev, inmw->size, 627 inmw->mm_base, inmw->dma_base); 628 } 629 630 inmw->mm_base = NULL; 631 inmw->dma_base = 0; 632 inmw->size = 0; 633 inmw->dbgfs_file = NULL; 634 } 635 636 static ssize_t tool_mw_trans_read(struct file *filep, char __user *ubuf, 637 size_t size, loff_t *offp) 638 { 639 struct tool_mw *inmw = filep->private_data; 640 resource_size_t addr_align; 641 resource_size_t size_align; 642 resource_size_t size_max; 643 ssize_t ret, off = 0; 644 size_t buf_size; 645 char *buf; 646 647 buf_size = min_t(size_t, size, 512); 648 649 buf = kmalloc(buf_size, GFP_KERNEL); 650 if (!buf) 651 return -ENOMEM; 652 653 ret = ntb_mw_get_align(inmw->tc->ntb, inmw->pidx, inmw->widx, 654 &addr_align, &size_align, &size_max); 655 if (ret) 656 goto err; 657 658 off += scnprintf(buf + off, buf_size - off, 659 "Inbound MW \t%d\n", 660 inmw->widx); 661 662 off += scnprintf(buf + off, buf_size - off, 663 "Port \t%d (%d)\n", 664 ntb_peer_port_number(inmw->tc->ntb, inmw->pidx), 665 inmw->pidx); 666 667 off += scnprintf(buf + off, buf_size - off, 668 "Window Address \t0x%pK\n", inmw->mm_base); 669 670 off += scnprintf(buf + off, buf_size - off, 671 "DMA Address \t%pad\n", 672 &inmw->dma_base); 673 674 off += scnprintf(buf + off, buf_size - off, 675 "Window Size \t%pap\n", 676 &inmw->size); 677 678 off += scnprintf(buf + off, buf_size - off, 679 "Alignment \t%pap\n", 680 &addr_align); 681 682 off += scnprintf(buf + off, buf_size - off, 683 "Size Alignment \t%pap\n", 684 &size_align); 685 686 off += scnprintf(buf + off, buf_size - off, 687 "Size Max \t%pap\n", 688 &size_max); 689 690 ret = simple_read_from_buffer(ubuf, size, offp, buf, off); 691 692 err: 693 kfree(buf); 694 695 return ret; 696 } 697 698 static ssize_t tool_mw_trans_write(struct file *filep, const char __user *ubuf, 699 size_t size, loff_t *offp) 700 { 701 struct tool_mw *inmw = filep->private_data; 702 unsigned int val; 703 int ret; 704 705 ret = kstrtouint_from_user(ubuf, size, 0, &val); 706 if (ret) 707 return ret; 708 709 tool_free_mw(inmw->tc, inmw->pidx, inmw->widx); 710 if (val) { 711 ret = tool_setup_mw(inmw->tc, inmw->pidx, inmw->widx, val); 712 if (ret) 713 return ret; 714 } 715 716 return size; 717 } 718 719 static TOOL_FOPS_RDWR(tool_mw_trans_fops, 720 tool_mw_trans_read, 721 tool_mw_trans_write); 722 723 static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf, 724 size_t size, loff_t *offp) 725 { 726 struct tool_mw *outmw = filep->private_data; 727 loff_t pos = *offp; 728 ssize_t ret; 729 void *buf; 730 731 if (outmw->io_base == NULL) 732 return -EIO; 733 734 if (pos >= outmw->size || !size) 735 return 0; 736 737 if (size > outmw->size - pos) 738 size = outmw->size - pos; 739 740 buf = kmalloc(size, GFP_KERNEL); 741 if (!buf) 742 return -ENOMEM; 743 744 memcpy_fromio(buf, outmw->io_base + pos, size); 745 ret = copy_to_user(ubuf, buf, size); 746 if (ret == size) { 747 ret = -EFAULT; 748 goto err_free; 749 } 750 751 size -= ret; 752 *offp = pos + size; 753 ret = size; 754 755 err_free: 756 kfree(buf); 757 758 return ret; 759 } 760 761 static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf, 762 size_t size, loff_t *offp) 763 { 764 struct tool_mw *outmw = filep->private_data; 765 ssize_t ret; 766 loff_t pos = *offp; 767 void *buf; 768 769 if (outmw->io_base == NULL) 770 return -EIO; 771 772 if (pos >= outmw->size || !size) 773 return 0; 774 if (size > outmw->size - pos) 775 size = outmw->size - pos; 776 777 buf = kmalloc(size, GFP_KERNEL); 778 if (!buf) 779 return -ENOMEM; 780 781 ret = copy_from_user(buf, ubuf, size); 782 if (ret == size) { 783 ret = -EFAULT; 784 goto err_free; 785 } 786 787 size -= ret; 788 *offp = pos + size; 789 ret = size; 790 791 memcpy_toio(outmw->io_base + pos, buf, size); 792 793 err_free: 794 kfree(buf); 795 796 return ret; 797 } 798 799 static TOOL_FOPS_RDWR(tool_peer_mw_fops, 800 tool_peer_mw_read, 801 tool_peer_mw_write); 802 803 static int tool_setup_peer_mw(struct tool_ctx *tc, int pidx, int widx, 804 u64 req_addr, size_t req_size) 805 { 806 struct tool_mw *outmw = &tc->outmws[widx]; 807 resource_size_t map_size; 808 phys_addr_t map_base; 809 char buf[TOOL_BUF_LEN]; 810 int ret; 811 812 if (outmw->io_base != NULL) 813 return 0; 814 815 ret = ntb_peer_mw_get_addr(tc->ntb, widx, &map_base, &map_size); 816 if (ret) 817 return ret; 818 819 ret = ntb_peer_mw_set_trans(tc->ntb, pidx, widx, req_addr, req_size); 820 if (ret) 821 return ret; 822 823 outmw->io_base = ioremap_wc(map_base, map_size); 824 if (outmw->io_base == NULL) { 825 ret = -EFAULT; 826 goto err_clear_trans; 827 } 828 829 outmw->tr_base = req_addr; 830 outmw->size = req_size; 831 outmw->pidx = pidx; 832 833 snprintf(buf, sizeof(buf), "peer_mw%d", widx); 834 outmw->dbgfs_file = debugfs_create_file(buf, 0600, 835 tc->peers[pidx].dbgfs_dir, outmw, 836 &tool_peer_mw_fops); 837 838 return 0; 839 840 err_clear_trans: 841 ntb_peer_mw_clear_trans(tc->ntb, pidx, widx); 842 843 return ret; 844 } 845 846 static void tool_free_peer_mw(struct tool_ctx *tc, int widx) 847 { 848 struct tool_mw *outmw = &tc->outmws[widx]; 849 850 debugfs_remove(outmw->dbgfs_file); 851 852 if (outmw->io_base != NULL) { 853 iounmap(tc->outmws[widx].io_base); 854 ntb_peer_mw_clear_trans(tc->ntb, outmw->pidx, widx); 855 } 856 857 outmw->io_base = NULL; 858 outmw->tr_base = 0; 859 outmw->size = 0; 860 outmw->pidx = -1; 861 outmw->dbgfs_file = NULL; 862 } 863 864 static ssize_t tool_peer_mw_trans_read(struct file *filep, char __user *ubuf, 865 size_t size, loff_t *offp) 866 { 867 struct tool_mw_wrap *outmw_wrap = filep->private_data; 868 struct tool_mw *outmw = outmw_wrap->mw; 869 resource_size_t map_size; 870 phys_addr_t map_base; 871 ssize_t off = 0; 872 size_t buf_size; 873 char *buf; 874 int ret; 875 876 ret = ntb_peer_mw_get_addr(outmw->tc->ntb, outmw->widx, 877 &map_base, &map_size); 878 if (ret) 879 return ret; 880 881 buf_size = min_t(size_t, size, 512); 882 883 buf = kmalloc(buf_size, GFP_KERNEL); 884 if (!buf) 885 return -ENOMEM; 886 887 off += scnprintf(buf + off, buf_size - off, 888 "Outbound MW: \t%d\n", outmw->widx); 889 890 if (outmw->io_base != NULL) { 891 off += scnprintf(buf + off, buf_size - off, 892 "Port attached \t%d (%d)\n", 893 ntb_peer_port_number(outmw->tc->ntb, outmw->pidx), 894 outmw->pidx); 895 } else { 896 off += scnprintf(buf + off, buf_size - off, 897 "Port attached \t-1 (-1)\n"); 898 } 899 900 off += scnprintf(buf + off, buf_size - off, 901 "Virtual address \t0x%pK\n", outmw->io_base); 902 903 off += scnprintf(buf + off, buf_size - off, 904 "Phys Address \t%pap\n", &map_base); 905 906 off += scnprintf(buf + off, buf_size - off, 907 "Mapping Size \t%pap\n", &map_size); 908 909 off += scnprintf(buf + off, buf_size - off, 910 "Translation Address \t0x%016llx\n", outmw->tr_base); 911 912 off += scnprintf(buf + off, buf_size - off, 913 "Window Size \t%pap\n", &outmw->size); 914 915 ret = simple_read_from_buffer(ubuf, size, offp, buf, off); 916 kfree(buf); 917 918 return ret; 919 } 920 921 static ssize_t tool_peer_mw_trans_write(struct file *filep, 922 const char __user *ubuf, 923 size_t size, loff_t *offp) 924 { 925 struct tool_mw_wrap *outmw_wrap = filep->private_data; 926 struct tool_mw *outmw = outmw_wrap->mw; 927 size_t buf_size, wsize; 928 char buf[TOOL_BUF_LEN]; 929 int ret, n; 930 u64 addr; 931 932 buf_size = min(size, (sizeof(buf) - 1)); 933 if (copy_from_user(buf, ubuf, buf_size)) 934 return -EFAULT; 935 936 buf[buf_size] = '\0'; 937 938 n = sscanf(buf, "%llu:%zu", &addr, &wsize); 939 if (n != 2) 940 return -EINVAL; 941 942 tool_free_peer_mw(outmw->tc, outmw->widx); 943 if (wsize) { 944 ret = tool_setup_peer_mw(outmw->tc, outmw_wrap->pidx, 945 outmw->widx, addr, wsize); 946 if (ret) 947 return ret; 948 } 949 950 return size; 951 } 952 953 static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops, 954 tool_peer_mw_trans_read, 955 tool_peer_mw_trans_write); 956 957 static int tool_init_mws(struct tool_ctx *tc) 958 { 959 int widx, pidx; 960 961 /* Initialize outbound memory windows */ 962 tc->outmw_cnt = ntb_peer_mw_count(tc->ntb); 963 tc->outmws = devm_kzalloc_objs(&tc->ntb->dev, *tc->outmws, 964 tc->outmw_cnt); 965 if (tc->outmws == NULL) 966 return -ENOMEM; 967 968 for (widx = 0; widx < tc->outmw_cnt; widx++) { 969 tc->outmws[widx].widx = widx; 970 tc->outmws[widx].pidx = -1; 971 tc->outmws[widx].tc = tc; 972 } 973 974 /* Initialize inbound memory windows and outbound MWs wrapper */ 975 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 976 tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->ntb, pidx); 977 tc->peers[pidx].inmws = 978 devm_kzalloc_objs(&tc->ntb->dev, *tc->peers[pidx].inmws, 979 tc->peers[pidx].inmw_cnt); 980 if (tc->peers[pidx].inmws == NULL) 981 return -ENOMEM; 982 983 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 984 tc->peers[pidx].inmws[widx].widx = widx; 985 tc->peers[pidx].inmws[widx].pidx = pidx; 986 tc->peers[pidx].inmws[widx].tc = tc; 987 } 988 989 tc->peers[pidx].outmw_cnt = ntb_peer_mw_count(tc->ntb); 990 tc->peers[pidx].outmws = 991 devm_kzalloc_objs(&tc->ntb->dev, 992 *tc->peers[pidx].outmws, 993 tc->peers[pidx].outmw_cnt); 994 if (tc->peers[pidx].outmws == NULL) 995 return -ENOMEM; 996 997 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) { 998 tc->peers[pidx].outmws[widx].pidx = pidx; 999 tc->peers[pidx].outmws[widx].mw = &tc->outmws[widx]; 1000 } 1001 } 1002 1003 return 0; 1004 } 1005 1006 static void tool_clear_mws(struct tool_ctx *tc) 1007 { 1008 int widx, pidx; 1009 1010 /* Free outbound memory windows */ 1011 for (widx = 0; widx < tc->outmw_cnt; widx++) 1012 tool_free_peer_mw(tc, widx); 1013 1014 /* Free outbound memory windows */ 1015 for (pidx = 0; pidx < tc->peer_cnt; pidx++) 1016 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) 1017 tool_free_mw(tc, pidx, widx); 1018 } 1019 1020 /*============================================================================== 1021 * Doorbell read/write methods 1022 *============================================================================== 1023 */ 1024 1025 static ssize_t tool_db_read(struct file *filep, char __user *ubuf, 1026 size_t size, loff_t *offp) 1027 { 1028 struct tool_ctx *tc = filep->private_data; 1029 1030 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read); 1031 } 1032 1033 static ssize_t tool_db_write(struct file *filep, const char __user *ubuf, 1034 size_t size, loff_t *offp) 1035 { 1036 struct tool_ctx *tc = filep->private_data; 1037 1038 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set, 1039 tc->ntb->ops->db_clear); 1040 } 1041 1042 static TOOL_FOPS_RDWR(tool_db_fops, 1043 tool_db_read, 1044 tool_db_write); 1045 1046 static ssize_t tool_db_valid_mask_read(struct file *filep, char __user *ubuf, 1047 size_t size, loff_t *offp) 1048 { 1049 struct tool_ctx *tc = filep->private_data; 1050 1051 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_valid_mask); 1052 } 1053 1054 static TOOL_FOPS_RDWR(tool_db_valid_mask_fops, 1055 tool_db_valid_mask_read, 1056 NULL); 1057 1058 static ssize_t tool_db_mask_read(struct file *filep, char __user *ubuf, 1059 size_t size, loff_t *offp) 1060 { 1061 struct tool_ctx *tc = filep->private_data; 1062 1063 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read_mask); 1064 } 1065 1066 static ssize_t tool_db_mask_write(struct file *filep, const char __user *ubuf, 1067 size_t size, loff_t *offp) 1068 { 1069 struct tool_ctx *tc = filep->private_data; 1070 1071 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set_mask, 1072 tc->ntb->ops->db_clear_mask); 1073 } 1074 1075 static TOOL_FOPS_RDWR(tool_db_mask_fops, 1076 tool_db_mask_read, 1077 tool_db_mask_write); 1078 1079 static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf, 1080 size_t size, loff_t *offp) 1081 { 1082 struct tool_ctx *tc = filep->private_data; 1083 1084 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->peer_db_read); 1085 } 1086 1087 static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf, 1088 size_t size, loff_t *offp) 1089 { 1090 struct tool_ctx *tc = filep->private_data; 1091 1092 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->peer_db_set, 1093 tc->ntb->ops->peer_db_clear); 1094 } 1095 1096 static TOOL_FOPS_RDWR(tool_peer_db_fops, 1097 tool_peer_db_read, 1098 tool_peer_db_write); 1099 1100 static ssize_t tool_peer_db_mask_read(struct file *filep, char __user *ubuf, 1101 size_t size, loff_t *offp) 1102 { 1103 struct tool_ctx *tc = filep->private_data; 1104 1105 return tool_fn_read(tc, ubuf, size, offp, 1106 tc->ntb->ops->peer_db_read_mask); 1107 } 1108 1109 static ssize_t tool_peer_db_mask_write(struct file *filep, 1110 const char __user *ubuf, 1111 size_t size, loff_t *offp) 1112 { 1113 struct tool_ctx *tc = filep->private_data; 1114 1115 return tool_fn_write(tc, ubuf, size, offp, 1116 tc->ntb->ops->peer_db_set_mask, 1117 tc->ntb->ops->peer_db_clear_mask); 1118 } 1119 1120 static TOOL_FOPS_RDWR(tool_peer_db_mask_fops, 1121 tool_peer_db_mask_read, 1122 tool_peer_db_mask_write); 1123 1124 static ssize_t tool_db_event_write(struct file *filep, 1125 const char __user *ubuf, 1126 size_t size, loff_t *offp) 1127 { 1128 struct tool_ctx *tc = filep->private_data; 1129 u64 val; 1130 int ret; 1131 1132 ret = kstrtou64_from_user(ubuf, size, 0, &val); 1133 if (ret) 1134 return ret; 1135 1136 if (wait_event_interruptible(tc->db_wq, ntb_db_read(tc->ntb) == val)) 1137 return -ERESTART; 1138 1139 return size; 1140 } 1141 1142 static TOOL_FOPS_RDWR(tool_db_event_fops, 1143 NULL, 1144 tool_db_event_write); 1145 1146 /*============================================================================== 1147 * Scratchpads read/write methods 1148 *============================================================================== 1149 */ 1150 1151 static ssize_t tool_spad_read(struct file *filep, char __user *ubuf, 1152 size_t size, loff_t *offp) 1153 { 1154 struct tool_spad *spad = filep->private_data; 1155 char buf[TOOL_BUF_LEN]; 1156 ssize_t pos; 1157 1158 if (!spad->tc->ntb->ops->spad_read) 1159 return -EINVAL; 1160 1161 pos = scnprintf(buf, sizeof(buf), "%#x\n", 1162 ntb_spad_read(spad->tc->ntb, spad->sidx)); 1163 1164 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 1165 } 1166 1167 static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf, 1168 size_t size, loff_t *offp) 1169 { 1170 struct tool_spad *spad = filep->private_data; 1171 u32 val; 1172 int ret; 1173 1174 if (!spad->tc->ntb->ops->spad_write) { 1175 dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n"); 1176 return -EINVAL; 1177 } 1178 1179 ret = kstrtou32_from_user(ubuf, size, 0, &val); 1180 if (ret) 1181 return ret; 1182 1183 ret = ntb_spad_write(spad->tc->ntb, spad->sidx, val); 1184 1185 return ret ?: size; 1186 } 1187 1188 static TOOL_FOPS_RDWR(tool_spad_fops, 1189 tool_spad_read, 1190 tool_spad_write); 1191 1192 static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf, 1193 size_t size, loff_t *offp) 1194 { 1195 struct tool_spad *spad = filep->private_data; 1196 char buf[TOOL_BUF_LEN]; 1197 ssize_t pos; 1198 1199 if (!spad->tc->ntb->ops->peer_spad_read) 1200 return -EINVAL; 1201 1202 pos = scnprintf(buf, sizeof(buf), "%#x\n", 1203 ntb_peer_spad_read(spad->tc->ntb, spad->pidx, spad->sidx)); 1204 1205 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 1206 } 1207 1208 static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf, 1209 size_t size, loff_t *offp) 1210 { 1211 struct tool_spad *spad = filep->private_data; 1212 u32 val; 1213 int ret; 1214 1215 if (!spad->tc->ntb->ops->peer_spad_write) { 1216 dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n"); 1217 return -EINVAL; 1218 } 1219 1220 ret = kstrtou32_from_user(ubuf, size, 0, &val); 1221 if (ret) 1222 return ret; 1223 1224 ret = ntb_peer_spad_write(spad->tc->ntb, spad->pidx, spad->sidx, val); 1225 1226 return ret ?: size; 1227 } 1228 1229 static TOOL_FOPS_RDWR(tool_peer_spad_fops, 1230 tool_peer_spad_read, 1231 tool_peer_spad_write); 1232 1233 static int tool_init_spads(struct tool_ctx *tc) 1234 { 1235 int sidx, pidx; 1236 1237 /* Initialize inbound scratchpad structures */ 1238 tc->inspad_cnt = ntb_spad_count(tc->ntb); 1239 tc->inspads = devm_kzalloc_objs(&tc->ntb->dev, *tc->inspads, 1240 tc->inspad_cnt); 1241 if (tc->inspads == NULL) 1242 return -ENOMEM; 1243 1244 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 1245 tc->inspads[sidx].sidx = sidx; 1246 tc->inspads[sidx].pidx = -1; 1247 tc->inspads[sidx].tc = tc; 1248 } 1249 1250 /* Initialize outbound scratchpad structures */ 1251 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1252 tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->ntb); 1253 tc->peers[pidx].outspads = 1254 devm_kzalloc_objs(&tc->ntb->dev, 1255 *tc->peers[pidx].outspads, 1256 tc->peers[pidx].outspad_cnt); 1257 if (tc->peers[pidx].outspads == NULL) 1258 return -ENOMEM; 1259 1260 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 1261 tc->peers[pidx].outspads[sidx].sidx = sidx; 1262 tc->peers[pidx].outspads[sidx].pidx = pidx; 1263 tc->peers[pidx].outspads[sidx].tc = tc; 1264 } 1265 } 1266 1267 return 0; 1268 } 1269 1270 /*============================================================================== 1271 * Messages read/write methods 1272 *============================================================================== 1273 */ 1274 1275 static ssize_t tool_inmsg_read(struct file *filep, char __user *ubuf, 1276 size_t size, loff_t *offp) 1277 { 1278 struct tool_msg *msg = filep->private_data; 1279 char buf[TOOL_BUF_LEN]; 1280 ssize_t pos; 1281 u32 data; 1282 int pidx; 1283 1284 data = ntb_msg_read(msg->tc->ntb, &pidx, msg->midx); 1285 1286 pos = scnprintf(buf, sizeof(buf), "0x%08x<-%d\n", data, pidx); 1287 1288 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 1289 } 1290 1291 static TOOL_FOPS_RDWR(tool_inmsg_fops, 1292 tool_inmsg_read, 1293 NULL); 1294 1295 static ssize_t tool_outmsg_write(struct file *filep, 1296 const char __user *ubuf, 1297 size_t size, loff_t *offp) 1298 { 1299 struct tool_msg *msg = filep->private_data; 1300 u32 val; 1301 int ret; 1302 1303 ret = kstrtou32_from_user(ubuf, size, 0, &val); 1304 if (ret) 1305 return ret; 1306 1307 ret = ntb_peer_msg_write(msg->tc->ntb, msg->pidx, msg->midx, val); 1308 1309 return ret ? : size; 1310 } 1311 1312 static TOOL_FOPS_RDWR(tool_outmsg_fops, 1313 NULL, 1314 tool_outmsg_write); 1315 1316 static ssize_t tool_msg_sts_read(struct file *filep, char __user *ubuf, 1317 size_t size, loff_t *offp) 1318 { 1319 struct tool_ctx *tc = filep->private_data; 1320 1321 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_read_sts); 1322 } 1323 1324 static ssize_t tool_msg_sts_write(struct file *filep, const char __user *ubuf, 1325 size_t size, loff_t *offp) 1326 { 1327 struct tool_ctx *tc = filep->private_data; 1328 1329 return tool_fn_write(tc, ubuf, size, offp, NULL, 1330 tc->ntb->ops->msg_clear_sts); 1331 } 1332 1333 static TOOL_FOPS_RDWR(tool_msg_sts_fops, 1334 tool_msg_sts_read, 1335 tool_msg_sts_write); 1336 1337 static ssize_t tool_msg_inbits_read(struct file *filep, char __user *ubuf, 1338 size_t size, loff_t *offp) 1339 { 1340 struct tool_ctx *tc = filep->private_data; 1341 1342 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_inbits); 1343 } 1344 1345 static TOOL_FOPS_RDWR(tool_msg_inbits_fops, 1346 tool_msg_inbits_read, 1347 NULL); 1348 1349 static ssize_t tool_msg_outbits_read(struct file *filep, char __user *ubuf, 1350 size_t size, loff_t *offp) 1351 { 1352 struct tool_ctx *tc = filep->private_data; 1353 1354 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_outbits); 1355 } 1356 1357 static TOOL_FOPS_RDWR(tool_msg_outbits_fops, 1358 tool_msg_outbits_read, 1359 NULL); 1360 1361 static ssize_t tool_msg_mask_write(struct file *filep, const char __user *ubuf, 1362 size_t size, loff_t *offp) 1363 { 1364 struct tool_ctx *tc = filep->private_data; 1365 1366 return tool_fn_write(tc, ubuf, size, offp, 1367 tc->ntb->ops->msg_set_mask, 1368 tc->ntb->ops->msg_clear_mask); 1369 } 1370 1371 static TOOL_FOPS_RDWR(tool_msg_mask_fops, 1372 NULL, 1373 tool_msg_mask_write); 1374 1375 static ssize_t tool_msg_event_write(struct file *filep, 1376 const char __user *ubuf, 1377 size_t size, loff_t *offp) 1378 { 1379 struct tool_ctx *tc = filep->private_data; 1380 u64 val; 1381 int ret; 1382 1383 ret = kstrtou64_from_user(ubuf, size, 0, &val); 1384 if (ret) 1385 return ret; 1386 1387 if (wait_event_interruptible(tc->msg_wq, 1388 ntb_msg_read_sts(tc->ntb) == val)) 1389 return -ERESTART; 1390 1391 return size; 1392 } 1393 1394 static TOOL_FOPS_RDWR(tool_msg_event_fops, 1395 NULL, 1396 tool_msg_event_write); 1397 1398 static int tool_init_msgs(struct tool_ctx *tc) 1399 { 1400 int midx, pidx; 1401 1402 /* Initialize inbound message structures */ 1403 tc->inmsg_cnt = ntb_msg_count(tc->ntb); 1404 tc->inmsgs = devm_kzalloc_objs(&tc->ntb->dev, *tc->inmsgs, 1405 tc->inmsg_cnt); 1406 if (tc->inmsgs == NULL) 1407 return -ENOMEM; 1408 1409 for (midx = 0; midx < tc->inmsg_cnt; midx++) { 1410 tc->inmsgs[midx].midx = midx; 1411 tc->inmsgs[midx].pidx = -1; 1412 tc->inmsgs[midx].tc = tc; 1413 } 1414 1415 /* Initialize outbound message structures */ 1416 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1417 tc->peers[pidx].outmsg_cnt = ntb_msg_count(tc->ntb); 1418 tc->peers[pidx].outmsgs = 1419 devm_kzalloc_objs(&tc->ntb->dev, 1420 *tc->peers[pidx].outmsgs, 1421 tc->peers[pidx].outmsg_cnt); 1422 if (tc->peers[pidx].outmsgs == NULL) 1423 return -ENOMEM; 1424 1425 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) { 1426 tc->peers[pidx].outmsgs[midx].midx = midx; 1427 tc->peers[pidx].outmsgs[midx].pidx = pidx; 1428 tc->peers[pidx].outmsgs[midx].tc = tc; 1429 } 1430 } 1431 1432 return 0; 1433 } 1434 1435 /*============================================================================== 1436 * Initialization methods 1437 *============================================================================== 1438 */ 1439 1440 static struct tool_ctx *tool_create_data(struct ntb_dev *ntb) 1441 { 1442 struct tool_ctx *tc; 1443 1444 tc = devm_kzalloc_obj(&ntb->dev, *tc); 1445 if (tc == NULL) 1446 return ERR_PTR(-ENOMEM); 1447 1448 tc->ntb = ntb; 1449 init_waitqueue_head(&tc->link_wq); 1450 init_waitqueue_head(&tc->db_wq); 1451 init_waitqueue_head(&tc->msg_wq); 1452 1453 if (ntb_db_is_unsafe(ntb)) 1454 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 1455 1456 if (ntb_spad_is_unsafe(ntb)) 1457 dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 1458 1459 return tc; 1460 } 1461 1462 static void tool_clear_data(struct tool_ctx *tc) 1463 { 1464 wake_up(&tc->link_wq); 1465 wake_up(&tc->db_wq); 1466 wake_up(&tc->msg_wq); 1467 } 1468 1469 static int tool_init_ntb(struct tool_ctx *tc) 1470 { 1471 return ntb_set_ctx(tc->ntb, tc, &tool_ops); 1472 } 1473 1474 static void tool_clear_ntb(struct tool_ctx *tc) 1475 { 1476 ntb_clear_ctx(tc->ntb); 1477 ntb_link_disable(tc->ntb); 1478 } 1479 1480 static void tool_setup_dbgfs(struct tool_ctx *tc) 1481 { 1482 int pidx, widx, sidx, midx; 1483 char buf[TOOL_BUF_LEN]; 1484 1485 /* This modules is useless without dbgfs... */ 1486 if (!tool_dbgfs_topdir) { 1487 tc->dbgfs_dir = NULL; 1488 return; 1489 } 1490 1491 tc->dbgfs_dir = debugfs_create_dir(dev_name(&tc->ntb->dev), 1492 tool_dbgfs_topdir); 1493 1494 debugfs_create_file("port", 0600, tc->dbgfs_dir, 1495 tc, &tool_port_fops); 1496 1497 debugfs_create_file("link", 0600, tc->dbgfs_dir, 1498 tc, &tool_link_fops); 1499 1500 debugfs_create_file("db", 0600, tc->dbgfs_dir, 1501 tc, &tool_db_fops); 1502 1503 debugfs_create_file("db_valid_mask", 0600, tc->dbgfs_dir, 1504 tc, &tool_db_valid_mask_fops); 1505 1506 debugfs_create_file("db_mask", 0600, tc->dbgfs_dir, 1507 tc, &tool_db_mask_fops); 1508 1509 debugfs_create_file("db_event", 0600, tc->dbgfs_dir, 1510 tc, &tool_db_event_fops); 1511 1512 debugfs_create_file("peer_db", 0600, tc->dbgfs_dir, 1513 tc, &tool_peer_db_fops); 1514 1515 debugfs_create_file("peer_db_mask", 0600, tc->dbgfs_dir, 1516 tc, &tool_peer_db_mask_fops); 1517 1518 if (tc->inspad_cnt != 0) { 1519 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 1520 snprintf(buf, sizeof(buf), "spad%d", sidx); 1521 1522 debugfs_create_file(buf, 0600, tc->dbgfs_dir, 1523 &tc->inspads[sidx], &tool_spad_fops); 1524 } 1525 } 1526 1527 if (tc->inmsg_cnt != 0) { 1528 for (midx = 0; midx < tc->inmsg_cnt; midx++) { 1529 snprintf(buf, sizeof(buf), "msg%d", midx); 1530 debugfs_create_file(buf, 0600, tc->dbgfs_dir, 1531 &tc->inmsgs[midx], &tool_inmsg_fops); 1532 } 1533 1534 debugfs_create_file("msg_sts", 0600, tc->dbgfs_dir, 1535 tc, &tool_msg_sts_fops); 1536 1537 debugfs_create_file("msg_inbits", 0600, tc->dbgfs_dir, 1538 tc, &tool_msg_inbits_fops); 1539 1540 debugfs_create_file("msg_outbits", 0600, tc->dbgfs_dir, 1541 tc, &tool_msg_outbits_fops); 1542 1543 debugfs_create_file("msg_mask", 0600, tc->dbgfs_dir, 1544 tc, &tool_msg_mask_fops); 1545 1546 debugfs_create_file("msg_event", 0600, tc->dbgfs_dir, 1547 tc, &tool_msg_event_fops); 1548 } 1549 1550 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1551 snprintf(buf, sizeof(buf), "peer%d", pidx); 1552 tc->peers[pidx].dbgfs_dir = 1553 debugfs_create_dir(buf, tc->dbgfs_dir); 1554 1555 debugfs_create_file("port", 0600, 1556 tc->peers[pidx].dbgfs_dir, 1557 &tc->peers[pidx], &tool_peer_port_fops); 1558 1559 debugfs_create_file("link", 0200, 1560 tc->peers[pidx].dbgfs_dir, 1561 &tc->peers[pidx], &tool_peer_link_fops); 1562 1563 debugfs_create_file("link_event", 0200, 1564 tc->peers[pidx].dbgfs_dir, 1565 &tc->peers[pidx], &tool_peer_link_event_fops); 1566 1567 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 1568 snprintf(buf, sizeof(buf), "mw_trans%d", widx); 1569 debugfs_create_file(buf, 0600, 1570 tc->peers[pidx].dbgfs_dir, 1571 &tc->peers[pidx].inmws[widx], 1572 &tool_mw_trans_fops); 1573 } 1574 1575 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) { 1576 snprintf(buf, sizeof(buf), "peer_mw_trans%d", widx); 1577 debugfs_create_file(buf, 0600, 1578 tc->peers[pidx].dbgfs_dir, 1579 &tc->peers[pidx].outmws[widx], 1580 &tool_peer_mw_trans_fops); 1581 } 1582 1583 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 1584 snprintf(buf, sizeof(buf), "spad%d", sidx); 1585 1586 debugfs_create_file(buf, 0600, 1587 tc->peers[pidx].dbgfs_dir, 1588 &tc->peers[pidx].outspads[sidx], 1589 &tool_peer_spad_fops); 1590 } 1591 1592 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) { 1593 snprintf(buf, sizeof(buf), "msg%d", midx); 1594 debugfs_create_file(buf, 0600, 1595 tc->peers[pidx].dbgfs_dir, 1596 &tc->peers[pidx].outmsgs[midx], 1597 &tool_outmsg_fops); 1598 } 1599 } 1600 } 1601 1602 static void tool_clear_dbgfs(struct tool_ctx *tc) 1603 { 1604 debugfs_remove_recursive(tc->dbgfs_dir); 1605 } 1606 1607 static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) 1608 { 1609 struct tool_ctx *tc; 1610 int ret; 1611 1612 tc = tool_create_data(ntb); 1613 if (IS_ERR(tc)) 1614 return PTR_ERR(tc); 1615 1616 ret = tool_init_peers(tc); 1617 if (ret != 0) 1618 goto err_clear_data; 1619 1620 ret = tool_init_mws(tc); 1621 if (ret != 0) 1622 goto err_clear_data; 1623 1624 ret = tool_init_spads(tc); 1625 if (ret != 0) 1626 goto err_clear_mws; 1627 1628 ret = tool_init_msgs(tc); 1629 if (ret != 0) 1630 goto err_clear_mws; 1631 1632 ret = tool_init_ntb(tc); 1633 if (ret != 0) 1634 goto err_clear_mws; 1635 1636 tool_setup_dbgfs(tc); 1637 1638 return 0; 1639 1640 err_clear_mws: 1641 tool_clear_mws(tc); 1642 1643 err_clear_data: 1644 tool_clear_data(tc); 1645 1646 return ret; 1647 } 1648 1649 static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb) 1650 { 1651 struct tool_ctx *tc = ntb->ctx; 1652 1653 tool_clear_dbgfs(tc); 1654 1655 tool_clear_ntb(tc); 1656 1657 tool_clear_mws(tc); 1658 1659 tool_clear_data(tc); 1660 } 1661 1662 static struct ntb_client tool_client = { 1663 .ops = { 1664 .probe = tool_probe, 1665 .remove = tool_remove, 1666 } 1667 }; 1668 1669 static int __init tool_init(void) 1670 { 1671 int ret; 1672 1673 if (debugfs_initialized()) 1674 tool_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL); 1675 1676 ret = ntb_register_client(&tool_client); 1677 if (ret) 1678 debugfs_remove_recursive(tool_dbgfs_topdir); 1679 1680 return ret; 1681 } 1682 module_init(tool_init); 1683 1684 static void __exit tool_exit(void) 1685 { 1686 ntb_unregister_client(&tool_client); 1687 debugfs_remove_recursive(tool_dbgfs_topdir); 1688 } 1689 module_exit(tool_exit); 1690