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