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