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) 2019 Advanced Micro Devices, Inc. All Rights Reserved. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of version 2 of the GNU General Public License as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * BSD LICENSE 19 * 20 * Copyright (c) 2019 Advanced Micro Devices, Inc. All Rights Reserved. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 26 * * Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * * Redistributions in binary form must reproduce the above copy 29 * notice, this list of conditions and the following disclaimer in 30 * the documentation and/or other materials provided with the 31 * distribution. 32 * * Neither the name of Advanced Micro Devices, Inc nor the names of its 33 * contributors may be used to endorse or promote products derived 34 * from this software without specific prior written permission. 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 37 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 38 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 39 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 40 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 43 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 44 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 45 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 46 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 47 * 48 * PCIe NTB Debugging Tool FreeBSD driver 49 */ 50 51 /* 52 * How to use this tool, by example. 53 * 54 * List of sysctl for ntb_tool driver. 55 * root@local# sysctl -a | grep ntb_tool 56 * dev.ntb_tool.0.peer0.spad7: 0x0 57 * dev.ntb_tool.0.peer0.spad6: 0x0 58 * dev.ntb_tool.0.peer0.spad5: 0x0 59 * dev.ntb_tool.0.peer0.spad4: 0x0 60 * dev.ntb_tool.0.peer0.spad3: 0x0 61 * dev.ntb_tool.0.peer0.spad2: 0x0 62 * dev.ntb_tool.0.peer0.spad1: 0x0 63 * dev.ntb_tool.0.peer0.spad0: 0x0 64 * dev.ntb_tool.0.peer0.mw_trans2: 65 * dev.ntb_tool.0.peer0.mw_trans1: 66 * dev.ntb_tool.0.peer0.mw_trans0: 67 * dev.ntb_tool.0.peer0.peer_mw2: 68 * dev.ntb_tool.0.peer0.peer_mw1: 69 * dev.ntb_tool.0.peer0.peer_mw0: 70 * dev.ntb_tool.0.peer0.mw2: 71 * dev.ntb_tool.0.peer0.mw1: 72 * dev.ntb_tool.0.peer0.mw0: 73 * dev.ntb_tool.0.peer0.link_event: 0x0 74 * dev.ntb_tool.0.peer0.link: Y 75 * dev.ntb_tool.0.peer0.port: 1 76 * dev.ntb_tool.0.spad7: 0x0 77 * dev.ntb_tool.0.spad6: 0x0 78 * dev.ntb_tool.0.spad5: 0x0 79 * dev.ntb_tool.0.spad4: 0x0 80 * dev.ntb_tool.0.spad3: 0x0 81 * dev.ntb_tool.0.spad2: 0x0 82 * dev.ntb_tool.0.spad1: 0x0 83 * dev.ntb_tool.0.spad0: 0x0 84 * dev.ntb_tool.0.db: 0x0 85 * dev.ntb_tool.0.db_event: 0x0 86 * dev.ntb_tool.0.db_mask: 0xffff 87 * dev.ntb_tool.0.db_valid_mask: 0xffff 88 * dev.ntb_tool.0.peer_db: 0x0 89 * dev.ntb_tool.0.peer_db_mask: 0xffff 90 * dev.ntb_tool.0.link: Y 91 * dev.ntb_tool.0.port: 0 92 * 93 * The above example list shows 94 * 1) three memory windows, 95 * 1) eight scratchpad registers. 96 * 3) doorbell config. 97 * 4) link config. 98 * 2) One peer. 99 * 100 * Based on the underlined ntb_hw driver config & connection topology, these 101 * things might differ. 102 *----------------------------------------------------------------------------- 103 * Eg: check local/peer port information. 104 * 105 * # Get local device port number 106 * root@local# sysctl dev.ntb_tool.0.port 107 * 108 * # Check peer device port number 109 * root@local# sysctl dev.ntb_tool.0.peer0.port 110 *----------------------------------------------------------------------------- 111 * Eg: NTB link tests 112 * 113 * # Set local link up/down 114 * root@local# sysctl dev.ntb_tool.0.link=Y 115 * root@local# sysctl dev.ntb_tool.0.link=N 116 * 117 * # Check if link with peer device is up/down: 118 * root@local# sysctl dev.ntb_tool.0.peer0.link 119 * 120 * # Poll until the link specified as up/down. For up, value needs to be set 121 * depends on peer index, i.e., for peer0 it is 0x1 and for down, value needs 122 * to be set as 0x0. 123 * root@local# sysctl dev.ntb_tool.0.peer0.link_event=0x1 124 * root@local# sysctl dev.ntb_tool.0.peer0.link_event=0x0 125 *----------------------------------------------------------------------------- 126 * Eg: Doorbell registers tests 127 * 128 * # clear/get local doorbell 129 * root@local# sysctl dev.ntb_tool.0.db="c 0x1" 130 * root@local# sysctl dev.ntb_tool.0.db 131 * 132 * # Set/clear/get local doorbell mask 133 * root@local# sysctl dev.ntb_tool.0.db_mask="s 0x1" 134 * root@local# sysctl dev.ntb_tool.0.db_mask="c 0x1" 135 * root@local# sysctl dev.ntb_tool.0.db_mask 136 * 137 * # Ring/clear/get peer doorbell 138 * root@local# sysctl dev.ntb_tool.0.peer_db="s 0x1" 139 * root@local# sysctl dev.ntb_tool.0.peer_db="c 0x1" 140 * root@local# sysctl dev.ntb_tool.0.peer_db 141 * 142 * # Set/clear/get peer doorbell mask (functionality is absent) 143 * root@local# sysctl dev.ntb_tool.0.peer_db_mask="s 0x1" 144 * root@local# sysctl dev.ntb_tool.0.peer_db_mask="c 0x1" 145 * root@local# sysctl dev.ntb_tool.0.peer_db_mask 146 * 147 * # Poll until local doorbell is set with the specified db bits 148 * root@local# dev.ntb_tool.0.db_event=0x1 149 *----------------------------------------------------------------------------- 150 * Eg: Scratchpad registers tests 151 * 152 * # Write/read to/from local scratchpad register #0 153 * root@local# sysctl dev.ntb_tool.0.spad0=0x1023457 154 * root@local# sysctl dev.ntb_tool.0.spad0 155 * 156 * # Write/read to/from peer scratchpad register #0 157 * root@local# sysctl dev.ntb_tool.0.peer0.spad0=0x01020304 158 * root@local# sysctl dev.ntb_tool.0.peer0.spad0 159 *----------------------------------------------------------------------------- 160 * Eg: Memory windows tests (need to configure local mw_trans on both sides) 161 * 162 * # Create inbound memory window buffer of specified size/get its dma address 163 * root@local# sysctl dev.ntb_tool.0.peer0.mw_trans0=16384 164 * root@local# sysctl dev.ntb_tool.0.peer0.mw_trans0 165 * 166 * # Write/read data to/from inbound memory window with specific pattern/random 167 * data. 168 * root@local# sysctl dev.ntb_tool.0.peer0.mw0="W offset 0 nbytes 100 pattern ab" 169 * root@local# sysctl dev.ntb_tool.0.peer0.mw0="R offset 0 nbytes 100" 170 * 171 * # Write/read data to/from outbound memory window on the local device with 172 * specific pattern/random (on peer device) 173 * root@local# sysctl dev.ntb_tool.0.peer0.peer_mw0="W offset 0 nbytes 100 pattern ab" 174 * root@local# sysctl dev.ntb_tool.0.peer0.peer_mw0="R offset 0 nbytes 100" 175 *----------------------------------------------------------------------------- 176 * NOTE: *Message registers are not supported* 177 *----------------------------------------------------------------------------- 178 * 179 * contact information: 180 * Arpan Palit <arpan.palit@amd.com> 181 * 182 */ 183 184 #include <sys/cdefs.h> 185 #include <sys/param.h> 186 #include <sys/bus.h> 187 #include <sys/kernel.h> 188 #include <sys/module.h> 189 #include <sys/mbuf.h> 190 #include <sys/sysctl.h> 191 #include <sys/sbuf.h> 192 193 #include <machine/bus.h> 194 195 #include <vm/vm.h> 196 197 #include "../ntb.h" 198 199 /* Buffer length for User input */ 200 #define TOOL_BUF_LEN 48 201 /* Memory window default command read and write offset. */ 202 #define DEFAULT_MW_OFF 0 203 /* Memory window default size and also max command read size. */ 204 #define DEFAULT_MW_SIZE 1024 205 206 MALLOC_DEFINE(M_NTB_TOOL, "ntb_tool", "ntb_tool driver memory allocation"); 207 208 /* 209 * Memory windows descriptor structure 210 */ 211 struct tool_mw { 212 struct tool_ctx *tc; 213 int widx; 214 int pidx; 215 216 /* Rx buff is off virt_addr / dma_base */ 217 bus_addr_t dma_base; 218 caddr_t virt_addr; 219 bus_dmamap_t dma_map; 220 bus_dma_tag_t dma_tag; 221 222 /* Tx buff is off vbase / phys_addr */ 223 caddr_t mm_base; 224 vm_paddr_t phys_addr; 225 bus_addr_t addr_limit; 226 size_t phys_size; 227 size_t xlat_align; 228 size_t xlat_align_size; 229 230 /* Memory window configured size and limits */ 231 size_t size; 232 ssize_t mw_buf_size; 233 ssize_t mw_buf_offset; 234 ssize_t mw_peer_buf_size; 235 ssize_t mw_peer_buf_offset; 236 237 /* options to handle sysctl out */ 238 int mw_cmd_rw; 239 int mw_peer_cmd_rw; 240 }; 241 242 struct tool_spad { 243 int sidx; 244 int pidx; 245 struct tool_ctx *tc; 246 }; 247 248 struct tool_peer { 249 int pidx; 250 struct tool_ctx *tc; 251 int inmw_cnt; 252 struct tool_mw *inmws; 253 int outspad_cnt; 254 struct tool_spad *outspads; 255 unsigned int port_no; 256 }; 257 258 struct tool_ctx { 259 device_t dev; 260 struct callout link_event_timer; 261 struct callout db_event_timer; 262 int peer_cnt; 263 struct tool_peer *peers; 264 int inmsg_cnt; 265 struct tool_msg *inmsgs; 266 int inspad_cnt; 267 struct tool_spad *inspads; 268 unsigned int unsafe; 269 270 /* sysctl read out variables */ 271 char link_status; 272 uint64_t link_bits; 273 uint64_t link_mask; 274 uint64_t db_valid_mask; 275 uint64_t db_mask_val; 276 uint64_t db_event_val; 277 uint64_t peer_db_val; 278 uint64_t peer_db_mask_val; 279 unsigned int port_no; 280 }; 281 282 /* structure to save dma_addr after dma load */ 283 struct ntb_tool_load_cb_args { 284 bus_addr_t addr; 285 int error; 286 }; 287 288 /* 289 * NTB events handlers 290 */ 291 static void 292 tool_link_event(void *ctx) 293 { 294 struct tool_ctx *tc = ctx; 295 enum ntb_speed speed = 0; 296 enum ntb_width width = 0; 297 int up = 0; 298 299 up = ntb_link_is_up(tc->dev, &speed, &width); 300 if (up) 301 tc->link_status = 'Y'; 302 else 303 tc->link_status = 'N'; 304 305 device_printf(tc->dev, "link is %s speed %d width %d\n", 306 up ? "up" : "down", speed, width); 307 } 308 309 static void 310 tool_db_event(void *ctx, uint32_t vec) 311 { 312 struct tool_ctx *tc = ctx; 313 uint64_t db_bits, db_mask; 314 315 db_mask = ntb_db_vector_mask(tc->dev, vec); 316 db_bits = ntb_db_read(tc->dev); 317 318 device_printf(tc->dev, "doorbell vec %d mask %#llx bits %#llx\n", 319 vec, (unsigned long long)db_mask, (unsigned long long)db_bits); 320 } 321 322 static const struct ntb_ctx_ops tool_ops = { 323 .link_event = tool_link_event, 324 .db_event = tool_db_event, 325 }; 326 327 /* 328 * Callout event methods 329 */ 330 static void 331 tool_link_event_handler(void *arg) 332 { 333 struct tool_ctx *tc = (struct tool_ctx *)arg; 334 uint64_t val; 335 336 val = ntb_link_is_up(tc->dev, NULL, NULL) & tc->link_mask; 337 338 if (val == tc->link_bits) { 339 device_printf(tc->dev, "link_event successful for link val=" 340 "0x%jx\n", tc->link_bits); 341 tc->link_bits = 0x0; 342 tc->link_mask = 0x0; 343 } else 344 callout_reset(&tc->link_event_timer, 1, tool_link_event_handler, tc); 345 } 346 347 static void 348 tool_db_event_handler(void *arg) 349 { 350 struct tool_ctx *tc = (struct tool_ctx *)arg; 351 uint64_t db_bits; 352 353 db_bits = ntb_db_read(tc->dev); 354 355 if (db_bits == tc->db_event_val) { 356 device_printf(tc->dev, "db_event successful for db val=0x%jx\n", 357 tc->db_event_val); 358 tc->db_event_val = 0x0; 359 } else 360 callout_reset(&tc->db_event_timer, 1, tool_db_event_handler, tc); 361 } 362 363 /* 364 * Common read/write methods 365 */ 366 static inline int 367 get_ubuf(struct sysctl_req *req, char *ubuf) 368 { 369 int rc; 370 371 if (req->newlen >= TOOL_BUF_LEN) 372 return (EINVAL); 373 374 rc = SYSCTL_IN(req, ubuf, req->newlen); 375 if (rc) 376 return (rc); 377 ubuf[req->newlen] = '\0'; 378 379 return (0); 380 } 381 382 static int 383 read_out(struct sysctl_req *req, uint64_t val) 384 { 385 char ubuf[19]; 386 387 memset((void *)ubuf, 0, sizeof(ubuf)); 388 snprintf(ubuf, sizeof(ubuf), "0x%jx", val); 389 390 return SYSCTL_OUT(req, ubuf, sizeof(ubuf)); 391 } 392 393 static int 394 tool_fn_read(struct tool_ctx *tc, struct sysctl_req *req, 395 uint64_t (*fn_read)(device_t ), uint64_t val) 396 { 397 if (fn_read == NULL) 398 return read_out(req, val); 399 else if (fn_read) 400 return read_out(req, (uint64_t)fn_read(tc->dev)); 401 else 402 return (EINVAL); 403 } 404 405 static int 406 tool_fn_write(struct tool_ctx *tc, struct sysctl_oid *oidp, 407 struct sysctl_req *req, char *ubuf, uint64_t *val, bool db_mask_sflag, 408 void (*fn_set)(device_t , uint64_t), void (*fn_clear)(device_t , uint64_t)) 409 { 410 uint64_t db_valid_mask = tc->db_valid_mask; 411 uint64_t bits; 412 char cmd; 413 414 if (fn_set == NULL && fn_clear == NULL) { 415 device_printf(tc->dev, "ERR: Set & Clear both are not supported\n"); 416 return (EINVAL); 417 } 418 419 if (tc->db_valid_mask == 0) 420 db_valid_mask = tc->db_valid_mask = ntb_db_valid_mask(tc->dev); 421 422 bits = 0; 423 sscanf(ubuf, "%c %jx", &cmd, &bits); 424 if (cmd == 's') { 425 if ((bits | db_valid_mask) > db_valid_mask) { 426 device_printf(tc->dev, "0x%jx value is not supported\n", bits); 427 return (EINVAL); 428 } 429 if (fn_set) 430 fn_set(tc->dev, bits); 431 else 432 return (EINVAL); 433 if (val) 434 *val |= bits; 435 } else if (cmd == 'c') { 436 if ((bits | db_valid_mask) > db_valid_mask) { 437 device_printf(tc->dev, "0x%jx value is not supported\n", bits); 438 return (EINVAL); 439 } 440 if (fn_clear) 441 fn_clear(tc->dev, bits); 442 if (val) 443 *val &= ~bits; 444 } else { 445 device_printf(tc->dev, "Wrong Write\n"); 446 return (EINVAL); 447 } 448 449 return (0); 450 } 451 452 static int 453 parse_mw_buf(char *buf, char *cmd, ssize_t *offset, ssize_t *buf_size, 454 uint64_t *pattern, bool *s_pflag) 455 { 456 char op1[8], op2[8], op3[8]; 457 uint64_t val1, val2, val3; 458 bool vs1, vs2, vs3; 459 int rc = 0; 460 461 vs1 = vs2 = vs3 = false; 462 sscanf(buf, "%c %s %jx %s %jx %s %jx", 463 cmd, op1, &val1, op2, &val2, op3, &val3); 464 465 if (*cmd != 'W' && *cmd != 'R') 466 return (EINVAL); 467 468 if (!strcmp(op1, "offset")) { 469 *offset = val1 ? val1 : DEFAULT_MW_OFF; 470 vs1 = true; 471 } else if (!strcmp(op1, "nbytes")) { 472 *buf_size = val1 ? val1: DEFAULT_MW_SIZE; 473 vs2 = true; 474 } else if (!strcmp(op1, "pattern")) { 475 *pattern = val1; 476 vs3 = true; 477 } 478 479 if (!vs1 && !strcmp(op2, "offset")) { 480 *offset = val2 ? val2 : DEFAULT_MW_OFF; 481 vs1 = true; 482 } else if (!vs2 && !strcmp(op2, "nbytes")) { 483 *buf_size = val2 ? val2: DEFAULT_MW_SIZE; 484 vs2 = true; 485 } else if (!vs3 && !strcmp(op2, "pattern")) { 486 *pattern = val2; 487 vs3 = true; 488 } 489 490 if (!vs1 && !strcmp(op3, "offset")) { 491 *offset = val3 ? val3 : DEFAULT_MW_OFF; 492 } else if (!vs2 && !strcmp(op3, "nbytes")) { 493 *buf_size = val3 ? val3: DEFAULT_MW_SIZE; 494 } else if (!vs3 && !strcmp(op3, "pattern")) { 495 *pattern = val3; 496 vs3 = true; 497 } 498 499 *s_pflag = vs3; 500 if (vs3 && *cmd == 'R') 501 printf("NTB_TOOL_WARN: pattern is not supported with read " 502 "command\n"); 503 504 return (rc); 505 } 506 507 static int 508 tool_mw_read_fn(struct sysctl_req *req, struct tool_mw *inmw, char *read_addr, 509 int *cmd_op, ssize_t buf_off, ssize_t buf_size, char *type) 510 { 511 ssize_t index, size; 512 struct sbuf *sb; 513 int i, loop, rc; 514 char *tmp; 515 516 /* The below check is made to ignore sysctl read call. */ 517 if (*cmd_op == 0) 518 return (0); 519 520 /* Proceeds only when command R/W is requested using sysctl. */ 521 index = buf_off; 522 tmp = read_addr; 523 tmp += index; 524 loop = ((buf_size == 0) || (buf_size > DEFAULT_MW_SIZE)) ? 525 DEFAULT_MW_SIZE : buf_size; 526 /* 527 * 256 bytes of extra buffer has been allocated to print details like 528 * summary, size, notes, i.e., excluding data part. 529 */ 530 size = loop + 256; 531 sb = sbuf_new_for_sysctl(NULL, NULL, size, req); 532 if (sb == NULL) { 533 rc = sb->s_error; 534 return (rc); 535 } 536 537 if (!strcmp(type, "mw")) 538 sbuf_printf(sb, "\nConfigured MW size\t: %zu\n", inmw->size); 539 else if (!strcmp(type, "peer_mw")) 540 sbuf_printf(sb, "\nConfigured Peer MW size\t: %zu\n", 541 inmw->size); 542 sbuf_printf(sb, "R/W size\t\t: %zi\nR/W Offset\t\t: %zi\n\nData\n----" 543 "->", buf_size, buf_off); 544 545 /* 546 * Data will be read based on MW size provided by the user using nbytes, 547 * which is limited to 1024 bytes if user req bigger size to read, check 548 * above loop calculation which is limiting or setting the MW read size. 549 * Below for loop prints data where in each line contains 32 bytes data 550 * and after each 8 bytes of data we used four spaces which ensures one 551 * data block. 552 */ 553 for (i = 0 ; i < loop; i++) { 554 if ((i % 32) == 0) { 555 sbuf_printf(sb, "\n%08zx:", index); 556 index += 32; 557 } 558 if ((i % 8) == 0) 559 sbuf_printf(sb, " "); 560 sbuf_printf(sb, "%02hhx", *(tmp+i)); 561 } 562 if (buf_size > DEFAULT_MW_SIZE) 563 sbuf_printf(sb, "\n\nNOTE: Truncating read size %zi->1024 " 564 "bytes\n", buf_size); 565 566 /* cmd_op is set to zero after completion of each R/W command. */ 567 *cmd_op -= 1; 568 rc = sbuf_finish(sb); 569 sbuf_delete(sb); 570 571 return (rc); 572 } 573 574 static int 575 tool_mw_write_fn(struct sysctl_oid *oidp, struct sysctl_req *req, 576 struct tool_mw *inmw, char *ubuf, caddr_t write_buf, int *cmd_op, 577 ssize_t *buf_offset, ssize_t *buf_size) 578 { 579 ssize_t data_buf_size; 580 uint64_t pattern = 0; 581 bool s_pflag = false; 582 void *data_buf; 583 char cmd; 584 int rc; 585 586 if (!write_buf) 587 return (ENXIO); 588 589 /* buf_offset and buf_size set to default in case user does not req */ 590 *buf_offset = DEFAULT_MW_OFF; 591 *buf_size = DEFAULT_MW_SIZE; 592 rc = parse_mw_buf(ubuf, &cmd, buf_offset, buf_size, &pattern, &s_pflag); 593 if (rc) { 594 device_printf(inmw->tc->dev, "Wrong Command \"%c\" provided\n", 595 cmd); 596 return (rc); 597 } 598 599 /* Check for req size and buffer limit */ 600 if ((*buf_offset + *buf_size) > inmw->size) { 601 device_printf(inmw->tc->dev, "%s: configured mw size :%zi and " 602 "requested size :%zi.\n", __func__, inmw->size, 603 (*buf_offset + *buf_size)); 604 *buf_offset = DEFAULT_MW_OFF; 605 *buf_size = DEFAULT_MW_SIZE; 606 rc = EINVAL; 607 goto out; 608 } 609 610 if (cmd == 'R') 611 goto read_out; 612 else if (cmd == 'W') 613 goto write; 614 else 615 goto out; 616 617 write: 618 data_buf_size = *buf_size; 619 data_buf = malloc(data_buf_size, M_NTB_TOOL, M_WAITOK | M_ZERO); 620 621 if (s_pflag) 622 memset(data_buf, pattern, data_buf_size); 623 else 624 arc4rand(data_buf, data_buf_size, 1); 625 626 memcpy(write_buf + *buf_offset, data_buf, data_buf_size); 627 628 free(data_buf, M_NTB_TOOL); 629 630 read_out: 631 /* cmd_op value is set to two as sysctl read call executes twice */ 632 *cmd_op = 2; 633 out: 634 return (rc); 635 } 636 637 /* 638 * Port sysctl read/write methods 639 */ 640 static int 641 sysctl_peer_port_number(SYSCTL_HANDLER_ARGS) 642 { 643 struct tool_ctx *tc = (struct tool_ctx *)arg1; 644 int rc, pidx = arg2, peer_port; 645 646 peer_port = ntb_peer_port_number(tc->dev, pidx); 647 rc = sysctl_handle_int(oidp, &peer_port, 0, req); 648 if (rc) 649 device_printf(tc->dev, "Peer port sysctl set failed with err=" 650 "(%d).\n", rc); 651 else 652 tc->peers[pidx].port_no = peer_port; 653 654 return (rc); 655 } 656 657 static int 658 sysctl_local_port_number(SYSCTL_HANDLER_ARGS) 659 { 660 struct tool_ctx *tc = (struct tool_ctx *)arg1; 661 int rc, local_port; 662 663 local_port = ntb_port_number(tc->dev); 664 rc = sysctl_handle_int(oidp, &local_port, 0, req); 665 if (rc) 666 device_printf(tc->dev, "Local port sysctl set failed with err=" 667 "(%d).\n", rc); 668 else 669 tc->port_no = local_port; 670 671 return (rc); 672 } 673 674 static void 675 tool_init_peers(struct tool_ctx *tc) 676 { 677 int pidx; 678 679 tc->peer_cnt = ntb_peer_port_count(tc->dev); 680 tc->peers = malloc(tc->peer_cnt * sizeof(*tc->peers), M_NTB_TOOL, 681 M_WAITOK | M_ZERO); 682 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 683 tc->peers[pidx].pidx = pidx; 684 tc->peers[pidx].tc = tc; 685 } 686 } 687 688 static void 689 tool_clear_peers(struct tool_ctx *tc) 690 { 691 692 free(tc->peers, M_NTB_TOOL); 693 } 694 695 /* 696 * Link state sysctl read/write methods 697 */ 698 static int 699 sysctl_link_handle(SYSCTL_HANDLER_ARGS) 700 { 701 struct tool_ctx *tc = (struct tool_ctx *)arg1; 702 char buf[TOOL_BUF_LEN]; 703 int rc; 704 705 if (req->newptr == NULL) { 706 snprintf(buf, 2, "%c", tc->link_status); 707 708 return SYSCTL_OUT(req, buf, 2); 709 } 710 711 rc = get_ubuf(req, buf); 712 if (rc) 713 return (rc); 714 715 if (buf[0] == 'Y') 716 rc = ntb_link_enable(tc->dev, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 717 else if (buf[0] == 'N') 718 rc = ntb_link_disable(tc->dev); 719 else 720 rc = EINVAL; 721 722 sscanf(buf, "%c", &tc->link_status); 723 724 return (0); 725 } 726 727 static int 728 sysctl_peer_link_handle(SYSCTL_HANDLER_ARGS) 729 { 730 struct tool_ctx *tc = (struct tool_ctx *)arg1; 731 int up = 0, pidx = arg2; 732 char buf[TOOL_BUF_LEN]; 733 734 if (req->newptr) 735 return (0); 736 737 up = ntb_link_is_up(tc->dev, NULL, NULL); 738 memset((void *)buf, 0, TOOL_BUF_LEN); 739 if (up & (1UL << pidx)) 740 buf[0] = 'Y'; 741 else 742 buf[0] = 'N'; 743 744 return SYSCTL_OUT(req, buf, sizeof(buf)); 745 } 746 747 static int 748 sysctl_peer_link_event_handle(SYSCTL_HANDLER_ARGS) 749 { 750 struct tool_ctx *tc = (struct tool_ctx *)arg1; 751 char buf[TOOL_BUF_LEN]; 752 int rc, pidx = arg2; 753 uint64_t bits; 754 755 if (req->newptr == NULL) 756 return read_out(req, tc->link_bits); 757 758 rc = get_ubuf(req, buf); 759 if (rc) 760 return (rc); 761 762 sscanf(buf, "0x%jx", &bits); 763 tc->link_bits = bits; 764 tc->link_mask = (1ULL << ((pidx) % 64)); 765 766 callout_reset(&tc->link_event_timer, 1, tool_link_event_handler, tc); 767 return (0); 768 } 769 770 /* 771 * Memory windows read/write/setting methods 772 */ 773 static void 774 ntb_tool_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 775 { 776 struct ntb_tool_load_cb_args *cba = (struct ntb_tool_load_cb_args *)arg; 777 778 if (!(cba->error = error)) 779 cba->addr = segs[0].ds_addr; 780 } 781 782 static int 783 sysctl_mw_handle(SYSCTL_HANDLER_ARGS) 784 { 785 struct tool_mw *inmw = (struct tool_mw *)arg1; 786 char buf[TOOL_BUF_LEN]; 787 int rc; 788 789 if (req->newptr == NULL) 790 return tool_mw_read_fn(req, inmw, (char *)inmw->mm_base, 791 &inmw->mw_cmd_rw, inmw->mw_buf_offset, inmw->mw_buf_size, 792 "mw"); 793 794 rc = get_ubuf(req, buf); 795 if (!rc) 796 return tool_mw_write_fn(oidp, req, inmw, buf, inmw->mm_base, 797 &inmw->mw_cmd_rw, &inmw->mw_buf_offset, &inmw->mw_buf_size); 798 799 return (rc); 800 } 801 802 static int 803 tool_setup_mw(struct tool_ctx *tc, unsigned int pidx, unsigned int widx, 804 size_t req_size) 805 { 806 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; 807 struct ntb_tool_load_cb_args cba; 808 int rc; 809 810 if (req_size == 0) 811 inmw->size = roundup(inmw->phys_size, inmw->xlat_align_size); 812 else 813 inmw->size = roundup(req_size, inmw->xlat_align_size); 814 815 device_printf(tc->dev, "mw_size %zi req_size %zi buff %zi\n", 816 inmw->phys_size, req_size, inmw->size); 817 818 if (bus_dma_tag_create(bus_get_dma_tag(tc->dev), inmw->xlat_align, 0, 819 inmw->addr_limit, BUS_SPACE_MAXADDR, NULL, NULL, inmw->size, 1, 820 inmw->size, 0, NULL, NULL, &inmw->dma_tag)) { 821 device_printf(tc->dev, "Unable to create MW tag of size " 822 "%zu/%zu\n", inmw->phys_size, inmw->size); 823 rc = ENOMEM; 824 goto err_free_dma_var; 825 } 826 827 if (bus_dmamem_alloc(inmw->dma_tag, (void **)&inmw->virt_addr, 828 BUS_DMA_WAITOK | BUS_DMA_ZERO, &inmw->dma_map)) { 829 device_printf(tc->dev, "Unable to allocate MW buffer of size " 830 "%zu/%zu\n", inmw->phys_size, inmw->size); 831 rc = ENOMEM; 832 goto err_free_tag_rem; 833 } 834 835 if (bus_dmamap_load(inmw->dma_tag, inmw->dma_map, inmw->virt_addr, 836 inmw->size, ntb_tool_load_cb, &cba, BUS_DMA_NOWAIT) || cba.error) { 837 device_printf(tc->dev, "Unable to load MW buffer of size " 838 "%zu/%zu\n", inmw->phys_size, inmw->size); 839 rc = ENOMEM; 840 goto err_free_dma; 841 } 842 inmw->dma_base = cba.addr; 843 844 rc = ntb_mw_set_trans(tc->dev, widx, inmw->dma_base, inmw->size); 845 if (rc) 846 goto err_free_mw; 847 848 return (0); 849 850 err_free_mw: 851 bus_dmamap_unload(inmw->dma_tag, inmw->dma_map); 852 853 err_free_dma: 854 bus_dmamem_free(inmw->dma_tag, inmw->virt_addr, inmw->dma_map); 855 856 err_free_tag_rem: 857 bus_dma_tag_destroy(inmw->dma_tag); 858 859 err_free_dma_var: 860 inmw->size = 0; 861 inmw->virt_addr = 0; 862 inmw->dma_base = 0; 863 inmw->dma_tag = 0; 864 inmw->dma_map = 0; 865 866 return (rc); 867 } 868 869 static void 870 tool_free_mw(struct tool_ctx *tc, int pidx, int widx) 871 { 872 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; 873 874 if (inmw->dma_base) 875 ntb_mw_clear_trans(tc->dev, widx); 876 877 if (inmw->virt_addr && inmw->dma_tag) { 878 bus_dmamap_unload(inmw->dma_tag, inmw->dma_map); 879 bus_dmamem_free(inmw->dma_tag, inmw->virt_addr, inmw->dma_map); 880 bus_dma_tag_destroy(inmw->dma_tag); 881 } 882 883 inmw->virt_addr = 0; 884 inmw->dma_base = 0; 885 inmw->dma_tag = 0; 886 inmw->dma_map = 0; 887 inmw->mm_base = 0; 888 inmw->size = 0; 889 } 890 891 static int 892 tool_mw_trans_read(struct tool_mw *inmw, struct sysctl_req *req) 893 { 894 ssize_t buf_size = 512; 895 struct sbuf *sb; 896 int rc = 0; 897 898 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req); 899 if (sb == NULL) { 900 rc = sb->s_error; 901 return (rc); 902 } 903 904 sbuf_printf(sb, "\nInbound MW \t%d\n", inmw->widx); 905 sbuf_printf(sb, "Port \t%d (%d)\n", 906 ntb_peer_port_number(inmw->tc->dev, inmw->pidx), inmw->pidx); 907 sbuf_printf(sb, "Window Address \t%p\n", inmw->mm_base); 908 sbuf_printf(sb, "DMA Address \t0x%016llx\n", (long long)inmw->dma_base); 909 sbuf_printf(sb, "Window Size \t0x%016zx[p]\n", inmw->size); 910 sbuf_printf(sb, "Alignment \t0x%016zx[p]\n", inmw->xlat_align); 911 sbuf_printf(sb, "Size Alignment \t0x%016zx[p]\n", 912 inmw->xlat_align_size); 913 sbuf_printf(sb, "Size Max \t0x%016zx[p]\n", inmw->phys_size); 914 915 rc = sbuf_finish(sb); 916 sbuf_delete(sb); 917 918 return (rc); 919 } 920 921 static int 922 tool_mw_trans_write(struct sysctl_oid *oidp, struct sysctl_req *req, 923 struct tool_mw *inmw, size_t wsize) 924 { 925 struct tool_ctx *tc = inmw->tc; 926 int rc = 0; 927 928 if (wsize == 0) 929 return (EINVAL); 930 931 /* No need to re-setup mw */ 932 if (inmw->size == wsize) 933 return (0); 934 935 /* free mw dma buffer */ 936 if (inmw->size) 937 tool_free_mw(tc, inmw->pidx, inmw->widx); 938 939 rc = tool_setup_mw(tc, inmw->pidx, inmw->widx, wsize); 940 941 return (rc); 942 } 943 944 static int 945 sysctl_mw_trans_handler(SYSCTL_HANDLER_ARGS) 946 { 947 struct tool_mw *inmw = (struct tool_mw *)arg1; 948 char buf[TOOL_BUF_LEN]; 949 ssize_t wsize; 950 int rc; 951 952 if (req->newptr == NULL) 953 return tool_mw_trans_read(inmw, req); 954 955 rc = get_ubuf(req, buf); 956 if (rc == 0) { 957 sscanf(buf, "%zi", &wsize); 958 return tool_mw_trans_write(oidp, req, inmw, wsize); 959 } 960 961 return (rc); 962 } 963 964 static int 965 sysctl_peer_mw_handle(SYSCTL_HANDLER_ARGS) 966 { 967 struct tool_mw *inmw = (struct tool_mw *)arg1; 968 char buf[TOOL_BUF_LEN]; 969 int rc; 970 971 if (req->newptr == NULL) 972 return tool_mw_read_fn(req, inmw, (char *)inmw->virt_addr, 973 &inmw->mw_peer_cmd_rw, inmw->mw_peer_buf_offset, 974 inmw->mw_peer_buf_size, "mw"); 975 976 rc = get_ubuf(req, buf); 977 if (rc == 0) 978 return tool_mw_write_fn(oidp, req, inmw, buf, inmw->virt_addr, 979 &inmw->mw_peer_cmd_rw, &inmw->mw_peer_buf_offset, 980 &inmw->mw_peer_buf_size); 981 982 return (rc); 983 } 984 985 static void tool_clear_mws(struct tool_ctx *tc) 986 { 987 int widx, pidx; 988 989 /* Free outbound memory windows */ 990 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 991 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) 992 tool_free_mw(tc, pidx, widx); 993 free(tc->peers[pidx].inmws, M_NTB_TOOL); 994 } 995 } 996 997 static int 998 tool_init_mws(struct tool_ctx *tc) 999 { 1000 struct tool_mw *mw; 1001 int widx, pidx, rc; 1002 1003 /* Initialize inbound memory windows and outbound MWs wrapper */ 1004 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1005 tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->dev); 1006 tc->peers[pidx].inmws = malloc(tc->peers[pidx].inmw_cnt * 1007 sizeof(*tc->peers[pidx].inmws), M_NTB_TOOL, 1008 M_WAITOK | M_ZERO); 1009 1010 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 1011 mw = &tc->peers[pidx].inmws[widx]; 1012 memset((void *)mw, 0, sizeof(*mw)); 1013 mw->tc = tc; 1014 mw->widx = widx; 1015 mw->pidx = pidx; 1016 mw->mw_buf_offset = DEFAULT_MW_OFF; 1017 mw->mw_buf_size = DEFAULT_MW_SIZE; 1018 /* get the tx buff details for each mw attached with each peer */ 1019 rc = ntb_mw_get_range(tc->dev, widx, &mw->phys_addr, 1020 &mw->mm_base, &mw->phys_size, &mw->xlat_align, 1021 &mw->xlat_align_size, &mw->addr_limit); 1022 if (rc) 1023 goto free_mws; 1024 } 1025 } 1026 1027 return (0); 1028 1029 free_mws: 1030 tool_clear_mws(tc); 1031 return (rc); 1032 } 1033 1034 /* 1035 * Doorbell handler for read/write 1036 */ 1037 static int 1038 sysctl_db_handle(SYSCTL_HANDLER_ARGS) 1039 { 1040 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1041 char buf[TOOL_BUF_LEN]; 1042 uint64_t db_bits; 1043 int rc; 1044 1045 if (req->newptr == NULL) { 1046 db_bits = ntb_db_read(tc->dev); 1047 return read_out(req, db_bits); 1048 } 1049 1050 rc = get_ubuf(req, buf); 1051 if (rc == 0) 1052 return tool_fn_write(tc, oidp, req, buf, NULL, false, NULL, 1053 ntb_db_clear); 1054 1055 return (rc); 1056 } 1057 1058 static int 1059 sysctl_db_valid_mask_handle(SYSCTL_HANDLER_ARGS) 1060 { 1061 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1062 1063 tc->db_valid_mask = ntb_db_valid_mask(tc->dev); 1064 if (!tc->db_valid_mask) { 1065 device_printf(tc->dev, "Error getting db_valid_mask from " 1066 "hw driver\n"); 1067 return (EINVAL); 1068 } else { 1069 return read_out(req, tc->db_valid_mask); 1070 } 1071 } 1072 1073 static int 1074 sysctl_db_mask_handle(SYSCTL_HANDLER_ARGS) 1075 { 1076 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1077 char buf[TOOL_BUF_LEN]; 1078 int rc; 1079 1080 if (req->newptr == NULL) { 1081 if (tc->db_mask_val == 0) 1082 ntb_db_valid_mask(tc->dev); 1083 return tool_fn_read(tc, req, NULL, tc->db_mask_val); 1084 } 1085 1086 rc = get_ubuf(req, buf); 1087 if (rc == 0) 1088 return tool_fn_write(tc, oidp, req, buf, &tc->db_mask_val, true, 1089 ntb_db_set_mask, ntb_db_clear_mask); 1090 1091 return (rc); 1092 } 1093 1094 static int 1095 sysctl_peer_db_handle(SYSCTL_HANDLER_ARGS) 1096 { 1097 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1098 char buf[TOOL_BUF_LEN]; 1099 int rc; 1100 1101 if (req->newptr == NULL) 1102 return tool_fn_read(tc, req, NULL, tc->peer_db_val); 1103 1104 rc = get_ubuf(req, buf); 1105 if (rc == 0) 1106 return tool_fn_write(tc, oidp, req, buf, &tc->peer_db_val, 1107 false, ntb_peer_db_set, NULL); 1108 1109 return (rc); 1110 } 1111 1112 static int 1113 sysctl_peer_db_mask_handle(SYSCTL_HANDLER_ARGS) 1114 { 1115 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1116 char buf[TOOL_BUF_LEN]; 1117 int rc; 1118 1119 if (req->newptr == NULL){ 1120 if (tc->peer_db_mask_val == 0) 1121 ntb_db_valid_mask(tc->dev); 1122 return tool_fn_read(tc, req, NULL, tc->peer_db_mask_val); 1123 } 1124 1125 rc = get_ubuf(req, buf); 1126 if (rc == 0) 1127 return tool_fn_write(tc, oidp, req, buf, &tc->peer_db_mask_val, 1128 true, NULL, NULL); 1129 1130 return (rc); 1131 } 1132 1133 static int 1134 sysctl_db_event_handle(SYSCTL_HANDLER_ARGS) 1135 { 1136 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1137 char buf[TOOL_BUF_LEN]; 1138 uint64_t bits; 1139 int rc; 1140 1141 if (req->newptr == NULL) 1142 return read_out(req, tc->db_event_val); 1143 1144 rc = get_ubuf(req, buf); 1145 if (rc) 1146 return (rc); 1147 1148 sscanf(buf, "%ju", &bits); 1149 tc->db_event_val = bits; 1150 callout_reset(&tc->db_event_timer, 1, tool_db_event_handler, tc); 1151 1152 return (0); 1153 } 1154 1155 /* 1156 * Scratchpads read/write methods 1157 */ 1158 static int 1159 sysctl_spad_handle(SYSCTL_HANDLER_ARGS) 1160 { 1161 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1162 unsigned int sidx = arg2; 1163 char buf[TOOL_BUF_LEN]; 1164 uint32_t bits; 1165 int rc; 1166 1167 if (req->newptr == NULL) { 1168 rc = ntb_spad_read(tc->dev, sidx, &bits); 1169 if (rc) 1170 return (rc); 1171 else 1172 return read_out(req, (uint64_t )bits); 1173 } 1174 1175 rc = get_ubuf(req, buf); 1176 if (rc == 0) { 1177 sscanf(buf, "%i", &bits); 1178 return ntb_spad_write(tc->dev, sidx, bits); 1179 } 1180 1181 return (rc); 1182 } 1183 1184 static int 1185 sysctl_peer_spad_handle(SYSCTL_HANDLER_ARGS) 1186 { 1187 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1188 unsigned int sidx = arg2; 1189 char buf[TOOL_BUF_LEN]; 1190 uint32_t bits; 1191 int rc; 1192 1193 if (req->newptr == NULL) { 1194 rc = ntb_peer_spad_read(tc->dev, sidx, &bits); 1195 if (rc) 1196 return (rc); 1197 else 1198 return read_out(req, (uint64_t )bits); 1199 } 1200 1201 rc = get_ubuf(req, buf); 1202 if (rc == 0) { 1203 sscanf(buf, "%i", &bits); 1204 return ntb_peer_spad_write(tc->dev, sidx, bits); 1205 } 1206 1207 return (rc); 1208 } 1209 1210 static void 1211 tool_init_spads(struct tool_ctx *tc) 1212 { 1213 int sidx, pidx; 1214 1215 /* Initialize inbound scratchpad structures */ 1216 tc->inspad_cnt = ntb_spad_count(tc->dev); 1217 tc->inspads = malloc(tc->inspad_cnt * sizeof(*tc->inspads), M_NTB_TOOL, 1218 M_WAITOK | M_ZERO); 1219 1220 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 1221 tc->inspads[sidx].sidx = sidx; 1222 tc->inspads[sidx].pidx = -1; 1223 tc->inspads[sidx].tc = tc; 1224 } 1225 1226 /* Initialize outbound scratchpad structures */ 1227 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1228 tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->dev); 1229 tc->peers[pidx].outspads = malloc(tc->peers[pidx].outspad_cnt * 1230 sizeof(*tc->peers[pidx].outspads), M_NTB_TOOL, M_WAITOK | 1231 M_ZERO); 1232 1233 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 1234 tc->peers[pidx].outspads[sidx].sidx = sidx; 1235 tc->peers[pidx].outspads[sidx].pidx = pidx; 1236 tc->peers[pidx].outspads[sidx].tc = tc; 1237 } 1238 } 1239 } 1240 1241 static void 1242 tool_clear_spads(struct tool_ctx *tc) 1243 { 1244 int pidx; 1245 1246 /* Free local inspads. */ 1247 free(tc->inspads, M_NTB_TOOL); 1248 1249 /* Free outspads for each peer. */ 1250 for (pidx = 0; pidx < tc->peer_cnt; pidx++) 1251 free(tc->peers[pidx].outspads, M_NTB_TOOL); 1252 } 1253 1254 /* 1255 * Initialization methods 1256 */ 1257 static int 1258 tool_check_ntb(struct tool_ctx *tc) 1259 { 1260 1261 /* create and initialize link callout handler */ 1262 callout_init(&tc->link_event_timer, 1); 1263 1264 /* create and initialize db callout handler */ 1265 callout_init(&tc->db_event_timer, 1); 1266 1267 /* Initialize sysctl read out values to default */ 1268 tc->link_status = 'U'; 1269 tc->db_mask_val = 0; 1270 tc->peer_db_val = 0; 1271 tc->peer_db_mask_val = 0; 1272 tc->db_event_val = 0; 1273 tc->link_bits = 0; 1274 1275 return (0); 1276 } 1277 1278 static void 1279 tool_clear_data(struct tool_ctx *tc) 1280 { 1281 1282 callout_drain(&tc->link_event_timer); 1283 callout_drain(&tc->db_event_timer); 1284 } 1285 1286 static int 1287 tool_init_ntb(struct tool_ctx *tc) 1288 { 1289 1290 return ntb_set_ctx(tc->dev, tc, &tool_ops); 1291 } 1292 1293 static void 1294 tool_clear_ntb(struct tool_ctx *tc) 1295 { 1296 1297 ntb_clear_ctx(tc->dev); 1298 ntb_link_disable(tc->dev); 1299 } 1300 1301 /* 1302 * Current sysctl implementation is made such that it gets attached to the 1303 * device and while detach it gets cleared automatically. 1304 */ 1305 static void 1306 tool_setup_sysctl(struct tool_ctx *tc) 1307 { 1308 char buf[TOOL_BUF_LEN], desc[TOOL_BUF_LEN]; 1309 struct sysctl_oid_list *top, *peer_top; 1310 struct sysctl_oid *parent, *peer; 1311 struct sysctl_ctx_list *clist; 1312 unsigned int pidx, sidx, widx; 1313 1314 clist = device_get_sysctl_ctx(tc->dev); 1315 parent = device_get_sysctl_tree(tc->dev); 1316 top = SYSCTL_CHILDREN(parent); 1317 1318 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "port", CTLTYPE_UINT | 1319 CTLFLAG_RDTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_local_port_number, 1320 "IU", "local port number"); 1321 1322 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "link", CTLTYPE_STRING | 1323 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_link_handle, 1324 "IU", "link info"); 1325 1326 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db", CTLTYPE_STRING | 1327 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_db_handle, 1328 "A", "db info"); 1329 1330 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db_valid_mask", CTLTYPE_STRING | 1331 CTLFLAG_RD | CTLFLAG_MPSAFE, tc, 0, sysctl_db_valid_mask_handle, 1332 "A", "db valid mask"); 1333 1334 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db_mask", CTLTYPE_STRING | 1335 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_db_mask_handle, 1336 "A", "db mask"); 1337 1338 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db_event", CTLTYPE_STRING | 1339 CTLFLAG_WR | CTLFLAG_MPSAFE, tc, 0, sysctl_db_event_handle, 1340 "A", "db event"); 1341 1342 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "peer_db", CTLTYPE_STRING | 1343 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_peer_db_handle, 1344 "A", "peer db"); 1345 1346 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "peer_db_mask", CTLTYPE_STRING | 1347 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_peer_db_mask_handle, 1348 "IU", "peer db mask info"); 1349 1350 if (tc->inspad_cnt != 0) { 1351 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 1352 snprintf(buf, sizeof(buf), "spad%d", sidx); 1353 snprintf(desc, sizeof(desc), "spad%d info", sidx); 1354 1355 SYSCTL_ADD_PROC(clist, top, OID_AUTO, buf, 1356 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1357 tc, sidx, sysctl_spad_handle, "IU", desc); 1358 } 1359 } 1360 1361 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1362 snprintf(buf, sizeof(buf), "peer%d", pidx); 1363 1364 peer = SYSCTL_ADD_NODE(clist, top, OID_AUTO, buf, 1365 CTLFLAG_RW | CTLFLAG_MPSAFE, 0, buf); 1366 peer_top = SYSCTL_CHILDREN(peer); 1367 1368 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, "port", 1369 CTLTYPE_UINT | CTLFLAG_RDTUN | CTLFLAG_MPSAFE, tc, pidx, 1370 sysctl_peer_port_number, "IU", "peer port number"); 1371 1372 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, "link", 1373 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, pidx, 1374 sysctl_peer_link_handle, "IU", "peer_link info"); 1375 1376 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, "link_event", 1377 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, pidx, 1378 sysctl_peer_link_event_handle, "IU", "link event"); 1379 1380 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 1381 snprintf(buf, sizeof(buf), "mw_trans%d", widx); 1382 snprintf(desc, sizeof(desc), "mw trans%d info", widx); 1383 1384 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, buf, 1385 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1386 &tc->peers[pidx].inmws[widx], 0, 1387 sysctl_mw_trans_handler, "IU", desc); 1388 1389 snprintf(buf, sizeof(buf), "mw%d", widx); 1390 snprintf(desc, sizeof(desc), "mw%d info", widx); 1391 1392 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, buf, 1393 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1394 &tc->peers[pidx].inmws[widx], 0, 1395 sysctl_mw_handle, "IU", desc); 1396 1397 snprintf(buf, sizeof(buf), "peer_mw%d", widx); 1398 snprintf(desc, sizeof(desc), "peer_mw%d info", widx); 1399 1400 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, buf, 1401 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1402 &tc->peers[pidx].inmws[widx], 0, 1403 sysctl_peer_mw_handle, "IU", desc); 1404 } 1405 1406 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 1407 snprintf(buf, sizeof(buf), "spad%d", sidx); 1408 snprintf(desc, sizeof(desc), "spad%d info", sidx); 1409 1410 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, buf, 1411 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1412 tc, sidx, sysctl_peer_spad_handle, "IU", desc); 1413 } 1414 } 1415 } 1416 1417 static int 1418 ntb_tool_probe(device_t dev) 1419 { 1420 device_set_desc(dev, "NTB TOOL"); 1421 return (0); 1422 } 1423 1424 static int 1425 ntb_tool_attach(device_t dev) 1426 { 1427 struct tool_ctx *tc = device_get_softc(dev); 1428 int rc = 0; 1429 1430 tc->dev = dev; 1431 rc = tool_check_ntb(tc); 1432 if (rc) 1433 goto out; 1434 1435 tool_init_peers(tc); 1436 1437 rc = tool_init_mws(tc); 1438 if (rc) 1439 goto err_clear_data; 1440 1441 tool_init_spads(tc); 1442 1443 rc = tool_init_ntb(tc); 1444 if (rc) 1445 goto err_clear_spads; 1446 1447 tool_setup_sysctl(tc); 1448 1449 return (0); 1450 1451 err_clear_spads: 1452 tool_clear_spads(tc); 1453 tool_clear_mws(tc); 1454 tool_clear_peers(tc); 1455 err_clear_data: 1456 tool_clear_data(tc); 1457 out: 1458 device_printf(dev, "ntb_tool attached failed with err=(%d).\n", rc); 1459 return (rc); 1460 } 1461 1462 static int 1463 ntb_tool_detach(device_t dev) 1464 { 1465 struct tool_ctx *tc = device_get_softc(dev); 1466 1467 tool_clear_ntb(tc); 1468 1469 tool_clear_spads(tc); 1470 1471 tool_clear_mws(tc); 1472 1473 tool_clear_peers(tc); 1474 1475 tool_clear_data(tc); 1476 1477 return (0); 1478 } 1479 1480 static device_method_t ntb_tool_methods[] = { 1481 /* Device interface */ 1482 DEVMETHOD(device_probe, ntb_tool_probe), 1483 DEVMETHOD(device_attach, ntb_tool_attach), 1484 DEVMETHOD(device_detach, ntb_tool_detach), 1485 DEVMETHOD_END 1486 }; 1487 1488 static DEFINE_CLASS_0(ntb_tool, ntb_tool_driver, ntb_tool_methods, 1489 sizeof(struct tool_ctx)); 1490 DRIVER_MODULE(ntb_tool, ntb_hw, ntb_tool_driver, NULL, NULL); 1491 MODULE_DEPEND(ntb_tool, ntb, 1, 1, 1); 1492 MODULE_VERSION(ntb_tool, 1.0); 1493