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