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_kcalloc(&tc->ntb->dev, tc->peer_cnt, 445 sizeof(*tc->peers), GFP_KERNEL); 446 if (tc->peers == NULL) 447 return -ENOMEM; 448 449 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 450 tc->peers[pidx].pidx = pidx; 451 tc->peers[pidx].tc = tc; 452 } 453 454 return 0; 455 } 456 457 /*============================================================================== 458 * Link state read/write methods 459 *============================================================================== 460 */ 461 462 static ssize_t tool_link_write(struct file *filep, const char __user *ubuf, 463 size_t size, loff_t *offp) 464 { 465 struct tool_ctx *tc = filep->private_data; 466 bool val; 467 int ret; 468 469 ret = kstrtobool_from_user(ubuf, size, &val); 470 if (ret) 471 return ret; 472 473 if (val) 474 ret = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 475 else 476 ret = ntb_link_disable(tc->ntb); 477 478 if (ret) 479 return ret; 480 481 return size; 482 } 483 484 static TOOL_FOPS_RDWR(tool_link_fops, 485 NULL, 486 tool_link_write); 487 488 static ssize_t tool_peer_link_read(struct file *filep, char __user *ubuf, 489 size_t size, loff_t *offp) 490 { 491 struct tool_peer *peer = filep->private_data; 492 struct tool_ctx *tc = peer->tc; 493 char buf[3]; 494 495 if (ntb_link_is_up(tc->ntb, NULL, NULL) & BIT(peer->pidx)) 496 buf[0] = 'Y'; 497 else 498 buf[0] = 'N'; 499 buf[1] = '\n'; 500 buf[2] = '\0'; 501 502 return simple_read_from_buffer(ubuf, size, offp, buf, 2); 503 } 504 505 static TOOL_FOPS_RDWR(tool_peer_link_fops, 506 tool_peer_link_read, 507 NULL); 508 509 static ssize_t tool_peer_link_event_write(struct file *filep, 510 const char __user *ubuf, 511 size_t size, loff_t *offp) 512 { 513 struct tool_peer *peer = filep->private_data; 514 struct tool_ctx *tc = peer->tc; 515 u64 link_msk; 516 bool val; 517 int ret; 518 519 ret = kstrtobool_from_user(ubuf, size, &val); 520 if (ret) 521 return ret; 522 523 link_msk = BIT_ULL_MASK(peer->pidx); 524 525 if (wait_event_interruptible(tc->link_wq, 526 !!(ntb_link_is_up(tc->ntb, NULL, NULL) & link_msk) == val)) 527 return -ERESTART; 528 529 return size; 530 } 531 532 static TOOL_FOPS_RDWR(tool_peer_link_event_fops, 533 NULL, 534 tool_peer_link_event_write); 535 536 /*============================================================================== 537 * Memory windows read/write/setting methods 538 *============================================================================== 539 */ 540 541 static ssize_t tool_mw_read(struct file *filep, char __user *ubuf, 542 size_t size, loff_t *offp) 543 { 544 struct tool_mw *inmw = filep->private_data; 545 546 if (inmw->mm_base == NULL) 547 return -ENXIO; 548 549 return simple_read_from_buffer(ubuf, size, offp, 550 inmw->mm_base, inmw->size); 551 } 552 553 static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf, 554 size_t size, loff_t *offp) 555 { 556 struct tool_mw *inmw = filep->private_data; 557 558 if (inmw->mm_base == NULL) 559 return -ENXIO; 560 561 return simple_write_to_buffer(inmw->mm_base, inmw->size, offp, 562 ubuf, size); 563 } 564 565 static TOOL_FOPS_RDWR(tool_mw_fops, 566 tool_mw_read, 567 tool_mw_write); 568 569 static int tool_setup_mw(struct tool_ctx *tc, int pidx, int widx, 570 size_t req_size) 571 { 572 resource_size_t size, addr_align, size_align; 573 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; 574 char buf[TOOL_BUF_LEN]; 575 int ret; 576 577 if (inmw->mm_base != NULL) 578 return 0; 579 580 ret = ntb_mw_get_align(tc->ntb, pidx, widx, &addr_align, 581 &size_align, &size); 582 if (ret) 583 return ret; 584 585 inmw->size = min_t(resource_size_t, req_size, size); 586 inmw->size = round_up(inmw->size, addr_align); 587 inmw->size = round_up(inmw->size, size_align); 588 inmw->mm_base = dma_alloc_coherent(&tc->ntb->pdev->dev, inmw->size, 589 &inmw->dma_base, GFP_KERNEL); 590 if (!inmw->mm_base) 591 return -ENOMEM; 592 593 if (!IS_ALIGNED(inmw->dma_base, addr_align)) { 594 ret = -ENOMEM; 595 goto err_free_dma; 596 } 597 598 ret = ntb_mw_set_trans(tc->ntb, pidx, widx, inmw->dma_base, inmw->size); 599 if (ret) 600 goto err_free_dma; 601 602 snprintf(buf, sizeof(buf), "mw%d", widx); 603 inmw->dbgfs_file = debugfs_create_file(buf, 0600, 604 tc->peers[pidx].dbgfs_dir, inmw, 605 &tool_mw_fops); 606 607 return 0; 608 609 err_free_dma: 610 dma_free_coherent(&tc->ntb->pdev->dev, inmw->size, inmw->mm_base, 611 inmw->dma_base); 612 inmw->mm_base = NULL; 613 inmw->dma_base = 0; 614 inmw->size = 0; 615 616 return ret; 617 } 618 619 static void tool_free_mw(struct tool_ctx *tc, int pidx, int widx) 620 { 621 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; 622 623 debugfs_remove(inmw->dbgfs_file); 624 625 if (inmw->mm_base != NULL) { 626 ntb_mw_clear_trans(tc->ntb, pidx, widx); 627 dma_free_coherent(&tc->ntb->pdev->dev, inmw->size, 628 inmw->mm_base, inmw->dma_base); 629 } 630 631 inmw->mm_base = NULL; 632 inmw->dma_base = 0; 633 inmw->size = 0; 634 inmw->dbgfs_file = NULL; 635 } 636 637 static ssize_t tool_mw_trans_read(struct file *filep, char __user *ubuf, 638 size_t size, loff_t *offp) 639 { 640 struct tool_mw *inmw = filep->private_data; 641 resource_size_t addr_align; 642 resource_size_t size_align; 643 resource_size_t size_max; 644 ssize_t ret, off = 0; 645 size_t buf_size; 646 char *buf; 647 648 buf_size = min_t(size_t, size, 512); 649 650 buf = kmalloc(buf_size, GFP_KERNEL); 651 if (!buf) 652 return -ENOMEM; 653 654 ret = ntb_mw_get_align(inmw->tc->ntb, inmw->pidx, inmw->widx, 655 &addr_align, &size_align, &size_max); 656 if (ret) 657 goto err; 658 659 off += scnprintf(buf + off, buf_size - off, 660 "Inbound MW \t%d\n", 661 inmw->widx); 662 663 off += scnprintf(buf + off, buf_size - off, 664 "Port \t%d (%d)\n", 665 ntb_peer_port_number(inmw->tc->ntb, inmw->pidx), 666 inmw->pidx); 667 668 off += scnprintf(buf + off, buf_size - off, 669 "Window Address \t0x%pK\n", inmw->mm_base); 670 671 off += scnprintf(buf + off, buf_size - off, 672 "DMA Address \t%pad\n", 673 &inmw->dma_base); 674 675 off += scnprintf(buf + off, buf_size - off, 676 "Window Size \t%pap\n", 677 &inmw->size); 678 679 off += scnprintf(buf + off, buf_size - off, 680 "Alignment \t%pap\n", 681 &addr_align); 682 683 off += scnprintf(buf + off, buf_size - off, 684 "Size Alignment \t%pap\n", 685 &size_align); 686 687 off += scnprintf(buf + off, buf_size - off, 688 "Size Max \t%pap\n", 689 &size_max); 690 691 ret = simple_read_from_buffer(ubuf, size, offp, buf, off); 692 693 err: 694 kfree(buf); 695 696 return ret; 697 } 698 699 static ssize_t tool_mw_trans_write(struct file *filep, const char __user *ubuf, 700 size_t size, loff_t *offp) 701 { 702 struct tool_mw *inmw = filep->private_data; 703 unsigned int val; 704 int ret; 705 706 ret = kstrtouint_from_user(ubuf, size, 0, &val); 707 if (ret) 708 return ret; 709 710 tool_free_mw(inmw->tc, inmw->pidx, inmw->widx); 711 if (val) { 712 ret = tool_setup_mw(inmw->tc, inmw->pidx, inmw->widx, val); 713 if (ret) 714 return ret; 715 } 716 717 return size; 718 } 719 720 static TOOL_FOPS_RDWR(tool_mw_trans_fops, 721 tool_mw_trans_read, 722 tool_mw_trans_write); 723 724 static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf, 725 size_t size, loff_t *offp) 726 { 727 struct tool_mw *outmw = filep->private_data; 728 loff_t pos = *offp; 729 ssize_t ret; 730 void *buf; 731 732 if (outmw->io_base == NULL) 733 return -EIO; 734 735 if (pos >= outmw->size || !size) 736 return 0; 737 738 if (size > outmw->size - pos) 739 size = outmw->size - pos; 740 741 buf = kmalloc(size, GFP_KERNEL); 742 if (!buf) 743 return -ENOMEM; 744 745 memcpy_fromio(buf, outmw->io_base + pos, size); 746 ret = copy_to_user(ubuf, buf, size); 747 if (ret == size) { 748 ret = -EFAULT; 749 goto err_free; 750 } 751 752 size -= ret; 753 *offp = pos + size; 754 ret = size; 755 756 err_free: 757 kfree(buf); 758 759 return ret; 760 } 761 762 static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf, 763 size_t size, loff_t *offp) 764 { 765 struct tool_mw *outmw = filep->private_data; 766 ssize_t ret; 767 loff_t pos = *offp; 768 void *buf; 769 770 if (outmw->io_base == NULL) 771 return -EIO; 772 773 if (pos >= outmw->size || !size) 774 return 0; 775 if (size > outmw->size - pos) 776 size = outmw->size - pos; 777 778 buf = kmalloc(size, GFP_KERNEL); 779 if (!buf) 780 return -ENOMEM; 781 782 ret = copy_from_user(buf, ubuf, size); 783 if (ret == size) { 784 ret = -EFAULT; 785 goto err_free; 786 } 787 788 size -= ret; 789 *offp = pos + size; 790 ret = size; 791 792 memcpy_toio(outmw->io_base + pos, buf, size); 793 794 err_free: 795 kfree(buf); 796 797 return ret; 798 } 799 800 static TOOL_FOPS_RDWR(tool_peer_mw_fops, 801 tool_peer_mw_read, 802 tool_peer_mw_write); 803 804 static int tool_setup_peer_mw(struct tool_ctx *tc, int pidx, int widx, 805 u64 req_addr, size_t req_size) 806 { 807 struct tool_mw *outmw = &tc->outmws[widx]; 808 resource_size_t map_size; 809 phys_addr_t map_base; 810 char buf[TOOL_BUF_LEN]; 811 int ret; 812 813 if (outmw->io_base != NULL) 814 return 0; 815 816 ret = ntb_peer_mw_get_addr(tc->ntb, widx, &map_base, &map_size); 817 if (ret) 818 return ret; 819 820 ret = ntb_peer_mw_set_trans(tc->ntb, pidx, widx, req_addr, req_size); 821 if (ret) 822 return ret; 823 824 outmw->io_base = ioremap_wc(map_base, map_size); 825 if (outmw->io_base == NULL) { 826 ret = -EFAULT; 827 goto err_clear_trans; 828 } 829 830 outmw->tr_base = req_addr; 831 outmw->size = req_size; 832 outmw->pidx = pidx; 833 834 snprintf(buf, sizeof(buf), "peer_mw%d", widx); 835 outmw->dbgfs_file = debugfs_create_file(buf, 0600, 836 tc->peers[pidx].dbgfs_dir, outmw, 837 &tool_peer_mw_fops); 838 839 return 0; 840 841 err_clear_trans: 842 ntb_peer_mw_clear_trans(tc->ntb, pidx, widx); 843 844 return ret; 845 } 846 847 static void tool_free_peer_mw(struct tool_ctx *tc, int widx) 848 { 849 struct tool_mw *outmw = &tc->outmws[widx]; 850 851 debugfs_remove(outmw->dbgfs_file); 852 853 if (outmw->io_base != NULL) { 854 iounmap(tc->outmws[widx].io_base); 855 ntb_peer_mw_clear_trans(tc->ntb, outmw->pidx, widx); 856 } 857 858 outmw->io_base = NULL; 859 outmw->tr_base = 0; 860 outmw->size = 0; 861 outmw->pidx = -1; 862 outmw->dbgfs_file = NULL; 863 } 864 865 static ssize_t tool_peer_mw_trans_read(struct file *filep, char __user *ubuf, 866 size_t size, loff_t *offp) 867 { 868 struct tool_mw_wrap *outmw_wrap = filep->private_data; 869 struct tool_mw *outmw = outmw_wrap->mw; 870 resource_size_t map_size; 871 phys_addr_t map_base; 872 ssize_t off = 0; 873 size_t buf_size; 874 char *buf; 875 int ret; 876 877 ret = ntb_peer_mw_get_addr(outmw->tc->ntb, outmw->widx, 878 &map_base, &map_size); 879 if (ret) 880 return ret; 881 882 buf_size = min_t(size_t, size, 512); 883 884 buf = kmalloc(buf_size, GFP_KERNEL); 885 if (!buf) 886 return -ENOMEM; 887 888 off += scnprintf(buf + off, buf_size - off, 889 "Outbound MW: \t%d\n", outmw->widx); 890 891 if (outmw->io_base != NULL) { 892 off += scnprintf(buf + off, buf_size - off, 893 "Port attached \t%d (%d)\n", 894 ntb_peer_port_number(outmw->tc->ntb, outmw->pidx), 895 outmw->pidx); 896 } else { 897 off += scnprintf(buf + off, buf_size - off, 898 "Port attached \t-1 (-1)\n"); 899 } 900 901 off += scnprintf(buf + off, buf_size - off, 902 "Virtual address \t0x%pK\n", outmw->io_base); 903 904 off += scnprintf(buf + off, buf_size - off, 905 "Phys Address \t%pap\n", &map_base); 906 907 off += scnprintf(buf + off, buf_size - off, 908 "Mapping Size \t%pap\n", &map_size); 909 910 off += scnprintf(buf + off, buf_size - off, 911 "Translation Address \t0x%016llx\n", outmw->tr_base); 912 913 off += scnprintf(buf + off, buf_size - off, 914 "Window Size \t%pap\n", &outmw->size); 915 916 ret = simple_read_from_buffer(ubuf, size, offp, buf, off); 917 kfree(buf); 918 919 return ret; 920 } 921 922 static ssize_t tool_peer_mw_trans_write(struct file *filep, 923 const char __user *ubuf, 924 size_t size, loff_t *offp) 925 { 926 struct tool_mw_wrap *outmw_wrap = filep->private_data; 927 struct tool_mw *outmw = outmw_wrap->mw; 928 size_t buf_size, wsize; 929 char buf[TOOL_BUF_LEN]; 930 int ret, n; 931 u64 addr; 932 933 buf_size = min(size, (sizeof(buf) - 1)); 934 if (copy_from_user(buf, ubuf, buf_size)) 935 return -EFAULT; 936 937 buf[buf_size] = '\0'; 938 939 n = sscanf(buf, "%lli:%zi", &addr, &wsize); 940 if (n != 2) 941 return -EINVAL; 942 943 tool_free_peer_mw(outmw->tc, outmw->widx); 944 if (wsize) { 945 ret = tool_setup_peer_mw(outmw->tc, outmw_wrap->pidx, 946 outmw->widx, addr, wsize); 947 if (ret) 948 return ret; 949 } 950 951 return size; 952 } 953 954 static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops, 955 tool_peer_mw_trans_read, 956 tool_peer_mw_trans_write); 957 958 static int tool_init_mws(struct tool_ctx *tc) 959 { 960 int widx, pidx; 961 962 /* Initialize outbound memory windows */ 963 tc->outmw_cnt = ntb_peer_mw_count(tc->ntb); 964 tc->outmws = devm_kcalloc(&tc->ntb->dev, tc->outmw_cnt, 965 sizeof(*tc->outmws), GFP_KERNEL); 966 if (tc->outmws == NULL) 967 return -ENOMEM; 968 969 for (widx = 0; widx < tc->outmw_cnt; widx++) { 970 tc->outmws[widx].widx = widx; 971 tc->outmws[widx].pidx = -1; 972 tc->outmws[widx].tc = tc; 973 } 974 975 /* Initialize inbound memory windows and outbound MWs wrapper */ 976 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 977 tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->ntb, pidx); 978 tc->peers[pidx].inmws = 979 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].inmw_cnt, 980 sizeof(*tc->peers[pidx].inmws), GFP_KERNEL); 981 if (tc->peers[pidx].inmws == NULL) 982 return -ENOMEM; 983 984 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 985 tc->peers[pidx].inmws[widx].widx = widx; 986 tc->peers[pidx].inmws[widx].pidx = pidx; 987 tc->peers[pidx].inmws[widx].tc = tc; 988 } 989 990 tc->peers[pidx].outmw_cnt = ntb_peer_mw_count(tc->ntb); 991 tc->peers[pidx].outmws = 992 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmw_cnt, 993 sizeof(*tc->peers[pidx].outmws), GFP_KERNEL); 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_kcalloc(&tc->ntb->dev, tc->inspad_cnt, 1240 sizeof(*tc->inspads), GFP_KERNEL); 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_kcalloc(&tc->ntb->dev, tc->peers[pidx].outspad_cnt, 1255 sizeof(*tc->peers[pidx].outspads), GFP_KERNEL); 1256 if (tc->peers[pidx].outspads == NULL) 1257 return -ENOMEM; 1258 1259 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 1260 tc->peers[pidx].outspads[sidx].sidx = sidx; 1261 tc->peers[pidx].outspads[sidx].pidx = pidx; 1262 tc->peers[pidx].outspads[sidx].tc = tc; 1263 } 1264 } 1265 1266 return 0; 1267 } 1268 1269 /*============================================================================== 1270 * Messages read/write methods 1271 *============================================================================== 1272 */ 1273 1274 static ssize_t tool_inmsg_read(struct file *filep, char __user *ubuf, 1275 size_t size, loff_t *offp) 1276 { 1277 struct tool_msg *msg = filep->private_data; 1278 char buf[TOOL_BUF_LEN]; 1279 ssize_t pos; 1280 u32 data; 1281 int pidx; 1282 1283 data = ntb_msg_read(msg->tc->ntb, &pidx, msg->midx); 1284 1285 pos = scnprintf(buf, sizeof(buf), "0x%08x<-%d\n", data, pidx); 1286 1287 return simple_read_from_buffer(ubuf, size, offp, buf, pos); 1288 } 1289 1290 static TOOL_FOPS_RDWR(tool_inmsg_fops, 1291 tool_inmsg_read, 1292 NULL); 1293 1294 static ssize_t tool_outmsg_write(struct file *filep, 1295 const char __user *ubuf, 1296 size_t size, loff_t *offp) 1297 { 1298 struct tool_msg *msg = filep->private_data; 1299 u32 val; 1300 int ret; 1301 1302 ret = kstrtou32_from_user(ubuf, size, 0, &val); 1303 if (ret) 1304 return ret; 1305 1306 ret = ntb_peer_msg_write(msg->tc->ntb, msg->pidx, msg->midx, val); 1307 1308 return ret ? : size; 1309 } 1310 1311 static TOOL_FOPS_RDWR(tool_outmsg_fops, 1312 NULL, 1313 tool_outmsg_write); 1314 1315 static ssize_t tool_msg_sts_read(struct file *filep, char __user *ubuf, 1316 size_t size, loff_t *offp) 1317 { 1318 struct tool_ctx *tc = filep->private_data; 1319 1320 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_read_sts); 1321 } 1322 1323 static ssize_t tool_msg_sts_write(struct file *filep, const char __user *ubuf, 1324 size_t size, loff_t *offp) 1325 { 1326 struct tool_ctx *tc = filep->private_data; 1327 1328 return tool_fn_write(tc, ubuf, size, offp, NULL, 1329 tc->ntb->ops->msg_clear_sts); 1330 } 1331 1332 static TOOL_FOPS_RDWR(tool_msg_sts_fops, 1333 tool_msg_sts_read, 1334 tool_msg_sts_write); 1335 1336 static ssize_t tool_msg_inbits_read(struct file *filep, char __user *ubuf, 1337 size_t size, loff_t *offp) 1338 { 1339 struct tool_ctx *tc = filep->private_data; 1340 1341 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_inbits); 1342 } 1343 1344 static TOOL_FOPS_RDWR(tool_msg_inbits_fops, 1345 tool_msg_inbits_read, 1346 NULL); 1347 1348 static ssize_t tool_msg_outbits_read(struct file *filep, char __user *ubuf, 1349 size_t size, loff_t *offp) 1350 { 1351 struct tool_ctx *tc = filep->private_data; 1352 1353 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_outbits); 1354 } 1355 1356 static TOOL_FOPS_RDWR(tool_msg_outbits_fops, 1357 tool_msg_outbits_read, 1358 NULL); 1359 1360 static ssize_t tool_msg_mask_write(struct file *filep, const char __user *ubuf, 1361 size_t size, loff_t *offp) 1362 { 1363 struct tool_ctx *tc = filep->private_data; 1364 1365 return tool_fn_write(tc, ubuf, size, offp, 1366 tc->ntb->ops->msg_set_mask, 1367 tc->ntb->ops->msg_clear_mask); 1368 } 1369 1370 static TOOL_FOPS_RDWR(tool_msg_mask_fops, 1371 NULL, 1372 tool_msg_mask_write); 1373 1374 static ssize_t tool_msg_event_write(struct file *filep, 1375 const char __user *ubuf, 1376 size_t size, loff_t *offp) 1377 { 1378 struct tool_ctx *tc = filep->private_data; 1379 u64 val; 1380 int ret; 1381 1382 ret = kstrtou64_from_user(ubuf, size, 0, &val); 1383 if (ret) 1384 return ret; 1385 1386 if (wait_event_interruptible(tc->msg_wq, 1387 ntb_msg_read_sts(tc->ntb) == val)) 1388 return -ERESTART; 1389 1390 return size; 1391 } 1392 1393 static TOOL_FOPS_RDWR(tool_msg_event_fops, 1394 NULL, 1395 tool_msg_event_write); 1396 1397 static int tool_init_msgs(struct tool_ctx *tc) 1398 { 1399 int midx, pidx; 1400 1401 /* Initialize inbound message structures */ 1402 tc->inmsg_cnt = ntb_msg_count(tc->ntb); 1403 tc->inmsgs = devm_kcalloc(&tc->ntb->dev, tc->inmsg_cnt, 1404 sizeof(*tc->inmsgs), GFP_KERNEL); 1405 if (tc->inmsgs == NULL) 1406 return -ENOMEM; 1407 1408 for (midx = 0; midx < tc->inmsg_cnt; midx++) { 1409 tc->inmsgs[midx].midx = midx; 1410 tc->inmsgs[midx].pidx = -1; 1411 tc->inmsgs[midx].tc = tc; 1412 } 1413 1414 /* Initialize outbound message structures */ 1415 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1416 tc->peers[pidx].outmsg_cnt = ntb_msg_count(tc->ntb); 1417 tc->peers[pidx].outmsgs = 1418 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmsg_cnt, 1419 sizeof(*tc->peers[pidx].outmsgs), GFP_KERNEL); 1420 if (tc->peers[pidx].outmsgs == NULL) 1421 return -ENOMEM; 1422 1423 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) { 1424 tc->peers[pidx].outmsgs[midx].midx = midx; 1425 tc->peers[pidx].outmsgs[midx].pidx = pidx; 1426 tc->peers[pidx].outmsgs[midx].tc = tc; 1427 } 1428 } 1429 1430 return 0; 1431 } 1432 1433 /*============================================================================== 1434 * Initialization methods 1435 *============================================================================== 1436 */ 1437 1438 static struct tool_ctx *tool_create_data(struct ntb_dev *ntb) 1439 { 1440 struct tool_ctx *tc; 1441 1442 tc = devm_kzalloc(&ntb->dev, sizeof(*tc), GFP_KERNEL); 1443 if (tc == NULL) 1444 return ERR_PTR(-ENOMEM); 1445 1446 tc->ntb = ntb; 1447 init_waitqueue_head(&tc->link_wq); 1448 init_waitqueue_head(&tc->db_wq); 1449 init_waitqueue_head(&tc->msg_wq); 1450 1451 if (ntb_db_is_unsafe(ntb)) 1452 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 1453 1454 if (ntb_spad_is_unsafe(ntb)) 1455 dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 1456 1457 return tc; 1458 } 1459 1460 static void tool_clear_data(struct tool_ctx *tc) 1461 { 1462 wake_up(&tc->link_wq); 1463 wake_up(&tc->db_wq); 1464 wake_up(&tc->msg_wq); 1465 } 1466 1467 static int tool_init_ntb(struct tool_ctx *tc) 1468 { 1469 return ntb_set_ctx(tc->ntb, tc, &tool_ops); 1470 } 1471 1472 static void tool_clear_ntb(struct tool_ctx *tc) 1473 { 1474 ntb_clear_ctx(tc->ntb); 1475 ntb_link_disable(tc->ntb); 1476 } 1477 1478 static void tool_setup_dbgfs(struct tool_ctx *tc) 1479 { 1480 int pidx, widx, sidx, midx; 1481 char buf[TOOL_BUF_LEN]; 1482 1483 /* This modules is useless without dbgfs... */ 1484 if (!tool_dbgfs_topdir) { 1485 tc->dbgfs_dir = NULL; 1486 return; 1487 } 1488 1489 tc->dbgfs_dir = debugfs_create_dir(dev_name(&tc->ntb->dev), 1490 tool_dbgfs_topdir); 1491 1492 debugfs_create_file("port", 0600, tc->dbgfs_dir, 1493 tc, &tool_port_fops); 1494 1495 debugfs_create_file("link", 0600, tc->dbgfs_dir, 1496 tc, &tool_link_fops); 1497 1498 debugfs_create_file("db", 0600, tc->dbgfs_dir, 1499 tc, &tool_db_fops); 1500 1501 debugfs_create_file("db_valid_mask", 0600, tc->dbgfs_dir, 1502 tc, &tool_db_valid_mask_fops); 1503 1504 debugfs_create_file("db_mask", 0600, tc->dbgfs_dir, 1505 tc, &tool_db_mask_fops); 1506 1507 debugfs_create_file("db_event", 0600, tc->dbgfs_dir, 1508 tc, &tool_db_event_fops); 1509 1510 debugfs_create_file("peer_db", 0600, tc->dbgfs_dir, 1511 tc, &tool_peer_db_fops); 1512 1513 debugfs_create_file("peer_db_mask", 0600, tc->dbgfs_dir, 1514 tc, &tool_peer_db_mask_fops); 1515 1516 if (tc->inspad_cnt != 0) { 1517 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 1518 snprintf(buf, sizeof(buf), "spad%d", sidx); 1519 1520 debugfs_create_file(buf, 0600, tc->dbgfs_dir, 1521 &tc->inspads[sidx], &tool_spad_fops); 1522 } 1523 } 1524 1525 if (tc->inmsg_cnt != 0) { 1526 for (midx = 0; midx < tc->inmsg_cnt; midx++) { 1527 snprintf(buf, sizeof(buf), "msg%d", midx); 1528 debugfs_create_file(buf, 0600, tc->dbgfs_dir, 1529 &tc->inmsgs[midx], &tool_inmsg_fops); 1530 } 1531 1532 debugfs_create_file("msg_sts", 0600, tc->dbgfs_dir, 1533 tc, &tool_msg_sts_fops); 1534 1535 debugfs_create_file("msg_inbits", 0600, tc->dbgfs_dir, 1536 tc, &tool_msg_inbits_fops); 1537 1538 debugfs_create_file("msg_outbits", 0600, tc->dbgfs_dir, 1539 tc, &tool_msg_outbits_fops); 1540 1541 debugfs_create_file("msg_mask", 0600, tc->dbgfs_dir, 1542 tc, &tool_msg_mask_fops); 1543 1544 debugfs_create_file("msg_event", 0600, tc->dbgfs_dir, 1545 tc, &tool_msg_event_fops); 1546 } 1547 1548 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1549 snprintf(buf, sizeof(buf), "peer%d", pidx); 1550 tc->peers[pidx].dbgfs_dir = 1551 debugfs_create_dir(buf, tc->dbgfs_dir); 1552 1553 debugfs_create_file("port", 0600, 1554 tc->peers[pidx].dbgfs_dir, 1555 &tc->peers[pidx], &tool_peer_port_fops); 1556 1557 debugfs_create_file("link", 0200, 1558 tc->peers[pidx].dbgfs_dir, 1559 &tc->peers[pidx], &tool_peer_link_fops); 1560 1561 debugfs_create_file("link_event", 0200, 1562 tc->peers[pidx].dbgfs_dir, 1563 &tc->peers[pidx], &tool_peer_link_event_fops); 1564 1565 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 1566 snprintf(buf, sizeof(buf), "mw_trans%d", widx); 1567 debugfs_create_file(buf, 0600, 1568 tc->peers[pidx].dbgfs_dir, 1569 &tc->peers[pidx].inmws[widx], 1570 &tool_mw_trans_fops); 1571 } 1572 1573 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) { 1574 snprintf(buf, sizeof(buf), "peer_mw_trans%d", widx); 1575 debugfs_create_file(buf, 0600, 1576 tc->peers[pidx].dbgfs_dir, 1577 &tc->peers[pidx].outmws[widx], 1578 &tool_peer_mw_trans_fops); 1579 } 1580 1581 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 1582 snprintf(buf, sizeof(buf), "spad%d", sidx); 1583 1584 debugfs_create_file(buf, 0600, 1585 tc->peers[pidx].dbgfs_dir, 1586 &tc->peers[pidx].outspads[sidx], 1587 &tool_peer_spad_fops); 1588 } 1589 1590 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) { 1591 snprintf(buf, sizeof(buf), "msg%d", midx); 1592 debugfs_create_file(buf, 0600, 1593 tc->peers[pidx].dbgfs_dir, 1594 &tc->peers[pidx].outmsgs[midx], 1595 &tool_outmsg_fops); 1596 } 1597 } 1598 } 1599 1600 static void tool_clear_dbgfs(struct tool_ctx *tc) 1601 { 1602 debugfs_remove_recursive(tc->dbgfs_dir); 1603 } 1604 1605 static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) 1606 { 1607 struct tool_ctx *tc; 1608 int ret; 1609 1610 tc = tool_create_data(ntb); 1611 if (IS_ERR(tc)) 1612 return PTR_ERR(tc); 1613 1614 ret = tool_init_peers(tc); 1615 if (ret != 0) 1616 goto err_clear_data; 1617 1618 ret = tool_init_mws(tc); 1619 if (ret != 0) 1620 goto err_clear_data; 1621 1622 ret = tool_init_spads(tc); 1623 if (ret != 0) 1624 goto err_clear_mws; 1625 1626 ret = tool_init_msgs(tc); 1627 if (ret != 0) 1628 goto err_clear_mws; 1629 1630 ret = tool_init_ntb(tc); 1631 if (ret != 0) 1632 goto err_clear_mws; 1633 1634 tool_setup_dbgfs(tc); 1635 1636 return 0; 1637 1638 err_clear_mws: 1639 tool_clear_mws(tc); 1640 1641 err_clear_data: 1642 tool_clear_data(tc); 1643 1644 return ret; 1645 } 1646 1647 static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb) 1648 { 1649 struct tool_ctx *tc = ntb->ctx; 1650 1651 tool_clear_dbgfs(tc); 1652 1653 tool_clear_ntb(tc); 1654 1655 tool_clear_mws(tc); 1656 1657 tool_clear_data(tc); 1658 } 1659 1660 static struct ntb_client tool_client = { 1661 .ops = { 1662 .probe = tool_probe, 1663 .remove = tool_remove, 1664 } 1665 }; 1666 1667 static int __init tool_init(void) 1668 { 1669 int ret; 1670 1671 if (debugfs_initialized()) 1672 tool_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL); 1673 1674 ret = ntb_register_client(&tool_client); 1675 if (ret) 1676 debugfs_remove_recursive(tool_dbgfs_topdir); 1677 1678 return ret; 1679 } 1680 module_init(tool_init); 1681 1682 static void __exit tool_exit(void) 1683 { 1684 ntb_unregister_client(&tool_client); 1685 debugfs_remove_recursive(tool_dbgfs_topdir); 1686 } 1687 module_exit(tool_exit); 1688