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