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[16]; 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 if (!data_buf) { 623 rc = ENOMEM; 624 goto out; 625 } 626 627 if (s_pflag) 628 memset(data_buf, pattern, data_buf_size); 629 else 630 arc4rand(data_buf, data_buf_size, 1); 631 632 memcpy(write_buf + *buf_offset, data_buf, data_buf_size); 633 634 free(data_buf, M_NTB_TOOL); 635 636 read_out: 637 /* cmd_op value is set to two as sysctl read call executes twice */ 638 *cmd_op = 2; 639 out: 640 return (rc); 641 } 642 643 /* 644 * Port sysctl read/write methods 645 */ 646 static int 647 sysctl_peer_port_number(SYSCTL_HANDLER_ARGS) 648 { 649 struct tool_ctx *tc = (struct tool_ctx *)arg1; 650 int rc, pidx = arg2, peer_port; 651 652 peer_port = ntb_peer_port_number(tc->dev, pidx); 653 rc = sysctl_handle_int(oidp, &peer_port, 0, req); 654 if (rc) 655 device_printf(tc->dev, "Peer port sysctl set failed with err=" 656 "(%d).\n", rc); 657 else 658 tc->peers[pidx].port_no = peer_port; 659 660 return (rc); 661 } 662 663 static int 664 sysctl_local_port_number(SYSCTL_HANDLER_ARGS) 665 { 666 struct tool_ctx *tc = (struct tool_ctx *)arg1; 667 int rc, local_port; 668 669 local_port = ntb_port_number(tc->dev); 670 rc = sysctl_handle_int(oidp, &local_port, 0, req); 671 if (rc) 672 device_printf(tc->dev, "Local port sysctl set failed with err=" 673 "(%d).\n", rc); 674 else 675 tc->port_no = local_port; 676 677 return (rc); 678 } 679 680 static int 681 tool_init_peers(struct tool_ctx *tc) 682 { 683 int pidx; 684 685 tc->peer_cnt = ntb_peer_port_count(tc->dev); 686 tc->peers = malloc(tc->peer_cnt * sizeof(*tc->peers), M_NTB_TOOL, 687 M_WAITOK | M_ZERO); 688 if (tc->peers == NULL) 689 return (ENOMEM); 690 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 691 tc->peers[pidx].pidx = pidx; 692 tc->peers[pidx].tc = tc; 693 } 694 695 return (0); 696 } 697 698 static void 699 tool_clear_peers(struct tool_ctx *tc) 700 { 701 702 free(tc->peers, M_NTB_TOOL); 703 } 704 705 /* 706 * Link state sysctl read/write methods 707 */ 708 static int 709 sysctl_link_handle(SYSCTL_HANDLER_ARGS) 710 { 711 struct tool_ctx *tc = (struct tool_ctx *)arg1; 712 char buf[TOOL_BUF_LEN]; 713 int rc; 714 715 if (req->newptr == NULL) { 716 snprintf(buf, 2, "%c", tc->link_status); 717 718 return SYSCTL_OUT(req, buf, 2); 719 } 720 721 rc = get_ubuf(req, buf); 722 if (rc) 723 return (rc); 724 725 if (buf[0] == 'Y') 726 rc = ntb_link_enable(tc->dev, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 727 else if (buf[0] == 'N') 728 rc = ntb_link_disable(tc->dev); 729 else 730 rc = EINVAL; 731 732 sscanf(buf, "%c", &tc->link_status); 733 734 return (0); 735 } 736 737 static int 738 sysctl_peer_link_handle(SYSCTL_HANDLER_ARGS) 739 { 740 struct tool_ctx *tc = (struct tool_ctx *)arg1; 741 int up = 0, pidx = arg2; 742 char buf[TOOL_BUF_LEN]; 743 744 if (req->newptr) 745 return (0); 746 747 up = ntb_link_is_up(tc->dev, NULL, NULL); 748 memset((void *)buf, 0, TOOL_BUF_LEN); 749 if (up & (1UL << pidx)) 750 buf[0] = 'Y'; 751 else 752 buf[0] = 'N'; 753 754 return SYSCTL_OUT(req, buf, sizeof(buf)); 755 } 756 757 static int 758 sysctl_peer_link_event_handle(SYSCTL_HANDLER_ARGS) 759 { 760 struct tool_ctx *tc = (struct tool_ctx *)arg1; 761 char buf[TOOL_BUF_LEN]; 762 int rc, pidx = arg2; 763 uint64_t bits; 764 765 if (req->newptr == NULL) 766 return read_out(req, tc->link_bits); 767 768 rc = get_ubuf(req, buf); 769 if (rc) 770 return (rc); 771 772 sscanf(buf, "0x%jx", &bits); 773 tc->link_bits = bits; 774 tc->link_mask = (1ULL << ((pidx) % 64)); 775 776 callout_reset(&tc->link_event_timer, 1, tool_link_event_handler, tc); 777 return (0); 778 } 779 780 /* 781 * Memory windows read/write/setting methods 782 */ 783 static void 784 ntb_tool_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 785 { 786 struct ntb_tool_load_cb_args *cba = (struct ntb_tool_load_cb_args *)arg; 787 788 if (!(cba->error = error)) 789 cba->addr = segs[0].ds_addr; 790 } 791 792 static int 793 sysctl_mw_handle(SYSCTL_HANDLER_ARGS) 794 { 795 struct tool_mw *inmw = (struct tool_mw *)arg1; 796 char buf[TOOL_BUF_LEN]; 797 int rc; 798 799 if (req->newptr == NULL) 800 return tool_mw_read_fn(req, inmw, (char *)inmw->mm_base, 801 &inmw->mw_cmd_rw, inmw->mw_buf_offset, inmw->mw_buf_size, 802 "mw"); 803 804 rc = get_ubuf(req, buf); 805 if (!rc) 806 return tool_mw_write_fn(oidp, req, inmw, buf, inmw->mm_base, 807 &inmw->mw_cmd_rw, &inmw->mw_buf_offset, &inmw->mw_buf_size); 808 809 return (rc); 810 } 811 812 static int 813 tool_setup_mw(struct tool_ctx *tc, unsigned int pidx, unsigned int widx, 814 size_t req_size) 815 { 816 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; 817 struct ntb_tool_load_cb_args cba; 818 int rc; 819 820 if (req_size == 0) 821 inmw->size = roundup(inmw->phys_size, inmw->xlat_align_size); 822 else 823 inmw->size = roundup(req_size, inmw->xlat_align_size); 824 825 device_printf(tc->dev, "mw_size %zi req_size %zi buff %zi\n", 826 inmw->phys_size, req_size, inmw->size); 827 828 if (bus_dma_tag_create(bus_get_dma_tag(tc->dev), inmw->xlat_align, 0, 829 inmw->addr_limit, BUS_SPACE_MAXADDR, NULL, NULL, inmw->size, 1, 830 inmw->size, 0, NULL, NULL, &inmw->dma_tag)) { 831 device_printf(tc->dev, "Unable to create MW tag of size " 832 "%zu/%zu\n", inmw->phys_size, inmw->size); 833 rc = ENOMEM; 834 goto err_free_dma_var; 835 } 836 837 if (bus_dmamem_alloc(inmw->dma_tag, (void **)&inmw->virt_addr, 838 BUS_DMA_WAITOK | BUS_DMA_ZERO, &inmw->dma_map)) { 839 device_printf(tc->dev, "Unable to allocate MW buffer of size " 840 "%zu/%zu\n", inmw->phys_size, inmw->size); 841 rc = ENOMEM; 842 goto err_free_tag_rem; 843 } 844 845 if (bus_dmamap_load(inmw->dma_tag, inmw->dma_map, inmw->virt_addr, 846 inmw->size, ntb_tool_load_cb, &cba, BUS_DMA_NOWAIT) || cba.error) { 847 device_printf(tc->dev, "Unable to load MW buffer of size " 848 "%zu/%zu\n", inmw->phys_size, inmw->size); 849 rc = ENOMEM; 850 goto err_free_dma; 851 } 852 inmw->dma_base = cba.addr; 853 854 rc = ntb_mw_set_trans(tc->dev, widx, inmw->dma_base, inmw->size); 855 if (rc) 856 goto err_free_mw; 857 858 return (0); 859 860 err_free_mw: 861 bus_dmamap_unload(inmw->dma_tag, inmw->dma_map); 862 863 err_free_dma: 864 bus_dmamem_free(inmw->dma_tag, inmw->virt_addr, inmw->dma_map); 865 866 err_free_tag_rem: 867 bus_dma_tag_destroy(inmw->dma_tag); 868 869 err_free_dma_var: 870 inmw->size = 0; 871 inmw->virt_addr = 0; 872 inmw->dma_base = 0; 873 inmw->dma_tag = 0; 874 inmw->dma_map = 0; 875 876 return (rc); 877 } 878 879 static void 880 tool_free_mw(struct tool_ctx *tc, int pidx, int widx) 881 { 882 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; 883 884 if (inmw->dma_base) 885 ntb_mw_clear_trans(tc->dev, widx); 886 887 if (inmw->virt_addr && inmw->dma_tag) { 888 bus_dmamap_unload(inmw->dma_tag, inmw->dma_map); 889 bus_dmamem_free(inmw->dma_tag, inmw->virt_addr, inmw->dma_map); 890 bus_dma_tag_destroy(inmw->dma_tag); 891 } 892 893 inmw->virt_addr = 0; 894 inmw->dma_base = 0; 895 inmw->dma_tag = 0; 896 inmw->dma_map = 0; 897 inmw->mm_base = 0; 898 inmw->size = 0; 899 } 900 901 static int 902 tool_mw_trans_read(struct tool_mw *inmw, struct sysctl_req *req) 903 { 904 ssize_t buf_size = 512; 905 struct sbuf *sb; 906 int rc = 0; 907 908 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req); 909 if (sb == NULL) { 910 rc = sb->s_error; 911 return (rc); 912 } 913 914 sbuf_printf(sb, "\nInbound MW \t%d\n", inmw->widx); 915 sbuf_printf(sb, "Port \t%d (%d)\n", 916 ntb_peer_port_number(inmw->tc->dev, inmw->pidx), inmw->pidx); 917 sbuf_printf(sb, "Window Address \t%p\n", inmw->mm_base); 918 sbuf_printf(sb, "DMA Address \t0x%016llx\n", (long long)inmw->dma_base); 919 sbuf_printf(sb, "Window Size \t0x%016zx[p]\n", inmw->size); 920 sbuf_printf(sb, "Alignment \t0x%016zx[p]\n", inmw->xlat_align); 921 sbuf_printf(sb, "Size Alignment \t0x%016zx[p]\n", 922 inmw->xlat_align_size); 923 sbuf_printf(sb, "Size Max \t0x%016zx[p]\n", inmw->phys_size); 924 925 rc = sbuf_finish(sb); 926 sbuf_delete(sb); 927 928 return (rc); 929 } 930 931 static int 932 tool_mw_trans_write(struct sysctl_oid *oidp, struct sysctl_req *req, 933 struct tool_mw *inmw, size_t wsize) 934 { 935 struct tool_ctx *tc = inmw->tc; 936 int rc = 0; 937 938 if (wsize == 0) 939 return (EINVAL); 940 941 /* No need to re-setup mw */ 942 if (inmw->size == wsize) 943 return (0); 944 945 /* free mw dma buffer */ 946 if (inmw->size) 947 tool_free_mw(tc, inmw->pidx, inmw->widx); 948 949 rc = tool_setup_mw(tc, inmw->pidx, inmw->widx, wsize); 950 951 return (rc); 952 } 953 954 static int 955 sysctl_mw_trans_handler(SYSCTL_HANDLER_ARGS) 956 { 957 struct tool_mw *inmw = (struct tool_mw *)arg1; 958 char buf[TOOL_BUF_LEN]; 959 ssize_t wsize; 960 int rc; 961 962 if (req->newptr == NULL) 963 return tool_mw_trans_read(inmw, req); 964 965 rc = get_ubuf(req, buf); 966 if (rc == 0) { 967 sscanf(buf, "%zi", &wsize); 968 return tool_mw_trans_write(oidp, req, inmw, wsize); 969 } 970 971 return (rc); 972 } 973 974 static int 975 sysctl_peer_mw_handle(SYSCTL_HANDLER_ARGS) 976 { 977 struct tool_mw *inmw = (struct tool_mw *)arg1; 978 char buf[TOOL_BUF_LEN]; 979 int rc; 980 981 if (req->newptr == NULL) 982 return tool_mw_read_fn(req, inmw, (char *)inmw->virt_addr, 983 &inmw->mw_peer_cmd_rw, inmw->mw_peer_buf_offset, 984 inmw->mw_peer_buf_size, "mw"); 985 986 rc = get_ubuf(req, buf); 987 if (rc == 0) 988 return tool_mw_write_fn(oidp, req, inmw, buf, inmw->virt_addr, 989 &inmw->mw_peer_cmd_rw, &inmw->mw_peer_buf_offset, 990 &inmw->mw_peer_buf_size); 991 992 return (rc); 993 } 994 995 static void tool_clear_mws(struct tool_ctx *tc) 996 { 997 int widx, pidx; 998 999 /* Free outbound memory windows */ 1000 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1001 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) 1002 tool_free_mw(tc, pidx, widx); 1003 free(tc->peers[pidx].inmws, M_NTB_TOOL); 1004 } 1005 } 1006 1007 static int 1008 tool_init_mws(struct tool_ctx *tc) 1009 { 1010 struct tool_mw *mw; 1011 int widx, pidx, rc; 1012 1013 /* Initialize inbound memory windows and outbound MWs wrapper */ 1014 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1015 tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->dev); 1016 tc->peers[pidx].inmws = malloc(tc->peers[pidx].inmw_cnt * 1017 sizeof(*tc->peers[pidx].inmws), M_NTB_TOOL, 1018 M_WAITOK | M_ZERO); 1019 if (tc->peers[pidx].inmws == NULL) 1020 return (ENOMEM); 1021 1022 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 1023 mw = &tc->peers[pidx].inmws[widx]; 1024 memset((void *)mw, 0, sizeof(*mw)); 1025 mw->tc = tc; 1026 mw->widx = widx; 1027 mw->pidx = pidx; 1028 mw->mw_buf_offset = DEFAULT_MW_OFF; 1029 mw->mw_buf_size = DEFAULT_MW_SIZE; 1030 /* get the tx buff details for each mw attached with each peer */ 1031 rc = ntb_mw_get_range(tc->dev, widx, &mw->phys_addr, 1032 &mw->mm_base, &mw->phys_size, &mw->xlat_align, 1033 &mw->xlat_align_size, &mw->addr_limit); 1034 if (rc) 1035 goto free_mws; 1036 } 1037 } 1038 1039 return (0); 1040 1041 free_mws: 1042 tool_clear_mws(tc); 1043 return (rc); 1044 } 1045 1046 /* 1047 * Doorbell handler for read/write 1048 */ 1049 static int 1050 sysctl_db_handle(SYSCTL_HANDLER_ARGS) 1051 { 1052 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1053 char buf[TOOL_BUF_LEN]; 1054 uint64_t db_bits; 1055 int rc; 1056 1057 if (req->newptr == NULL) { 1058 db_bits = ntb_db_read(tc->dev); 1059 return read_out(req, db_bits); 1060 } 1061 1062 rc = get_ubuf(req, buf); 1063 if (rc == 0) 1064 return tool_fn_write(tc, oidp, req, buf, NULL, false, NULL, 1065 ntb_db_clear); 1066 1067 return (rc); 1068 } 1069 1070 static int 1071 sysctl_db_valid_mask_handle(SYSCTL_HANDLER_ARGS) 1072 { 1073 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1074 1075 tc->db_valid_mask = ntb_db_valid_mask(tc->dev); 1076 if (!tc->db_valid_mask) { 1077 device_printf(tc->dev, "Error getting db_valid_mask from " 1078 "hw driver\n"); 1079 return (EINVAL); 1080 } else { 1081 return read_out(req, tc->db_valid_mask); 1082 } 1083 } 1084 1085 static int 1086 sysctl_db_mask_handle(SYSCTL_HANDLER_ARGS) 1087 { 1088 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1089 char buf[TOOL_BUF_LEN]; 1090 int rc; 1091 1092 if (req->newptr == NULL) { 1093 if (tc->db_mask_val == 0) 1094 ntb_db_valid_mask(tc->dev); 1095 return tool_fn_read(tc, req, NULL, tc->db_mask_val); 1096 } 1097 1098 rc = get_ubuf(req, buf); 1099 if (rc == 0) 1100 return tool_fn_write(tc, oidp, req, buf, &tc->db_mask_val, true, 1101 ntb_db_set_mask, ntb_db_clear_mask); 1102 1103 return (rc); 1104 } 1105 1106 static int 1107 sysctl_peer_db_handle(SYSCTL_HANDLER_ARGS) 1108 { 1109 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1110 char buf[TOOL_BUF_LEN]; 1111 int rc; 1112 1113 if (req->newptr == NULL) 1114 return tool_fn_read(tc, req, NULL, tc->peer_db_val); 1115 1116 rc = get_ubuf(req, buf); 1117 if (rc == 0) 1118 return tool_fn_write(tc, oidp, req, buf, &tc->peer_db_val, 1119 false, ntb_peer_db_set, NULL); 1120 1121 return (rc); 1122 } 1123 1124 static int 1125 sysctl_peer_db_mask_handle(SYSCTL_HANDLER_ARGS) 1126 { 1127 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1128 char buf[TOOL_BUF_LEN]; 1129 int rc; 1130 1131 if (req->newptr == NULL){ 1132 if (tc->peer_db_mask_val == 0) 1133 ntb_db_valid_mask(tc->dev); 1134 return tool_fn_read(tc, req, NULL, tc->peer_db_mask_val); 1135 } 1136 1137 rc = get_ubuf(req, buf); 1138 if (rc == 0) 1139 return tool_fn_write(tc, oidp, req, buf, &tc->peer_db_mask_val, 1140 true, NULL, NULL); 1141 1142 return (rc); 1143 } 1144 1145 static int 1146 sysctl_db_event_handle(SYSCTL_HANDLER_ARGS) 1147 { 1148 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1149 char buf[TOOL_BUF_LEN]; 1150 uint64_t bits; 1151 int rc; 1152 1153 if (req->newptr == NULL) 1154 return read_out(req, tc->db_event_val); 1155 1156 rc = get_ubuf(req, buf); 1157 if (rc) 1158 return (rc); 1159 1160 sscanf(buf, "%ju", &bits); 1161 tc->db_event_val = bits; 1162 callout_reset(&tc->db_event_timer, 1, tool_db_event_handler, tc); 1163 1164 return (0); 1165 } 1166 1167 /* 1168 * Scratchpads read/write methods 1169 */ 1170 static int 1171 sysctl_spad_handle(SYSCTL_HANDLER_ARGS) 1172 { 1173 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1174 unsigned int sidx = arg2; 1175 char buf[TOOL_BUF_LEN]; 1176 uint32_t bits; 1177 int rc; 1178 1179 if (req->newptr == NULL) { 1180 rc = ntb_spad_read(tc->dev, sidx, &bits); 1181 if (rc) 1182 return (rc); 1183 else 1184 return read_out(req, (uint64_t )bits); 1185 } 1186 1187 rc = get_ubuf(req, buf); 1188 if (rc == 0) { 1189 sscanf(buf, "%i", &bits); 1190 return ntb_spad_write(tc->dev, sidx, bits); 1191 } 1192 1193 return (rc); 1194 } 1195 1196 static int 1197 sysctl_peer_spad_handle(SYSCTL_HANDLER_ARGS) 1198 { 1199 struct tool_ctx *tc = (struct tool_ctx *)arg1; 1200 unsigned int sidx = arg2; 1201 char buf[TOOL_BUF_LEN]; 1202 uint32_t bits; 1203 int rc; 1204 1205 if (req->newptr == NULL) { 1206 rc = ntb_peer_spad_read(tc->dev, sidx, &bits); 1207 if (rc) 1208 return (rc); 1209 else 1210 return read_out(req, (uint64_t )bits); 1211 } 1212 1213 rc = get_ubuf(req, buf); 1214 if (rc == 0) { 1215 sscanf(buf, "%i", &bits); 1216 return ntb_peer_spad_write(tc->dev, sidx, bits); 1217 } 1218 1219 return (rc); 1220 } 1221 1222 static int 1223 tool_init_spads(struct tool_ctx *tc) 1224 { 1225 int sidx, pidx; 1226 1227 /* Initialize inbound scratchpad structures */ 1228 tc->inspad_cnt = ntb_spad_count(tc->dev); 1229 tc->inspads = malloc(tc->inspad_cnt * sizeof(*tc->inspads), M_NTB_TOOL, 1230 M_WAITOK | M_ZERO); 1231 if (tc->inspads == NULL) 1232 return (ENOMEM); 1233 1234 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 1235 tc->inspads[sidx].sidx = sidx; 1236 tc->inspads[sidx].pidx = -1; 1237 tc->inspads[sidx].tc = tc; 1238 } 1239 1240 /* Initialize outbound scratchpad structures */ 1241 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1242 tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->dev); 1243 tc->peers[pidx].outspads = malloc(tc->peers[pidx].outspad_cnt * 1244 sizeof(*tc->peers[pidx].outspads), M_NTB_TOOL, M_WAITOK | 1245 M_ZERO); 1246 if (tc->peers[pidx].outspads == NULL) 1247 return (ENOMEM); 1248 1249 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 1250 tc->peers[pidx].outspads[sidx].sidx = sidx; 1251 tc->peers[pidx].outspads[sidx].pidx = pidx; 1252 tc->peers[pidx].outspads[sidx].tc = tc; 1253 } 1254 } 1255 1256 return (0); 1257 } 1258 1259 static void 1260 tool_clear_spads(struct tool_ctx *tc) 1261 { 1262 int pidx; 1263 1264 /* Free local inspads. */ 1265 free(tc->inspads, M_NTB_TOOL); 1266 1267 /* Free outspads for each peer. */ 1268 for (pidx = 0; pidx < tc->peer_cnt; pidx++) 1269 free(tc->peers[pidx].outspads, M_NTB_TOOL); 1270 } 1271 1272 /* 1273 * Initialization methods 1274 */ 1275 static int 1276 tool_check_ntb(struct tool_ctx *tc) 1277 { 1278 1279 /* create and initialize link callout handler */ 1280 callout_init(&tc->link_event_timer, 1); 1281 1282 /* create and initialize db callout handler */ 1283 callout_init(&tc->db_event_timer, 1); 1284 1285 /* Initialize sysctl read out values to default */ 1286 tc->link_status = 'U'; 1287 tc->db_mask_val = 0; 1288 tc->peer_db_val = 0; 1289 tc->peer_db_mask_val = 0; 1290 tc->db_event_val = 0; 1291 tc->link_bits = 0; 1292 1293 return (0); 1294 } 1295 1296 static void 1297 tool_clear_data(struct tool_ctx *tc) 1298 { 1299 1300 callout_drain(&tc->link_event_timer); 1301 callout_drain(&tc->db_event_timer); 1302 } 1303 1304 static int 1305 tool_init_ntb(struct tool_ctx *tc) 1306 { 1307 1308 return ntb_set_ctx(tc->dev, tc, &tool_ops); 1309 } 1310 1311 static void 1312 tool_clear_ntb(struct tool_ctx *tc) 1313 { 1314 1315 ntb_clear_ctx(tc->dev); 1316 ntb_link_disable(tc->dev); 1317 } 1318 1319 /* 1320 * Current sysctl implementation is made such that it gets attached to the 1321 * device and while detach it gets cleared automatically. 1322 */ 1323 static void 1324 tool_setup_sysctl(struct tool_ctx *tc) 1325 { 1326 char buf[TOOL_BUF_LEN], desc[TOOL_BUF_LEN]; 1327 struct sysctl_oid_list *top, *peer_top; 1328 struct sysctl_oid *parent, *peer; 1329 struct sysctl_ctx_list *clist; 1330 unsigned int pidx, sidx, widx; 1331 1332 clist = device_get_sysctl_ctx(tc->dev); 1333 parent = device_get_sysctl_tree(tc->dev); 1334 top = SYSCTL_CHILDREN(parent); 1335 1336 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "port", CTLTYPE_UINT | 1337 CTLFLAG_RDTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_local_port_number, 1338 "IU", "local port number"); 1339 1340 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "link", CTLTYPE_STRING | 1341 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_link_handle, 1342 "IU", "link info"); 1343 1344 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db", CTLTYPE_STRING | 1345 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_db_handle, 1346 "A", "db info"); 1347 1348 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db_valid_mask", CTLTYPE_STRING | 1349 CTLFLAG_RD | CTLFLAG_MPSAFE, tc, 0, sysctl_db_valid_mask_handle, 1350 "A", "db valid mask"); 1351 1352 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db_mask", CTLTYPE_STRING | 1353 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_db_mask_handle, 1354 "A", "db mask"); 1355 1356 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db_event", CTLTYPE_STRING | 1357 CTLFLAG_WR | CTLFLAG_MPSAFE, tc, 0, sysctl_db_event_handle, 1358 "A", "db event"); 1359 1360 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "peer_db", CTLTYPE_STRING | 1361 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_peer_db_handle, 1362 "A", "peer db"); 1363 1364 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "peer_db_mask", CTLTYPE_STRING | 1365 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_peer_db_mask_handle, 1366 "IU", "peer db mask info"); 1367 1368 if (tc->inspad_cnt != 0) { 1369 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 1370 snprintf(buf, sizeof(buf), "spad%d", sidx); 1371 snprintf(desc, sizeof(desc), "spad%d info", sidx); 1372 1373 SYSCTL_ADD_PROC(clist, top, OID_AUTO, buf, 1374 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1375 tc, sidx, sysctl_spad_handle, "IU", desc); 1376 } 1377 } 1378 1379 for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 1380 snprintf(buf, sizeof(buf), "peer%d", pidx); 1381 1382 peer = SYSCTL_ADD_NODE(clist, top, OID_AUTO, buf, 1383 CTLFLAG_RW | CTLFLAG_MPSAFE, 0, buf); 1384 peer_top = SYSCTL_CHILDREN(peer); 1385 1386 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, "port", 1387 CTLTYPE_UINT | CTLFLAG_RDTUN | CTLFLAG_MPSAFE, tc, pidx, 1388 sysctl_peer_port_number, "IU", "peer port number"); 1389 1390 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, "link", 1391 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, pidx, 1392 sysctl_peer_link_handle, "IU", "peer_link info"); 1393 1394 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, "link_event", 1395 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, pidx, 1396 sysctl_peer_link_event_handle, "IU", "link event"); 1397 1398 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 1399 snprintf(buf, sizeof(buf), "mw_trans%d", widx); 1400 snprintf(desc, sizeof(desc), "mw trans%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_mw_trans_handler, "IU", desc); 1406 1407 snprintf(buf, sizeof(buf), "mw%d", widx); 1408 snprintf(desc, sizeof(desc), "mw%d info", widx); 1409 1410 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, buf, 1411 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1412 &tc->peers[pidx].inmws[widx], 0, 1413 sysctl_mw_handle, "IU", desc); 1414 1415 snprintf(buf, sizeof(buf), "peer_mw%d", widx); 1416 snprintf(desc, sizeof(desc), "peer_mw%d info", widx); 1417 1418 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, buf, 1419 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1420 &tc->peers[pidx].inmws[widx], 0, 1421 sysctl_peer_mw_handle, "IU", desc); 1422 } 1423 1424 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 1425 snprintf(buf, sizeof(buf), "spad%d", sidx); 1426 snprintf(desc, sizeof(desc), "spad%d info", sidx); 1427 1428 SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, buf, 1429 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1430 tc, sidx, sysctl_peer_spad_handle, "IU", desc); 1431 } 1432 } 1433 } 1434 1435 static int 1436 ntb_tool_probe(device_t dev) 1437 { 1438 device_set_desc(dev, "NTB TOOL"); 1439 return (0); 1440 } 1441 1442 static int 1443 ntb_tool_attach(device_t dev) 1444 { 1445 struct tool_ctx *tc = device_get_softc(dev); 1446 int rc = 0; 1447 1448 tc->dev = dev; 1449 rc = tool_check_ntb(tc); 1450 if (rc) 1451 goto out; 1452 1453 rc = tool_init_peers(tc); 1454 if (rc) 1455 goto err_clear_data; 1456 1457 rc = tool_init_mws(tc); 1458 if (rc) 1459 goto err_clear_data; 1460 1461 rc = tool_init_spads(tc); 1462 if (rc) 1463 goto err_clear_mws; 1464 1465 rc = tool_init_ntb(tc); 1466 if (rc) 1467 goto err_clear_spads; 1468 1469 tool_setup_sysctl(tc); 1470 1471 return (0); 1472 1473 err_clear_spads: 1474 tool_clear_spads(tc); 1475 err_clear_mws: 1476 tool_clear_mws(tc); 1477 tool_clear_peers(tc); 1478 err_clear_data: 1479 tool_clear_data(tc); 1480 out: 1481 device_printf(dev, "ntb_tool attached failed with err=(%d).\n", rc); 1482 return (rc); 1483 } 1484 1485 static int 1486 ntb_tool_detach(device_t dev) 1487 { 1488 struct tool_ctx *tc = device_get_softc(dev); 1489 1490 tool_clear_ntb(tc); 1491 1492 tool_clear_spads(tc); 1493 1494 tool_clear_mws(tc); 1495 1496 tool_clear_peers(tc); 1497 1498 tool_clear_data(tc); 1499 1500 return (0); 1501 } 1502 1503 static device_method_t ntb_tool_methods[] = { 1504 /* Device interface */ 1505 DEVMETHOD(device_probe, ntb_tool_probe), 1506 DEVMETHOD(device_attach, ntb_tool_attach), 1507 DEVMETHOD(device_detach, ntb_tool_detach), 1508 DEVMETHOD_END 1509 }; 1510 1511 devclass_t ntb_tool_devclass; 1512 static DEFINE_CLASS_0(ntb_tool, ntb_tool_driver, ntb_tool_methods, 1513 sizeof(struct tool_ctx)); 1514 DRIVER_MODULE(ntb_tool, ntb_hw, ntb_tool_driver, ntb_tool_devclass, NULL, NULL); 1515 MODULE_DEPEND(ntb_tool, ntb, 1, 1, 1); 1516 MODULE_VERSION(ntb_tool, 1.0); 1517