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.
7 * Copyright (c) 2019 Advanced Micro Devices, Inc. All Rights Reserved.
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.
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.
20 * Copyright (c) 2019 Advanced Micro Devices, Inc. All Rights Reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
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
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.
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.
48 * PCIe NTB Debugging Tool FreeBSD driver
52 * How to use this tool, by example.
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
93 * The above example list shows
94 * 1) three memory windows,
95 * 1) eight scratchpad registers.
100 * Based on the underlined ntb_hw driver config & connection topology, these
101 * things might differ.
102 *-----------------------------------------------------------------------------
103 * Eg: check local/peer port information.
105 * # Get local device port number
106 * root@local# sysctl dev.ntb_tool.0.port
108 * # Check peer device port number
109 * root@local# sysctl dev.ntb_tool.0.peer0.port
110 *-----------------------------------------------------------------------------
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
117 * # Check if link with peer device is up/down:
118 * root@local# sysctl dev.ntb_tool.0.peer0.link
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
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
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
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
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
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
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
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
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)
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
166 * # Write/read data to/from inbound memory window with specific pattern/random
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"
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 *-----------------------------------------------------------------------------
179 * contact information:
180 * Arpan Palit <arpan.palit@amd.com>
184 #include <sys/cdefs.h>
185 __FBSDID("$FreeBSD$");
187 #include <sys/param.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>
195 #include <machine/bus.h>
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
208 MALLOC_DEFINE(M_NTB_TOOL, "ntb_tool", "ntb_tool driver memory allocation");
211 * Memory windows descriptor structure
218 /* Rx buff is off virt_addr / dma_base */
221 bus_dmamap_t dma_map;
222 bus_dma_tag_t dma_tag;
224 /* Tx buff is off vbase / phys_addr */
226 vm_paddr_t phys_addr;
227 bus_addr_t addr_limit;
230 size_t xlat_align_size;
232 /* Memory window configured size and limits */
235 ssize_t mw_buf_offset;
236 ssize_t mw_peer_buf_size;
237 ssize_t mw_peer_buf_offset;
239 /* options to handle sysctl out */
254 struct tool_mw *inmws;
256 struct tool_spad *outspads;
257 unsigned int port_no;
262 struct callout link_event_timer;
263 struct callout db_event_timer;
265 struct tool_peer *peers;
267 struct tool_msg *inmsgs;
269 struct tool_spad *inspads;
272 /* sysctl read out variables */
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;
284 /* structure to save dma_addr after dma load */
285 struct ntb_tool_load_cb_args {
291 * NTB events handlers
294 tool_link_event(void *ctx)
296 struct tool_ctx *tc = ctx;
297 enum ntb_speed speed = 0;
298 enum ntb_width width = 0;
301 up = ntb_link_is_up(tc->dev, &speed, &width);
303 tc->link_status = 'Y';
305 tc->link_status = 'N';
307 device_printf(tc->dev, "link is %s speed %d width %d\n",
308 up ? "up" : "down", speed, width);
312 tool_db_event(void *ctx, uint32_t vec)
314 struct tool_ctx *tc = ctx;
315 uint64_t db_bits, db_mask;
317 db_mask = ntb_db_vector_mask(tc->dev, vec);
318 db_bits = ntb_db_read(tc->dev);
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);
324 static const struct ntb_ctx_ops tool_ops = {
325 .link_event = tool_link_event,
326 .db_event = tool_db_event,
330 * Callout event methods
333 tool_link_event_handler(void *arg)
335 struct tool_ctx *tc = (struct tool_ctx *)arg;
338 val = ntb_link_is_up(tc->dev, NULL, NULL) & tc->link_mask;
340 if (val == tc->link_bits) {
341 device_printf(tc->dev, "link_event successful for link val="
342 "0x%jx\n", tc->link_bits);
346 callout_reset(&tc->link_event_timer, 1, tool_link_event_handler, tc);
350 tool_db_event_handler(void *arg)
352 struct tool_ctx *tc = (struct tool_ctx *)arg;
355 db_bits = ntb_db_read(tc->dev);
357 if (db_bits == tc->db_event_val) {
358 device_printf(tc->dev, "db_event successful for db val=0x%jx\n",
360 tc->db_event_val = 0x0;
362 callout_reset(&tc->db_event_timer, 1, tool_db_event_handler, tc);
366 * Common read/write methods
369 get_ubuf(struct sysctl_req *req, char *ubuf)
373 if (req->newlen >= TOOL_BUF_LEN)
376 rc = SYSCTL_IN(req, ubuf, req->newlen);
379 ubuf[req->newlen] = '\0';
385 read_out(struct sysctl_req *req, uint64_t val)
389 memset((void *)ubuf, 0, sizeof(ubuf));
390 snprintf(ubuf, sizeof(ubuf), "0x%jx", val);
392 return SYSCTL_OUT(req, ubuf, sizeof(ubuf));
396 tool_fn_read(struct tool_ctx *tc, struct sysctl_req *req,
397 uint64_t (*fn_read)(device_t ), uint64_t val)
400 return read_out(req, val);
402 return read_out(req, (uint64_t)fn_read(tc->dev));
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))
412 uint64_t db_valid_mask = tc->db_valid_mask;
416 if (fn_set == NULL && fn_clear == NULL) {
417 device_printf(tc->dev, "ERR: Set & Clear both are not supported\n");
421 if (tc->db_valid_mask == 0)
422 db_valid_mask = tc->db_valid_mask = ntb_db_valid_mask(tc->dev);
425 sscanf(ubuf, "%c %jx", &cmd, &bits);
427 if ((bits | db_valid_mask) > db_valid_mask) {
428 device_printf(tc->dev, "0x%jx value is not supported\n", bits);
432 fn_set(tc->dev, 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);
443 fn_clear(tc->dev, bits);
447 device_printf(tc->dev, "Wrong Write\n");
455 parse_mw_buf(char *buf, char *cmd, ssize_t *offset, ssize_t *buf_size,
456 uint64_t *pattern, bool *s_pflag)
458 char op1[8], op2[8], op3[8];
459 uint64_t val1, val2, val3;
463 vs1 = vs2 = vs3 = false;
464 sscanf(buf, "%c %s %jx %s %jx %s %jx",
465 cmd, op1, &val1, op2, &val2, op3, &val3);
467 if (*cmd != 'W' && *cmd != 'R')
470 if (!strcmp(op1, "offset")) {
471 *offset = val1 ? val1 : DEFAULT_MW_OFF;
473 } else if (!strcmp(op1, "nbytes")) {
474 *buf_size = val1 ? val1: DEFAULT_MW_SIZE;
476 } else if (!strcmp(op1, "pattern")) {
481 if (!vs1 && !strcmp(op2, "offset")) {
482 *offset = val2 ? val2 : DEFAULT_MW_OFF;
484 } else if (!vs2 && !strcmp(op2, "nbytes")) {
485 *buf_size = val2 ? val2: DEFAULT_MW_SIZE;
487 } else if (!vs3 && !strcmp(op2, "pattern")) {
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")) {
502 if (vs3 && *cmd == 'R')
503 printf("NTB_TOOL_WARN: pattern is not supported with read "
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)
518 /* The below check is made to ignore sysctl read call. */
522 /* Proceeds only when command R/W is requested using sysctl. */
526 loop = ((buf_size == 0) || (buf_size > DEFAULT_MW_SIZE)) ?
527 DEFAULT_MW_SIZE : buf_size;
529 * 256 bytes of extra buffer has been allocated to print details like
530 * summary, size, notes, i.e., excluding data part.
533 sb = sbuf_new_for_sysctl(NULL, NULL, size, req);
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",
544 sbuf_printf(sb, "R/W size\t\t: %zi\nR/W Offset\t\t: %zi\n\nData\n----"
545 "->", buf_size, buf_off);
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
555 for (i = 0 ; i < loop; i++) {
557 sbuf_printf(sb, "\n%08zx:", index);
561 sbuf_printf(sb, " ");
562 sbuf_printf(sb, "%02hhx", *(tmp+i));
564 if (buf_size > DEFAULT_MW_SIZE)
565 sbuf_printf(sb, "\n\nNOTE: Truncating read size %zi->1024 "
566 "bytes\n", buf_size);
568 /* cmd_op is set to zero after completion of each R/W command. */
570 rc = sbuf_finish(sb);
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)
581 ssize_t data_buf_size;
582 uint64_t pattern = 0;
583 bool s_pflag = false;
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);
596 device_printf(inmw->tc->dev, "Wrong Command \"%c\" provided\n",
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;
620 data_buf_size = *buf_size;
621 data_buf = malloc(data_buf_size, M_NTB_TOOL, M_WAITOK | M_ZERO);
628 memset(data_buf, pattern, data_buf_size);
630 arc4rand(data_buf, data_buf_size, 1);
632 memcpy(write_buf + *buf_offset, data_buf, data_buf_size);
634 free(data_buf, M_NTB_TOOL);
637 /* cmd_op value is set to two as sysctl read call executes twice */
644 * Port sysctl read/write methods
647 sysctl_peer_port_number(SYSCTL_HANDLER_ARGS)
649 struct tool_ctx *tc = (struct tool_ctx *)arg1;
650 int rc, pidx = arg2, peer_port;
652 peer_port = ntb_peer_port_number(tc->dev, pidx);
653 rc = sysctl_handle_int(oidp, &peer_port, 0, req);
655 device_printf(tc->dev, "Peer port sysctl set failed with err="
658 tc->peers[pidx].port_no = peer_port;
664 sysctl_local_port_number(SYSCTL_HANDLER_ARGS)
666 struct tool_ctx *tc = (struct tool_ctx *)arg1;
669 local_port = ntb_port_number(tc->dev);
670 rc = sysctl_handle_int(oidp, &local_port, 0, req);
672 device_printf(tc->dev, "Local port sysctl set failed with err="
675 tc->port_no = local_port;
681 tool_init_peers(struct tool_ctx *tc)
685 tc->peer_cnt = ntb_peer_port_count(tc->dev);
686 tc->peers = malloc(tc->peer_cnt * sizeof(*tc->peers), M_NTB_TOOL,
688 if (tc->peers == NULL)
690 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
691 tc->peers[pidx].pidx = pidx;
692 tc->peers[pidx].tc = tc;
699 tool_clear_peers(struct tool_ctx *tc)
702 free(tc->peers, M_NTB_TOOL);
706 * Link state sysctl read/write methods
709 sysctl_link_handle(SYSCTL_HANDLER_ARGS)
711 struct tool_ctx *tc = (struct tool_ctx *)arg1;
712 char buf[TOOL_BUF_LEN];
715 if (req->newptr == NULL) {
716 snprintf(buf, 2, "%c", tc->link_status);
718 return SYSCTL_OUT(req, buf, 2);
721 rc = get_ubuf(req, buf);
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);
732 sscanf(buf, "%c", &tc->link_status);
738 sysctl_peer_link_handle(SYSCTL_HANDLER_ARGS)
740 struct tool_ctx *tc = (struct tool_ctx *)arg1;
741 int up = 0, pidx = arg2;
742 char buf[TOOL_BUF_LEN];
747 up = ntb_link_is_up(tc->dev, NULL, NULL);
748 memset((void *)buf, 0, TOOL_BUF_LEN);
749 if (up & (1UL << pidx))
754 return SYSCTL_OUT(req, buf, sizeof(buf));
758 sysctl_peer_link_event_handle(SYSCTL_HANDLER_ARGS)
760 struct tool_ctx *tc = (struct tool_ctx *)arg1;
761 char buf[TOOL_BUF_LEN];
765 if (req->newptr == NULL)
766 return read_out(req, tc->link_bits);
768 rc = get_ubuf(req, buf);
772 sscanf(buf, "0x%jx", &bits);
773 tc->link_bits = bits;
774 tc->link_mask = (1ULL << ((pidx) % 64));
776 callout_reset(&tc->link_event_timer, 1, tool_link_event_handler, tc);
781 * Memory windows read/write/setting methods
784 ntb_tool_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
786 struct ntb_tool_load_cb_args *cba = (struct ntb_tool_load_cb_args *)arg;
788 if (!(cba->error = error))
789 cba->addr = segs[0].ds_addr;
793 sysctl_mw_handle(SYSCTL_HANDLER_ARGS)
795 struct tool_mw *inmw = (struct tool_mw *)arg1;
796 char buf[TOOL_BUF_LEN];
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,
804 rc = get_ubuf(req, buf);
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);
813 tool_setup_mw(struct tool_ctx *tc, unsigned int pidx, unsigned int widx,
816 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
817 struct ntb_tool_load_cb_args cba;
821 inmw->size = roundup(inmw->phys_size, inmw->xlat_align_size);
823 inmw->size = roundup(req_size, inmw->xlat_align_size);
825 device_printf(tc->dev, "mw_size %zi req_size %zi buff %zi\n",
826 inmw->phys_size, req_size, inmw->size);
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);
834 goto err_free_dma_var;
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);
842 goto err_free_tag_rem;
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);
852 inmw->dma_base = cba.addr;
854 rc = ntb_mw_set_trans(tc->dev, widx, inmw->dma_base, inmw->size);
861 bus_dmamap_unload(inmw->dma_tag, inmw->dma_map);
864 bus_dmamem_free(inmw->dma_tag, inmw->virt_addr, inmw->dma_map);
867 bus_dma_tag_destroy(inmw->dma_tag);
880 tool_free_mw(struct tool_ctx *tc, int pidx, int widx)
882 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
885 ntb_mw_clear_trans(tc->dev, widx);
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);
902 tool_mw_trans_read(struct tool_mw *inmw, struct sysctl_req *req)
904 ssize_t buf_size = 512;
908 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
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);
925 rc = sbuf_finish(sb);
932 tool_mw_trans_write(struct sysctl_oid *oidp, struct sysctl_req *req,
933 struct tool_mw *inmw, size_t wsize)
935 struct tool_ctx *tc = inmw->tc;
941 /* No need to re-setup mw */
942 if (inmw->size == wsize)
945 /* free mw dma buffer */
947 tool_free_mw(tc, inmw->pidx, inmw->widx);
949 rc = tool_setup_mw(tc, inmw->pidx, inmw->widx, wsize);
955 sysctl_mw_trans_handler(SYSCTL_HANDLER_ARGS)
957 struct tool_mw *inmw = (struct tool_mw *)arg1;
958 char buf[TOOL_BUF_LEN];
962 if (req->newptr == NULL)
963 return tool_mw_trans_read(inmw, req);
965 rc = get_ubuf(req, buf);
967 sscanf(buf, "%zi", &wsize);
968 return tool_mw_trans_write(oidp, req, inmw, wsize);
975 sysctl_peer_mw_handle(SYSCTL_HANDLER_ARGS)
977 struct tool_mw *inmw = (struct tool_mw *)arg1;
978 char buf[TOOL_BUF_LEN];
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");
986 rc = get_ubuf(req, buf);
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);
995 static void tool_clear_mws(struct tool_ctx *tc)
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);
1008 tool_init_mws(struct tool_ctx *tc)
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,
1019 if (tc->peers[pidx].inmws == NULL)
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));
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);
1047 * Doorbell handler for read/write
1050 sysctl_db_handle(SYSCTL_HANDLER_ARGS)
1052 struct tool_ctx *tc = (struct tool_ctx *)arg1;
1053 char buf[TOOL_BUF_LEN];
1057 if (req->newptr == NULL) {
1058 db_bits = ntb_db_read(tc->dev);
1059 return read_out(req, db_bits);
1062 rc = get_ubuf(req, buf);
1064 return tool_fn_write(tc, oidp, req, buf, NULL, false, NULL,
1071 sysctl_db_valid_mask_handle(SYSCTL_HANDLER_ARGS)
1073 struct tool_ctx *tc = (struct tool_ctx *)arg1;
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 "
1081 return read_out(req, tc->db_valid_mask);
1086 sysctl_db_mask_handle(SYSCTL_HANDLER_ARGS)
1088 struct tool_ctx *tc = (struct tool_ctx *)arg1;
1089 char buf[TOOL_BUF_LEN];
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);
1098 rc = get_ubuf(req, buf);
1100 return tool_fn_write(tc, oidp, req, buf, &tc->db_mask_val, true,
1101 ntb_db_set_mask, ntb_db_clear_mask);
1107 sysctl_peer_db_handle(SYSCTL_HANDLER_ARGS)
1109 struct tool_ctx *tc = (struct tool_ctx *)arg1;
1110 char buf[TOOL_BUF_LEN];
1113 if (req->newptr == NULL)
1114 return tool_fn_read(tc, req, NULL, tc->peer_db_val);
1116 rc = get_ubuf(req, buf);
1118 return tool_fn_write(tc, oidp, req, buf, &tc->peer_db_val,
1119 false, ntb_peer_db_set, NULL);
1125 sysctl_peer_db_mask_handle(SYSCTL_HANDLER_ARGS)
1127 struct tool_ctx *tc = (struct tool_ctx *)arg1;
1128 char buf[TOOL_BUF_LEN];
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);
1137 rc = get_ubuf(req, buf);
1139 return tool_fn_write(tc, oidp, req, buf, &tc->peer_db_mask_val,
1146 sysctl_db_event_handle(SYSCTL_HANDLER_ARGS)
1148 struct tool_ctx *tc = (struct tool_ctx *)arg1;
1149 char buf[TOOL_BUF_LEN];
1153 if (req->newptr == NULL)
1154 return read_out(req, tc->db_event_val);
1156 rc = get_ubuf(req, buf);
1160 sscanf(buf, "%ju", &bits);
1161 tc->db_event_val = bits;
1162 callout_reset(&tc->db_event_timer, 1, tool_db_event_handler, tc);
1168 * Scratchpads read/write methods
1171 sysctl_spad_handle(SYSCTL_HANDLER_ARGS)
1173 struct tool_ctx *tc = (struct tool_ctx *)arg1;
1174 unsigned int sidx = arg2;
1175 char buf[TOOL_BUF_LEN];
1179 if (req->newptr == NULL) {
1180 rc = ntb_spad_read(tc->dev, sidx, &bits);
1184 return read_out(req, (uint64_t )bits);
1187 rc = get_ubuf(req, buf);
1189 sscanf(buf, "%i", &bits);
1190 return ntb_spad_write(tc->dev, sidx, bits);
1197 sysctl_peer_spad_handle(SYSCTL_HANDLER_ARGS)
1199 struct tool_ctx *tc = (struct tool_ctx *)arg1;
1200 unsigned int sidx = arg2;
1201 char buf[TOOL_BUF_LEN];
1205 if (req->newptr == NULL) {
1206 rc = ntb_peer_spad_read(tc->dev, sidx, &bits);
1210 return read_out(req, (uint64_t )bits);
1213 rc = get_ubuf(req, buf);
1215 sscanf(buf, "%i", &bits);
1216 return ntb_peer_spad_write(tc->dev, sidx, bits);
1223 tool_init_spads(struct tool_ctx *tc)
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,
1231 if (tc->inspads == NULL)
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;
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 |
1246 if (tc->peers[pidx].outspads == NULL)
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;
1260 tool_clear_spads(struct tool_ctx *tc)
1264 /* Free local inspads. */
1265 free(tc->inspads, M_NTB_TOOL);
1267 /* Free outspads for each peer. */
1268 for (pidx = 0; pidx < tc->peer_cnt; pidx++)
1269 free(tc->peers[pidx].outspads, M_NTB_TOOL);
1273 * Initialization methods
1276 tool_check_ntb(struct tool_ctx *tc)
1279 /* create and initialize link callout handler */
1280 callout_init(&tc->link_event_timer, 1);
1282 /* create and initialize db callout handler */
1283 callout_init(&tc->db_event_timer, 1);
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;
1297 tool_clear_data(struct tool_ctx *tc)
1300 callout_drain(&tc->link_event_timer);
1301 callout_drain(&tc->db_event_timer);
1305 tool_init_ntb(struct tool_ctx *tc)
1308 return ntb_set_ctx(tc->dev, tc, &tool_ops);
1312 tool_clear_ntb(struct tool_ctx *tc)
1315 ntb_clear_ctx(tc->dev);
1316 ntb_link_disable(tc->dev);
1320 * Current sysctl implementation is made such that it gets attached to the
1321 * device and while detach it gets cleared automatically.
1324 tool_setup_sysctl(struct tool_ctx *tc)
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;
1332 clist = device_get_sysctl_ctx(tc->dev);
1333 parent = device_get_sysctl_tree(tc->dev);
1334 top = SYSCTL_CHILDREN(parent);
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");
1340 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "link", CTLTYPE_STRING |
1341 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_link_handle,
1344 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db", CTLTYPE_STRING |
1345 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_db_handle,
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");
1352 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db_mask", CTLTYPE_STRING |
1353 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_db_mask_handle,
1356 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db_event", CTLTYPE_STRING |
1357 CTLFLAG_WR | CTLFLAG_MPSAFE, tc, 0, sysctl_db_event_handle,
1360 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "peer_db", CTLTYPE_STRING |
1361 CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_peer_db_handle,
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");
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);
1373 SYSCTL_ADD_PROC(clist, top, OID_AUTO, buf,
1374 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1375 tc, sidx, sysctl_spad_handle, "IU", desc);
1379 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
1380 snprintf(buf, sizeof(buf), "peer%d", pidx);
1382 peer = SYSCTL_ADD_NODE(clist, top, OID_AUTO, buf,
1383 CTLFLAG_RW | CTLFLAG_MPSAFE, 0, buf);
1384 peer_top = SYSCTL_CHILDREN(peer);
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");
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");
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");
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);
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);
1407 snprintf(buf, sizeof(buf), "mw%d", widx);
1408 snprintf(desc, sizeof(desc), "mw%d info", widx);
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);
1415 snprintf(buf, sizeof(buf), "peer_mw%d", widx);
1416 snprintf(desc, sizeof(desc), "peer_mw%d info", widx);
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);
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);
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);
1436 ntb_tool_probe(device_t dev)
1438 device_set_desc(dev, "NTB TOOL");
1443 ntb_tool_attach(device_t dev)
1445 struct tool_ctx *tc = device_get_softc(dev);
1449 rc = tool_check_ntb(tc);
1453 rc = tool_init_peers(tc);
1455 goto err_clear_data;
1457 rc = tool_init_mws(tc);
1459 goto err_clear_data;
1461 rc = tool_init_spads(tc);
1465 rc = tool_init_ntb(tc);
1467 goto err_clear_spads;
1469 tool_setup_sysctl(tc);
1474 tool_clear_spads(tc);
1477 tool_clear_peers(tc);
1479 tool_clear_data(tc);
1481 device_printf(dev, "ntb_tool attached failed with err=(%d).\n", rc);
1486 ntb_tool_detach(device_t dev)
1488 struct tool_ctx *tc = device_get_softc(dev);
1492 tool_clear_spads(tc);
1496 tool_clear_peers(tc);
1498 tool_clear_data(tc);
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),
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);