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