xref: /freebsd/sys/dev/ntb/test/ntb_tool.c (revision fdafd315)
196f556f5SAlexander Motin /*-
296f556f5SAlexander Motin  * This file is provided under a dual BSD/GPLv2 license.  When using or
396f556f5SAlexander Motin  * redistributing this file, you may do so under either license.
496f556f5SAlexander Motin  *
596f556f5SAlexander Motin  * GPL LICENSE SUMMARY
696f556f5SAlexander Motin  *
796f556f5SAlexander Motin  * Copyright (c) 2019 Advanced Micro Devices, Inc. All Rights Reserved.
896f556f5SAlexander Motin  *
996f556f5SAlexander Motin  * This program is free software; you can redistribute it and/or modify
1096f556f5SAlexander Motin  * it under the terms of version 2 of the GNU General Public License as
1196f556f5SAlexander Motin  * published by the Free Software Foundation.
1296f556f5SAlexander Motin  *
1396f556f5SAlexander Motin  * This program is distributed in the hope that it will be useful, but
1496f556f5SAlexander Motin  * WITHOUT ANY WARRANTY; without even the implied warranty of
1596f556f5SAlexander Motin  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1696f556f5SAlexander Motin  * General Public License for more details.
1796f556f5SAlexander Motin  *
1896f556f5SAlexander Motin  * BSD LICENSE
1996f556f5SAlexander Motin  *
2096f556f5SAlexander Motin  * Copyright (c) 2019 Advanced Micro Devices, Inc. All Rights Reserved.
2196f556f5SAlexander Motin  *
2296f556f5SAlexander Motin  * Redistribution and use in source and binary forms, with or without
2396f556f5SAlexander Motin  * modification, are permitted provided that the following conditions
2496f556f5SAlexander Motin  * are met:
2596f556f5SAlexander Motin  *
2696f556f5SAlexander Motin  *   * Redistributions of source code must retain the above copyright
2796f556f5SAlexander Motin  *     notice, this list of conditions and the following disclaimer.
2896f556f5SAlexander Motin  *   * Redistributions in binary form must reproduce the above copy
2996f556f5SAlexander Motin  *     notice, this list of conditions and the following disclaimer in
3096f556f5SAlexander Motin  *     the documentation and/or other materials provided with the
3196f556f5SAlexander Motin  *     distribution.
3296f556f5SAlexander Motin  *   * Neither the name of Advanced Micro Devices, Inc nor the names of its
3396f556f5SAlexander Motin  *     contributors may be used to endorse or promote products derived
3496f556f5SAlexander Motin  *     from this software without specific prior written permission.
3596f556f5SAlexander Motin  *
3696f556f5SAlexander Motin  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3796f556f5SAlexander Motin  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3896f556f5SAlexander Motin  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3996f556f5SAlexander Motin  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4096f556f5SAlexander Motin  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4196f556f5SAlexander Motin  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4296f556f5SAlexander Motin  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4396f556f5SAlexander Motin  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4496f556f5SAlexander Motin  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4596f556f5SAlexander Motin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4696f556f5SAlexander Motin  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4796f556f5SAlexander Motin  *
4896f556f5SAlexander Motin  * PCIe NTB Debugging Tool FreeBSD driver
4996f556f5SAlexander Motin  */
5096f556f5SAlexander Motin 
5196f556f5SAlexander Motin /*
5296f556f5SAlexander Motin  * How to use this tool, by example.
5396f556f5SAlexander Motin  *
5496f556f5SAlexander Motin  * List of sysctl for ntb_tool driver.
5596f556f5SAlexander Motin  * root@local# sysctl -a | grep ntb_tool
5696f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.spad7: 0x0
5796f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.spad6: 0x0
5896f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.spad5: 0x0
5996f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.spad4: 0x0
6096f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.spad3: 0x0
6196f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.spad2: 0x0
6296f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.spad1: 0x0
6396f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.spad0: 0x0
6496f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.mw_trans2:
6596f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.mw_trans1:
6696f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.mw_trans0:
6796f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.peer_mw2:
6896f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.peer_mw1:
6996f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.peer_mw0:
7096f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.mw2:
7196f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.mw1:
7296f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.mw0:
7396f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.link_event: 0x0
7496f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.link: Y
7596f556f5SAlexander Motin  * dev.ntb_tool.0.peer0.port: 1
7696f556f5SAlexander Motin  * dev.ntb_tool.0.spad7: 0x0
7796f556f5SAlexander Motin  * dev.ntb_tool.0.spad6: 0x0
7896f556f5SAlexander Motin  * dev.ntb_tool.0.spad5: 0x0
7996f556f5SAlexander Motin  * dev.ntb_tool.0.spad4: 0x0
8096f556f5SAlexander Motin  * dev.ntb_tool.0.spad3: 0x0
8196f556f5SAlexander Motin  * dev.ntb_tool.0.spad2: 0x0
8296f556f5SAlexander Motin  * dev.ntb_tool.0.spad1: 0x0
8396f556f5SAlexander Motin  * dev.ntb_tool.0.spad0: 0x0
8496f556f5SAlexander Motin  * dev.ntb_tool.0.db: 0x0
8596f556f5SAlexander Motin  * dev.ntb_tool.0.db_event: 0x0
8696f556f5SAlexander Motin  * dev.ntb_tool.0.db_mask: 0xffff
8796f556f5SAlexander Motin  * dev.ntb_tool.0.db_valid_mask: 0xffff
8896f556f5SAlexander Motin  * dev.ntb_tool.0.peer_db: 0x0
8996f556f5SAlexander Motin  * dev.ntb_tool.0.peer_db_mask: 0xffff
9096f556f5SAlexander Motin  * dev.ntb_tool.0.link: Y
9196f556f5SAlexander Motin  * dev.ntb_tool.0.port: 0
9296f556f5SAlexander Motin  *
9396f556f5SAlexander Motin  * The above example list shows
9496f556f5SAlexander Motin  * 1) three memory windows,
9596f556f5SAlexander Motin  * 1) eight scratchpad registers.
9696f556f5SAlexander Motin  * 3) doorbell config.
9796f556f5SAlexander Motin  * 4) link config.
9896f556f5SAlexander Motin  * 2) One peer.
9996f556f5SAlexander Motin  *
10096f556f5SAlexander Motin  * Based on the underlined ntb_hw driver config & connection topology, these
10196f556f5SAlexander Motin  * things might differ.
10296f556f5SAlexander Motin  *-----------------------------------------------------------------------------
10396f556f5SAlexander Motin  * Eg: check local/peer port information.
10496f556f5SAlexander Motin  *
10596f556f5SAlexander Motin  * # Get local device port number
10696f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.port
10796f556f5SAlexander Motin  *
10896f556f5SAlexander Motin  * # Check peer device port number
10996f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer0.port
11096f556f5SAlexander Motin  *-----------------------------------------------------------------------------
11196f556f5SAlexander Motin  * Eg: NTB link tests
11296f556f5SAlexander Motin  *
11396f556f5SAlexander Motin  * # Set local link up/down
11496f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.link=Y
11596f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.link=N
11696f556f5SAlexander Motin  *
11796f556f5SAlexander Motin  * # Check if link with peer device is up/down:
11896f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer0.link
11996f556f5SAlexander Motin  *
12096f556f5SAlexander Motin  * # Poll until the link specified as up/down. For up, value needs to be set
12196f556f5SAlexander Motin  * depends on peer index, i.e., for peer0 it is 0x1 and for down, value needs
12296f556f5SAlexander Motin  * to be set as 0x0.
12396f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer0.link_event=0x1
12496f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer0.link_event=0x0
12596f556f5SAlexander Motin  *-----------------------------------------------------------------------------
12696f556f5SAlexander Motin  * Eg: Doorbell registers tests
12796f556f5SAlexander Motin  *
12896f556f5SAlexander Motin  * # clear/get local doorbell
12996f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.db="c 0x1"
13096f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.db
13196f556f5SAlexander Motin  *
13296f556f5SAlexander Motin  * # Set/clear/get local doorbell mask
13396f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.db_mask="s 0x1"
13496f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.db_mask="c 0x1"
13596f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.db_mask
13696f556f5SAlexander Motin  *
13796f556f5SAlexander Motin  * # Ring/clear/get peer doorbell
13896f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer_db="s 0x1"
13996f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer_db="c 0x1"
14096f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer_db
14196f556f5SAlexander Motin  *
14296f556f5SAlexander Motin  * # Set/clear/get peer doorbell mask (functionality is absent)
14396f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer_db_mask="s 0x1"
14496f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer_db_mask="c 0x1"
14596f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer_db_mask
14696f556f5SAlexander Motin  *
14796f556f5SAlexander Motin  * # Poll until local doorbell is set with the specified db bits
14896f556f5SAlexander Motin  * root@local# dev.ntb_tool.0.db_event=0x1
14996f556f5SAlexander Motin  *-----------------------------------------------------------------------------
15096f556f5SAlexander Motin  * Eg: Scratchpad registers tests
15196f556f5SAlexander Motin  *
15296f556f5SAlexander Motin  * # Write/read to/from local scratchpad register #0
15396f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.spad0=0x1023457
15496f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.spad0
15596f556f5SAlexander Motin  *
15696f556f5SAlexander Motin  * # Write/read to/from peer scratchpad register #0
15796f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer0.spad0=0x01020304
15896f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer0.spad0
15996f556f5SAlexander Motin  *-----------------------------------------------------------------------------
16096f556f5SAlexander Motin  * Eg: Memory windows tests (need to configure local mw_trans on both sides)
16196f556f5SAlexander Motin  *
16296f556f5SAlexander Motin  * # Create inbound memory window buffer of specified size/get its dma address
16396f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer0.mw_trans0=16384
16496f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer0.mw_trans0
16596f556f5SAlexander Motin  *
16696f556f5SAlexander Motin  * # Write/read data to/from inbound memory window with specific pattern/random
16796f556f5SAlexander Motin  * data.
16896f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer0.mw0="W offset 0 nbytes 100 pattern ab"
16996f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer0.mw0="R offset 0 nbytes 100"
17096f556f5SAlexander Motin  *
17196f556f5SAlexander Motin  * # Write/read data to/from outbound memory window on the local device with
17296f556f5SAlexander Motin  * specific pattern/random (on peer device)
17396f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer0.peer_mw0="W offset 0 nbytes 100 pattern ab"
17496f556f5SAlexander Motin  * root@local# sysctl dev.ntb_tool.0.peer0.peer_mw0="R offset 0 nbytes 100"
17596f556f5SAlexander Motin  *-----------------------------------------------------------------------------
17696f556f5SAlexander Motin  * NOTE: *Message registers are not supported*
17796f556f5SAlexander Motin  *-----------------------------------------------------------------------------
17896f556f5SAlexander Motin  *
17996f556f5SAlexander Motin  * contact information:
18096f556f5SAlexander Motin  * Arpan Palit <arpan.palit@amd.com>
18196f556f5SAlexander Motin  *
18296f556f5SAlexander Motin  */
18396f556f5SAlexander Motin 
18496f556f5SAlexander Motin #include <sys/param.h>
18596f556f5SAlexander Motin #include <sys/bus.h>
18696f556f5SAlexander Motin #include <sys/kernel.h>
18796f556f5SAlexander Motin #include <sys/module.h>
18896f556f5SAlexander Motin #include <sys/mbuf.h>
18996f556f5SAlexander Motin #include <sys/sysctl.h>
19096f556f5SAlexander Motin #include <sys/sbuf.h>
19196f556f5SAlexander Motin 
19296f556f5SAlexander Motin #include <machine/bus.h>
19396f556f5SAlexander Motin 
19496f556f5SAlexander Motin #include <vm/vm.h>
19596f556f5SAlexander Motin 
19696f556f5SAlexander Motin #include "../ntb.h"
19796f556f5SAlexander Motin 
19896f556f5SAlexander Motin /* Buffer length for User input */
19996f556f5SAlexander Motin #define	TOOL_BUF_LEN 48
20096f556f5SAlexander Motin /* Memory window default command read and write offset. */
20196f556f5SAlexander Motin #define	DEFAULT_MW_OFF  0
20296f556f5SAlexander Motin /* Memory window default size and also max command read size. */
20396f556f5SAlexander Motin #define	DEFAULT_MW_SIZE 1024
20496f556f5SAlexander Motin 
20596f556f5SAlexander Motin MALLOC_DEFINE(M_NTB_TOOL, "ntb_tool", "ntb_tool driver memory allocation");
20696f556f5SAlexander Motin 
20796f556f5SAlexander Motin /*
20896f556f5SAlexander Motin  * Memory windows descriptor structure
20996f556f5SAlexander Motin  */
21096f556f5SAlexander Motin struct tool_mw {
21196f556f5SAlexander Motin 	struct tool_ctx    *tc;
21296f556f5SAlexander Motin 	int                widx;
21396f556f5SAlexander Motin 	int                pidx;
21496f556f5SAlexander Motin 
21596f556f5SAlexander Motin 	/* Rx buff is off virt_addr / dma_base */
21696f556f5SAlexander Motin 	bus_addr_t         dma_base;
21796f556f5SAlexander Motin 	caddr_t            virt_addr;
21896f556f5SAlexander Motin 	bus_dmamap_t       dma_map;
21996f556f5SAlexander Motin 	bus_dma_tag_t      dma_tag;
22096f556f5SAlexander Motin 
22196f556f5SAlexander Motin 	/* Tx buff is off vbase / phys_addr */
22296f556f5SAlexander Motin 	caddr_t            mm_base;
22396f556f5SAlexander Motin 	vm_paddr_t         phys_addr;
22496f556f5SAlexander Motin 	bus_addr_t         addr_limit;
22596f556f5SAlexander Motin 	size_t             phys_size;
22696f556f5SAlexander Motin 	size_t             xlat_align;
22796f556f5SAlexander Motin 	size_t             xlat_align_size;
22896f556f5SAlexander Motin 
22996f556f5SAlexander Motin 	/* Memory window configured size and limits */
23096f556f5SAlexander Motin 	size_t             size;
23196f556f5SAlexander Motin 	ssize_t            mw_buf_size;
23296f556f5SAlexander Motin 	ssize_t            mw_buf_offset;
23396f556f5SAlexander Motin 	ssize_t            mw_peer_buf_size;
23496f556f5SAlexander Motin 	ssize_t            mw_peer_buf_offset;
23596f556f5SAlexander Motin 
23696f556f5SAlexander Motin 	/* options to handle sysctl out */
23796f556f5SAlexander Motin 	int                mw_cmd_rw;
23896f556f5SAlexander Motin 	int                mw_peer_cmd_rw;
23996f556f5SAlexander Motin };
24096f556f5SAlexander Motin 
24196f556f5SAlexander Motin struct tool_spad {
24296f556f5SAlexander Motin 	int                sidx;
24396f556f5SAlexander Motin 	int                pidx;
24496f556f5SAlexander Motin 	struct tool_ctx    *tc;
24596f556f5SAlexander Motin };
24696f556f5SAlexander Motin 
24796f556f5SAlexander Motin struct tool_peer {
24896f556f5SAlexander Motin 	int                 pidx;
24996f556f5SAlexander Motin 	struct tool_ctx     *tc;
25096f556f5SAlexander Motin 	int                 inmw_cnt;
25196f556f5SAlexander Motin 	struct tool_mw      *inmws;
25296f556f5SAlexander Motin 	int                 outspad_cnt;
25396f556f5SAlexander Motin 	struct tool_spad    *outspads;
25496f556f5SAlexander Motin 	unsigned int        port_no;
25596f556f5SAlexander Motin };
25696f556f5SAlexander Motin 
25796f556f5SAlexander Motin struct tool_ctx {
25896f556f5SAlexander Motin 	device_t            dev;
25996f556f5SAlexander Motin 	struct callout      link_event_timer;
26096f556f5SAlexander Motin 	struct callout      db_event_timer;
26196f556f5SAlexander Motin 	int                 peer_cnt;
26296f556f5SAlexander Motin 	struct tool_peer    *peers;
26396f556f5SAlexander Motin 	int                 inmsg_cnt;
26496f556f5SAlexander Motin 	struct tool_msg     *inmsgs;
26596f556f5SAlexander Motin 	int                 inspad_cnt;
26696f556f5SAlexander Motin 	struct tool_spad    *inspads;
26796f556f5SAlexander Motin 	unsigned int        unsafe;
26896f556f5SAlexander Motin 
26996f556f5SAlexander Motin 	/* sysctl read out variables */
27096f556f5SAlexander Motin 	char                link_status;
27196f556f5SAlexander Motin 	uint64_t            link_bits;
27296f556f5SAlexander Motin 	uint64_t            link_mask;
27396f556f5SAlexander Motin 	uint64_t            db_valid_mask;
27496f556f5SAlexander Motin 	uint64_t            db_mask_val;
27596f556f5SAlexander Motin 	uint64_t            db_event_val;
27696f556f5SAlexander Motin 	uint64_t            peer_db_val;
27796f556f5SAlexander Motin 	uint64_t            peer_db_mask_val;
27896f556f5SAlexander Motin 	unsigned int        port_no;
27996f556f5SAlexander Motin };
28096f556f5SAlexander Motin 
28196f556f5SAlexander Motin /* structure to save dma_addr after dma load */
28296f556f5SAlexander Motin struct ntb_tool_load_cb_args {
28396f556f5SAlexander Motin 	bus_addr_t addr;
28496f556f5SAlexander Motin 	int error;
28596f556f5SAlexander Motin };
28696f556f5SAlexander Motin 
28796f556f5SAlexander Motin /*
28896f556f5SAlexander Motin  * NTB events handlers
28996f556f5SAlexander Motin  */
29096f556f5SAlexander Motin static void
tool_link_event(void * ctx)29196f556f5SAlexander Motin tool_link_event(void *ctx)
29296f556f5SAlexander Motin {
29396f556f5SAlexander Motin 	struct tool_ctx *tc = ctx;
29496f556f5SAlexander Motin 	enum ntb_speed speed = 0;
29596f556f5SAlexander Motin 	enum ntb_width width = 0;
29696f556f5SAlexander Motin 	int up = 0;
29796f556f5SAlexander Motin 
29896f556f5SAlexander Motin 	up = ntb_link_is_up(tc->dev, &speed, &width);
29996f556f5SAlexander Motin 	if (up)
30096f556f5SAlexander Motin 		tc->link_status = 'Y';
30196f556f5SAlexander Motin 	else
30296f556f5SAlexander Motin 		tc->link_status = 'N';
30396f556f5SAlexander Motin 
30496f556f5SAlexander Motin 	device_printf(tc->dev, "link is %s speed %d width %d\n",
30596f556f5SAlexander Motin 	    up ? "up" : "down", speed, width);
30696f556f5SAlexander Motin }
30796f556f5SAlexander Motin 
30896f556f5SAlexander Motin static void
tool_db_event(void * ctx,uint32_t vec)30996f556f5SAlexander Motin tool_db_event(void *ctx, uint32_t vec)
31096f556f5SAlexander Motin {
31196f556f5SAlexander Motin 	struct tool_ctx *tc = ctx;
31296f556f5SAlexander Motin 	uint64_t db_bits, db_mask;
31396f556f5SAlexander Motin 
31496f556f5SAlexander Motin 	db_mask = ntb_db_vector_mask(tc->dev, vec);
31596f556f5SAlexander Motin 	db_bits = ntb_db_read(tc->dev);
31696f556f5SAlexander Motin 
31796f556f5SAlexander Motin 	device_printf(tc->dev, "doorbell vec %d mask %#llx bits %#llx\n",
31896f556f5SAlexander Motin 	    vec, (unsigned long long)db_mask, (unsigned long long)db_bits);
31996f556f5SAlexander Motin }
32096f556f5SAlexander Motin 
32196f556f5SAlexander Motin static const struct ntb_ctx_ops tool_ops = {
32296f556f5SAlexander Motin 	.link_event = tool_link_event,
32396f556f5SAlexander Motin 	.db_event = tool_db_event,
32496f556f5SAlexander Motin };
32596f556f5SAlexander Motin 
32696f556f5SAlexander Motin /*
32796f556f5SAlexander Motin  * Callout event methods
32896f556f5SAlexander Motin  */
32996f556f5SAlexander Motin static void
tool_link_event_handler(void * arg)33096f556f5SAlexander Motin tool_link_event_handler(void *arg)
33196f556f5SAlexander Motin {
33296f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg;
33396f556f5SAlexander Motin 	uint64_t val;
33496f556f5SAlexander Motin 
33596f556f5SAlexander Motin 	val = ntb_link_is_up(tc->dev, NULL, NULL) & tc->link_mask;
33696f556f5SAlexander Motin 
33796f556f5SAlexander Motin 	if (val == tc->link_bits) {
33896f556f5SAlexander Motin 		device_printf(tc->dev, "link_event successful for link val="
33996f556f5SAlexander Motin 		    "0x%jx\n", tc->link_bits);
34096f556f5SAlexander Motin 		tc->link_bits = 0x0;
34196f556f5SAlexander Motin 		tc->link_mask = 0x0;
34296f556f5SAlexander Motin 	} else
34396f556f5SAlexander Motin 		callout_reset(&tc->link_event_timer, 1, tool_link_event_handler, tc);
34496f556f5SAlexander Motin }
34596f556f5SAlexander Motin 
34696f556f5SAlexander Motin static void
tool_db_event_handler(void * arg)34796f556f5SAlexander Motin tool_db_event_handler(void *arg)
34896f556f5SAlexander Motin {
34996f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg;
35096f556f5SAlexander Motin 	uint64_t db_bits;
35196f556f5SAlexander Motin 
35296f556f5SAlexander Motin 	db_bits = ntb_db_read(tc->dev);
35396f556f5SAlexander Motin 
35496f556f5SAlexander Motin 	if (db_bits == tc->db_event_val) {
35596f556f5SAlexander Motin 		device_printf(tc->dev, "db_event successful for db val=0x%jx\n",
35696f556f5SAlexander Motin 		    tc->db_event_val);
35796f556f5SAlexander Motin 		tc->db_event_val = 0x0;
35896f556f5SAlexander Motin 	} else
35996f556f5SAlexander Motin 		callout_reset(&tc->db_event_timer, 1, tool_db_event_handler, tc);
36096f556f5SAlexander Motin }
36196f556f5SAlexander Motin 
36296f556f5SAlexander Motin /*
36396f556f5SAlexander Motin  * Common read/write methods
36496f556f5SAlexander Motin  */
36596f556f5SAlexander Motin static inline int
get_ubuf(struct sysctl_req * req,char * ubuf)36696f556f5SAlexander Motin get_ubuf(struct sysctl_req *req, char *ubuf)
36796f556f5SAlexander Motin {
36896f556f5SAlexander Motin 	int rc;
36996f556f5SAlexander Motin 
37096f556f5SAlexander Motin 	if (req->newlen >= TOOL_BUF_LEN)
37196f556f5SAlexander Motin 		return (EINVAL);
37296f556f5SAlexander Motin 
37396f556f5SAlexander Motin 	rc = SYSCTL_IN(req, ubuf, req->newlen);
37496f556f5SAlexander Motin 	if (rc)
37596f556f5SAlexander Motin 		return (rc);
37696f556f5SAlexander Motin 	ubuf[req->newlen] = '\0';
37796f556f5SAlexander Motin 
37896f556f5SAlexander Motin 	return (0);
37996f556f5SAlexander Motin }
38096f556f5SAlexander Motin 
38196f556f5SAlexander Motin static int
read_out(struct sysctl_req * req,uint64_t val)38296f556f5SAlexander Motin read_out(struct sysctl_req *req, uint64_t val)
38396f556f5SAlexander Motin {
384c59370f0SEric van Gyzen 	char ubuf[19];
38596f556f5SAlexander Motin 
38696f556f5SAlexander Motin 	memset((void *)ubuf, 0, sizeof(ubuf));
38796f556f5SAlexander Motin 	snprintf(ubuf, sizeof(ubuf), "0x%jx", val);
38896f556f5SAlexander Motin 
38996f556f5SAlexander Motin 	return SYSCTL_OUT(req, ubuf, sizeof(ubuf));
39096f556f5SAlexander Motin }
39196f556f5SAlexander Motin 
39296f556f5SAlexander Motin static int
tool_fn_read(struct tool_ctx * tc,struct sysctl_req * req,uint64_t (* fn_read)(device_t),uint64_t val)39396f556f5SAlexander Motin tool_fn_read(struct tool_ctx *tc, struct sysctl_req *req,
39496f556f5SAlexander Motin     uint64_t (*fn_read)(device_t ), uint64_t val)
39596f556f5SAlexander Motin {
39696f556f5SAlexander Motin 	if (fn_read == NULL)
39796f556f5SAlexander Motin 		return read_out(req, val);
39896f556f5SAlexander Motin 	else if (fn_read)
39996f556f5SAlexander Motin 		return read_out(req, (uint64_t)fn_read(tc->dev));
40096f556f5SAlexander Motin 	else
40196f556f5SAlexander Motin 		return (EINVAL);
40296f556f5SAlexander Motin }
40396f556f5SAlexander Motin 
40496f556f5SAlexander Motin 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))40596f556f5SAlexander Motin tool_fn_write(struct tool_ctx *tc, struct sysctl_oid *oidp,
40696f556f5SAlexander Motin     struct sysctl_req *req, char *ubuf, uint64_t *val, bool db_mask_sflag,
40796f556f5SAlexander Motin     void (*fn_set)(device_t , uint64_t), void (*fn_clear)(device_t , uint64_t))
40896f556f5SAlexander Motin {
40996f556f5SAlexander Motin 	uint64_t db_valid_mask = tc->db_valid_mask;
41096f556f5SAlexander Motin 	uint64_t bits;
41196f556f5SAlexander Motin 	char cmd;
41296f556f5SAlexander Motin 
41396f556f5SAlexander Motin 	if (fn_set == NULL && fn_clear == NULL) {
41496f556f5SAlexander Motin 		device_printf(tc->dev, "ERR: Set & Clear both are not supported\n");
41596f556f5SAlexander Motin 		return (EINVAL);
41696f556f5SAlexander Motin 	}
41796f556f5SAlexander Motin 
41896f556f5SAlexander Motin 	if (tc->db_valid_mask == 0)
41996f556f5SAlexander Motin 		db_valid_mask = tc->db_valid_mask = ntb_db_valid_mask(tc->dev);
42096f556f5SAlexander Motin 
42196f556f5SAlexander Motin 	bits = 0;
42296f556f5SAlexander Motin 	sscanf(ubuf, "%c %jx", &cmd, &bits);
42396f556f5SAlexander Motin 	if (cmd == 's') {
42496f556f5SAlexander Motin 		if ((bits | db_valid_mask) > db_valid_mask) {
42596f556f5SAlexander Motin 			device_printf(tc->dev, "0x%jx value is not supported\n", bits);
42696f556f5SAlexander Motin 			return (EINVAL);
42796f556f5SAlexander Motin 		}
42896f556f5SAlexander Motin 		if (fn_set)
42996f556f5SAlexander Motin 			fn_set(tc->dev, bits);
43096f556f5SAlexander Motin 		else
43196f556f5SAlexander Motin 			return (EINVAL);
43296f556f5SAlexander Motin 		if (val)
43396f556f5SAlexander Motin 			*val |= bits;
43496f556f5SAlexander Motin 	} else if (cmd == 'c') {
43596f556f5SAlexander Motin 		if ((bits | db_valid_mask) > db_valid_mask) {
43696f556f5SAlexander Motin 			device_printf(tc->dev, "0x%jx value is not supported\n", bits);
43796f556f5SAlexander Motin 			return (EINVAL);
43896f556f5SAlexander Motin 		}
43996f556f5SAlexander Motin 		if (fn_clear)
44096f556f5SAlexander Motin 			fn_clear(tc->dev, bits);
44196f556f5SAlexander Motin 		if (val)
44296f556f5SAlexander Motin 			*val &= ~bits;
44396f556f5SAlexander Motin 	} else {
44496f556f5SAlexander Motin 		device_printf(tc->dev, "Wrong Write\n");
44596f556f5SAlexander Motin 		return (EINVAL);
44696f556f5SAlexander Motin 	}
44796f556f5SAlexander Motin 
44896f556f5SAlexander Motin 	return (0);
44996f556f5SAlexander Motin }
45096f556f5SAlexander Motin 
45196f556f5SAlexander Motin static int
parse_mw_buf(char * buf,char * cmd,ssize_t * offset,ssize_t * buf_size,uint64_t * pattern,bool * s_pflag)45296f556f5SAlexander Motin parse_mw_buf(char *buf, char *cmd, ssize_t *offset, ssize_t *buf_size,
45396f556f5SAlexander Motin     uint64_t *pattern, bool *s_pflag)
45496f556f5SAlexander Motin {
45596f556f5SAlexander Motin 	char op1[8], op2[8], op3[8];
45696f556f5SAlexander Motin 	uint64_t val1, val2, val3;
45796f556f5SAlexander Motin 	bool vs1, vs2, vs3;
45896f556f5SAlexander Motin 	int rc = 0;
45996f556f5SAlexander Motin 
46096f556f5SAlexander Motin 	vs1 = vs2 = vs3 = false;
46196f556f5SAlexander Motin 	sscanf(buf, "%c %s %jx %s %jx %s %jx",
46296f556f5SAlexander Motin 	    cmd, op1, &val1, op2, &val2, op3, &val3);
46396f556f5SAlexander Motin 
46496f556f5SAlexander Motin 	if (*cmd != 'W' && *cmd != 'R')
46596f556f5SAlexander Motin 		return (EINVAL);
46696f556f5SAlexander Motin 
46796f556f5SAlexander Motin 	if (!strcmp(op1, "offset")) {
46896f556f5SAlexander Motin 		*offset = val1 ? val1 : DEFAULT_MW_OFF;
46996f556f5SAlexander Motin 		vs1 = true;
47096f556f5SAlexander Motin 	} else if (!strcmp(op1, "nbytes")) {
47196f556f5SAlexander Motin 		*buf_size = val1 ? val1: DEFAULT_MW_SIZE;
47296f556f5SAlexander Motin 		vs2 = true;
47396f556f5SAlexander Motin 	} else if (!strcmp(op1, "pattern")) {
47496f556f5SAlexander Motin 		*pattern = val1;
47596f556f5SAlexander Motin 		vs3 = true;
47696f556f5SAlexander Motin 	}
47796f556f5SAlexander Motin 
47896f556f5SAlexander Motin 	if (!vs1 && !strcmp(op2, "offset")) {
47996f556f5SAlexander Motin 		*offset = val2 ? val2 : DEFAULT_MW_OFF;
48096f556f5SAlexander Motin 		vs1 = true;
48196f556f5SAlexander Motin 	} else if (!vs2 && !strcmp(op2, "nbytes")) {
48296f556f5SAlexander Motin 		*buf_size = val2 ? val2: DEFAULT_MW_SIZE;
48396f556f5SAlexander Motin 		vs2 = true;
48496f556f5SAlexander Motin 	} else if (!vs3 && !strcmp(op2, "pattern")) {
48596f556f5SAlexander Motin 		*pattern = val2;
48696f556f5SAlexander Motin 		vs3 = true;
48796f556f5SAlexander Motin 	}
48896f556f5SAlexander Motin 
48996f556f5SAlexander Motin 	if (!vs1 && !strcmp(op3, "offset")) {
49096f556f5SAlexander Motin 		*offset = val3 ? val3 : DEFAULT_MW_OFF;
49196f556f5SAlexander Motin 	} else if (!vs2 && !strcmp(op3, "nbytes")) {
49296f556f5SAlexander Motin 		*buf_size = val3 ? val3: DEFAULT_MW_SIZE;
49396f556f5SAlexander Motin 	} else if (!vs3 && !strcmp(op3, "pattern")) {
49496f556f5SAlexander Motin 		*pattern = val3;
49596f556f5SAlexander Motin 		vs3 = true;
49696f556f5SAlexander Motin 	}
49796f556f5SAlexander Motin 
49896f556f5SAlexander Motin 	*s_pflag = vs3;
49996f556f5SAlexander Motin 	if (vs3 && *cmd == 'R')
50096f556f5SAlexander Motin 		printf("NTB_TOOL_WARN: pattern is not supported with read "
50196f556f5SAlexander Motin 		    "command\n");
50296f556f5SAlexander Motin 
50396f556f5SAlexander Motin 	return (rc);
50496f556f5SAlexander Motin }
50596f556f5SAlexander Motin 
50696f556f5SAlexander Motin 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)50796f556f5SAlexander Motin tool_mw_read_fn(struct sysctl_req *req, struct tool_mw *inmw, char *read_addr,
50896f556f5SAlexander Motin     int *cmd_op, ssize_t buf_off, ssize_t buf_size, char *type)
50996f556f5SAlexander Motin {
51096f556f5SAlexander Motin 	ssize_t index, size;
51196f556f5SAlexander Motin 	struct sbuf *sb;
51296f556f5SAlexander Motin 	int i, loop, rc;
51396f556f5SAlexander Motin 	char *tmp;
51496f556f5SAlexander Motin 
51596f556f5SAlexander Motin 	/* The below check is made to ignore sysctl read call. */
51696f556f5SAlexander Motin 	if (*cmd_op == 0)
51796f556f5SAlexander Motin 		return (0);
51896f556f5SAlexander Motin 
51996f556f5SAlexander Motin 	/* Proceeds only when command R/W is requested using sysctl. */
52096f556f5SAlexander Motin 	index = buf_off;
52196f556f5SAlexander Motin 	tmp = read_addr;
52296f556f5SAlexander Motin 	tmp += index;
52396f556f5SAlexander Motin 	loop = ((buf_size == 0) || (buf_size > DEFAULT_MW_SIZE)) ?
52496f556f5SAlexander Motin 	    DEFAULT_MW_SIZE : buf_size;
52596f556f5SAlexander Motin 	/*
52696f556f5SAlexander Motin 	 * 256 bytes of extra buffer has been allocated to print details like
52796f556f5SAlexander Motin 	 * summary, size, notes, i.e., excluding data part.
52896f556f5SAlexander Motin 	 */
52996f556f5SAlexander Motin 	size = loop + 256;
53096f556f5SAlexander Motin 	sb = sbuf_new_for_sysctl(NULL, NULL, size, req);
53196f556f5SAlexander Motin 	if (sb == NULL) {
53296f556f5SAlexander Motin 		rc = sb->s_error;
53396f556f5SAlexander Motin 		return (rc);
53496f556f5SAlexander Motin 	}
53596f556f5SAlexander Motin 
53696f556f5SAlexander Motin 	if (!strcmp(type, "mw"))
53796f556f5SAlexander Motin 		sbuf_printf(sb, "\nConfigured MW size\t: %zu\n", inmw->size);
53896f556f5SAlexander Motin 	else if (!strcmp(type, "peer_mw"))
53996f556f5SAlexander Motin 		sbuf_printf(sb, "\nConfigured Peer MW size\t: %zu\n",
54096f556f5SAlexander Motin 		    inmw->size);
54196f556f5SAlexander Motin 	sbuf_printf(sb, "R/W size\t\t: %zi\nR/W Offset\t\t: %zi\n\nData\n----"
54296f556f5SAlexander Motin 	    "->", buf_size, buf_off);
54396f556f5SAlexander Motin 
54496f556f5SAlexander Motin 	/*
54596f556f5SAlexander Motin 	 * Data will be read based on MW size provided by the user using nbytes,
54696f556f5SAlexander Motin 	 * which is limited to 1024 bytes if user req bigger size to read, check
54796f556f5SAlexander Motin 	 * above loop calculation which is limiting or setting the MW read size.
54896f556f5SAlexander Motin 	 * Below for loop prints data where in each line contains 32 bytes data
54996f556f5SAlexander Motin 	 * and after each 8 bytes of data we used four spaces which ensures one
55096f556f5SAlexander Motin 	 * data block.
55196f556f5SAlexander Motin 	 */
55296f556f5SAlexander Motin 	for (i = 0 ; i < loop; i++) {
55396f556f5SAlexander Motin 		if ((i % 32) == 0) {
55496f556f5SAlexander Motin 			sbuf_printf(sb, "\n%08zx:", index);
55596f556f5SAlexander Motin 			index += 32;
55696f556f5SAlexander Motin 		}
55796f556f5SAlexander Motin 		if ((i % 8) == 0)
55896f556f5SAlexander Motin 			sbuf_printf(sb, "    ");
55996f556f5SAlexander Motin 		sbuf_printf(sb, "%02hhx", *(tmp+i));
56096f556f5SAlexander Motin 	}
56196f556f5SAlexander Motin 	if (buf_size > DEFAULT_MW_SIZE)
56296f556f5SAlexander Motin 		sbuf_printf(sb, "\n\nNOTE: Truncating read size %zi->1024 "
56396f556f5SAlexander Motin 		    "bytes\n", buf_size);
56496f556f5SAlexander Motin 
56596f556f5SAlexander Motin 	/* cmd_op is set to zero after completion of each R/W command. */
56696f556f5SAlexander Motin 	*cmd_op -= 1;
56796f556f5SAlexander Motin 	rc = sbuf_finish(sb);
56896f556f5SAlexander Motin 	sbuf_delete(sb);
56996f556f5SAlexander Motin 
57096f556f5SAlexander Motin 	return (rc);
57196f556f5SAlexander Motin }
57296f556f5SAlexander Motin 
57396f556f5SAlexander Motin 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)57496f556f5SAlexander Motin tool_mw_write_fn(struct sysctl_oid *oidp, struct sysctl_req *req,
57596f556f5SAlexander Motin     struct tool_mw *inmw, char *ubuf, caddr_t write_buf, int *cmd_op,
57696f556f5SAlexander Motin     ssize_t *buf_offset, ssize_t *buf_size)
57796f556f5SAlexander Motin {
57896f556f5SAlexander Motin 	ssize_t data_buf_size;
57996f556f5SAlexander Motin 	uint64_t pattern = 0;
58096f556f5SAlexander Motin 	bool s_pflag = false;
58196f556f5SAlexander Motin 	void *data_buf;
58296f556f5SAlexander Motin 	char cmd;
58396f556f5SAlexander Motin 	int rc;
58496f556f5SAlexander Motin 
58596f556f5SAlexander Motin 	if (!write_buf)
58696f556f5SAlexander Motin 		return (ENXIO);
58796f556f5SAlexander Motin 
58896f556f5SAlexander Motin 	/* buf_offset and buf_size set to default in case user does not req */
58996f556f5SAlexander Motin 	*buf_offset = DEFAULT_MW_OFF;
59096f556f5SAlexander Motin 	*buf_size = DEFAULT_MW_SIZE;
59196f556f5SAlexander Motin 	rc = parse_mw_buf(ubuf, &cmd, buf_offset, buf_size, &pattern, &s_pflag);
59296f556f5SAlexander Motin 	if (rc) {
59396f556f5SAlexander Motin 		device_printf(inmw->tc->dev, "Wrong Command \"%c\" provided\n",
59496f556f5SAlexander Motin 		    cmd);
59596f556f5SAlexander Motin 		return (rc);
59696f556f5SAlexander Motin 	}
59796f556f5SAlexander Motin 
59896f556f5SAlexander Motin 	/* Check for req size and buffer limit */
59996f556f5SAlexander Motin 	if ((*buf_offset + *buf_size) > inmw->size) {
60096f556f5SAlexander Motin 		device_printf(inmw->tc->dev, "%s: configured mw size :%zi and "
60196f556f5SAlexander Motin 		    "requested size :%zi.\n", __func__, inmw->size,
60296f556f5SAlexander Motin 		    (*buf_offset + *buf_size));
60396f556f5SAlexander Motin 		*buf_offset = DEFAULT_MW_OFF;
60496f556f5SAlexander Motin 		*buf_size = DEFAULT_MW_SIZE;
60596f556f5SAlexander Motin 		rc = EINVAL;
60696f556f5SAlexander Motin 		goto out;
60796f556f5SAlexander Motin 	}
60896f556f5SAlexander Motin 
60996f556f5SAlexander Motin 	if (cmd == 'R')
61096f556f5SAlexander Motin 		goto read_out;
61196f556f5SAlexander Motin 	else if (cmd == 'W')
61296f556f5SAlexander Motin 		goto write;
61396f556f5SAlexander Motin 	else
61496f556f5SAlexander Motin 		goto out;
61596f556f5SAlexander Motin 
61696f556f5SAlexander Motin write:
61796f556f5SAlexander Motin 	data_buf_size = *buf_size;
61896f556f5SAlexander Motin 	data_buf = malloc(data_buf_size, M_NTB_TOOL, M_WAITOK | M_ZERO);
61996f556f5SAlexander Motin 
62096f556f5SAlexander Motin 	if (s_pflag)
62196f556f5SAlexander Motin 		memset(data_buf, pattern, data_buf_size);
62296f556f5SAlexander Motin 	else
62396f556f5SAlexander Motin 		arc4rand(data_buf, data_buf_size, 1);
62496f556f5SAlexander Motin 
62596f556f5SAlexander Motin 	memcpy(write_buf + *buf_offset, data_buf, data_buf_size);
62696f556f5SAlexander Motin 
62796f556f5SAlexander Motin 	free(data_buf, M_NTB_TOOL);
62896f556f5SAlexander Motin 
62996f556f5SAlexander Motin read_out:
63096f556f5SAlexander Motin 	/* cmd_op value is set to two as sysctl read call executes twice */
63196f556f5SAlexander Motin 	*cmd_op = 2;
63296f556f5SAlexander Motin out:
63396f556f5SAlexander Motin 	return (rc);
63496f556f5SAlexander Motin }
63596f556f5SAlexander Motin 
63696f556f5SAlexander Motin /*
63796f556f5SAlexander Motin  * Port sysctl read/write methods
63896f556f5SAlexander Motin  */
63996f556f5SAlexander Motin static int
sysctl_peer_port_number(SYSCTL_HANDLER_ARGS)64096f556f5SAlexander Motin sysctl_peer_port_number(SYSCTL_HANDLER_ARGS)
64196f556f5SAlexander Motin {
64296f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
64396f556f5SAlexander Motin 	int rc, pidx = arg2, peer_port;
64496f556f5SAlexander Motin 
64596f556f5SAlexander Motin 	peer_port = ntb_peer_port_number(tc->dev, pidx);
64696f556f5SAlexander Motin 	rc = sysctl_handle_int(oidp, &peer_port, 0, req);
64796f556f5SAlexander Motin 	if (rc)
64896f556f5SAlexander Motin 		device_printf(tc->dev, "Peer port sysctl set failed with err="
64996f556f5SAlexander Motin 		    "(%d).\n", rc);
65096f556f5SAlexander Motin 	else
65196f556f5SAlexander Motin 		tc->peers[pidx].port_no = peer_port;
65296f556f5SAlexander Motin 
65396f556f5SAlexander Motin 	return (rc);
65496f556f5SAlexander Motin }
65596f556f5SAlexander Motin 
65696f556f5SAlexander Motin static int
sysctl_local_port_number(SYSCTL_HANDLER_ARGS)65796f556f5SAlexander Motin sysctl_local_port_number(SYSCTL_HANDLER_ARGS)
65896f556f5SAlexander Motin {
65996f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
66096f556f5SAlexander Motin 	int rc, local_port;
66196f556f5SAlexander Motin 
66296f556f5SAlexander Motin 	local_port = ntb_port_number(tc->dev);
66396f556f5SAlexander Motin 	rc = sysctl_handle_int(oidp, &local_port, 0, req);
66496f556f5SAlexander Motin 	if (rc)
66596f556f5SAlexander Motin 		device_printf(tc->dev, "Local port sysctl set failed with err="
66696f556f5SAlexander Motin 		    "(%d).\n", rc);
66796f556f5SAlexander Motin 	else
66896f556f5SAlexander Motin 		tc->port_no = local_port;
66996f556f5SAlexander Motin 
67096f556f5SAlexander Motin 	return (rc);
67196f556f5SAlexander Motin }
67296f556f5SAlexander Motin 
673dace3812SMark Johnston static void
tool_init_peers(struct tool_ctx * tc)67496f556f5SAlexander Motin tool_init_peers(struct tool_ctx *tc)
67596f556f5SAlexander Motin {
67696f556f5SAlexander Motin 	int pidx;
67796f556f5SAlexander Motin 
67896f556f5SAlexander Motin 	tc->peer_cnt = ntb_peer_port_count(tc->dev);
67996f556f5SAlexander Motin 	tc->peers = malloc(tc->peer_cnt * sizeof(*tc->peers), M_NTB_TOOL,
68096f556f5SAlexander Motin 	    M_WAITOK | M_ZERO);
68196f556f5SAlexander Motin 	for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
68296f556f5SAlexander Motin 		tc->peers[pidx].pidx = pidx;
68396f556f5SAlexander Motin 		tc->peers[pidx].tc = tc;
68496f556f5SAlexander Motin 	}
68596f556f5SAlexander Motin }
68696f556f5SAlexander Motin 
68796f556f5SAlexander Motin static void
tool_clear_peers(struct tool_ctx * tc)68896f556f5SAlexander Motin tool_clear_peers(struct tool_ctx *tc)
68996f556f5SAlexander Motin {
69096f556f5SAlexander Motin 
69196f556f5SAlexander Motin 	free(tc->peers, M_NTB_TOOL);
69296f556f5SAlexander Motin }
69396f556f5SAlexander Motin 
69496f556f5SAlexander Motin /*
69596f556f5SAlexander Motin  * Link state sysctl read/write methods
69696f556f5SAlexander Motin  */
69796f556f5SAlexander Motin static int
sysctl_link_handle(SYSCTL_HANDLER_ARGS)69896f556f5SAlexander Motin sysctl_link_handle(SYSCTL_HANDLER_ARGS)
69996f556f5SAlexander Motin {
70096f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
70196f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
70296f556f5SAlexander Motin 	int rc;
70396f556f5SAlexander Motin 
70496f556f5SAlexander Motin 	if (req->newptr == NULL) {
70596f556f5SAlexander Motin 		snprintf(buf, 2, "%c", tc->link_status);
70696f556f5SAlexander Motin 
70796f556f5SAlexander Motin 		return SYSCTL_OUT(req, buf, 2);
70896f556f5SAlexander Motin 	}
70996f556f5SAlexander Motin 
71096f556f5SAlexander Motin 	rc = get_ubuf(req, buf);
71196f556f5SAlexander Motin 	if (rc)
71296f556f5SAlexander Motin 		return (rc);
71396f556f5SAlexander Motin 
71496f556f5SAlexander Motin 	if (buf[0] == 'Y')
71596f556f5SAlexander Motin 		rc = ntb_link_enable(tc->dev, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
71696f556f5SAlexander Motin 	else if (buf[0] == 'N')
71796f556f5SAlexander Motin 		rc = ntb_link_disable(tc->dev);
71896f556f5SAlexander Motin 	else
71996f556f5SAlexander Motin 		rc = EINVAL;
72096f556f5SAlexander Motin 
72196f556f5SAlexander Motin 	sscanf(buf, "%c", &tc->link_status);
72296f556f5SAlexander Motin 
72396f556f5SAlexander Motin 	return (0);
72496f556f5SAlexander Motin }
72596f556f5SAlexander Motin 
72696f556f5SAlexander Motin static int
sysctl_peer_link_handle(SYSCTL_HANDLER_ARGS)72796f556f5SAlexander Motin sysctl_peer_link_handle(SYSCTL_HANDLER_ARGS)
72896f556f5SAlexander Motin {
72996f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
73096f556f5SAlexander Motin 	int up = 0, pidx = arg2;
73196f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
73296f556f5SAlexander Motin 
73396f556f5SAlexander Motin 	if (req->newptr)
73496f556f5SAlexander Motin 		return (0);
73596f556f5SAlexander Motin 
73696f556f5SAlexander Motin 	up = ntb_link_is_up(tc->dev, NULL, NULL);
73796f556f5SAlexander Motin 	memset((void *)buf, 0, TOOL_BUF_LEN);
73896f556f5SAlexander Motin 	if (up & (1UL << pidx))
73996f556f5SAlexander Motin 		buf[0] = 'Y';
74096f556f5SAlexander Motin 	else
74196f556f5SAlexander Motin 		buf[0] = 'N';
74296f556f5SAlexander Motin 
74396f556f5SAlexander Motin 	return SYSCTL_OUT(req, buf, sizeof(buf));
74496f556f5SAlexander Motin }
74596f556f5SAlexander Motin 
74696f556f5SAlexander Motin static int
sysctl_peer_link_event_handle(SYSCTL_HANDLER_ARGS)74796f556f5SAlexander Motin sysctl_peer_link_event_handle(SYSCTL_HANDLER_ARGS)
74896f556f5SAlexander Motin {
74996f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
75096f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
75196f556f5SAlexander Motin 	int rc, pidx = arg2;
75296f556f5SAlexander Motin 	uint64_t bits;
75396f556f5SAlexander Motin 
75496f556f5SAlexander Motin 	if (req->newptr == NULL)
75596f556f5SAlexander Motin 		return read_out(req, tc->link_bits);
75696f556f5SAlexander Motin 
75796f556f5SAlexander Motin 	rc = get_ubuf(req, buf);
75896f556f5SAlexander Motin 	if (rc)
75996f556f5SAlexander Motin 		return (rc);
76096f556f5SAlexander Motin 
76196f556f5SAlexander Motin 	sscanf(buf, "0x%jx", &bits);
76296f556f5SAlexander Motin 	tc->link_bits = bits;
76396f556f5SAlexander Motin 	tc->link_mask = (1ULL << ((pidx) % 64));
76496f556f5SAlexander Motin 
76596f556f5SAlexander Motin 	callout_reset(&tc->link_event_timer, 1, tool_link_event_handler, tc);
76696f556f5SAlexander Motin 	return (0);
76796f556f5SAlexander Motin }
76896f556f5SAlexander Motin 
76996f556f5SAlexander Motin /*
77096f556f5SAlexander Motin  * Memory windows read/write/setting methods
77196f556f5SAlexander Motin  */
77296f556f5SAlexander Motin static void
ntb_tool_load_cb(void * arg,bus_dma_segment_t * segs,int nsegs,int error)77396f556f5SAlexander Motin ntb_tool_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
77496f556f5SAlexander Motin {
77596f556f5SAlexander Motin 	struct ntb_tool_load_cb_args *cba = (struct ntb_tool_load_cb_args *)arg;
77696f556f5SAlexander Motin 
77796f556f5SAlexander Motin 	if (!(cba->error = error))
77896f556f5SAlexander Motin 		cba->addr = segs[0].ds_addr;
77996f556f5SAlexander Motin }
78096f556f5SAlexander Motin 
78196f556f5SAlexander Motin static int
sysctl_mw_handle(SYSCTL_HANDLER_ARGS)78296f556f5SAlexander Motin sysctl_mw_handle(SYSCTL_HANDLER_ARGS)
78396f556f5SAlexander Motin {
78496f556f5SAlexander Motin 	struct tool_mw *inmw = (struct tool_mw *)arg1;
78596f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
78696f556f5SAlexander Motin 	int rc;
78796f556f5SAlexander Motin 
78896f556f5SAlexander Motin 	if (req->newptr == NULL)
78996f556f5SAlexander Motin 		return tool_mw_read_fn(req, inmw, (char *)inmw->mm_base,
79096f556f5SAlexander Motin 		    &inmw->mw_cmd_rw, inmw->mw_buf_offset, inmw->mw_buf_size,
79196f556f5SAlexander Motin 		    "mw");
79296f556f5SAlexander Motin 
79396f556f5SAlexander Motin 	rc = get_ubuf(req, buf);
79496f556f5SAlexander Motin 	if (!rc)
79596f556f5SAlexander Motin 		return tool_mw_write_fn(oidp, req, inmw, buf, inmw->mm_base,
79696f556f5SAlexander Motin 		    &inmw->mw_cmd_rw, &inmw->mw_buf_offset, &inmw->mw_buf_size);
79796f556f5SAlexander Motin 
79896f556f5SAlexander Motin 	return (rc);
79996f556f5SAlexander Motin }
80096f556f5SAlexander Motin 
80196f556f5SAlexander Motin static int
tool_setup_mw(struct tool_ctx * tc,unsigned int pidx,unsigned int widx,size_t req_size)80296f556f5SAlexander Motin tool_setup_mw(struct tool_ctx *tc, unsigned int pidx, unsigned int widx,
80396f556f5SAlexander Motin     size_t req_size)
80496f556f5SAlexander Motin {
80596f556f5SAlexander Motin 	struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
80696f556f5SAlexander Motin 	struct ntb_tool_load_cb_args cba;
80796f556f5SAlexander Motin 	int rc;
80896f556f5SAlexander Motin 
80996f556f5SAlexander Motin 	if (req_size == 0)
81096f556f5SAlexander Motin 		inmw->size = roundup(inmw->phys_size, inmw->xlat_align_size);
81196f556f5SAlexander Motin 	else
81296f556f5SAlexander Motin 		inmw->size = roundup(req_size, inmw->xlat_align_size);
81396f556f5SAlexander Motin 
81496f556f5SAlexander Motin 	device_printf(tc->dev, "mw_size %zi req_size %zi buff %zi\n",
81596f556f5SAlexander Motin 	    inmw->phys_size, req_size, inmw->size);
81696f556f5SAlexander Motin 
81796f556f5SAlexander Motin 	if (bus_dma_tag_create(bus_get_dma_tag(tc->dev), inmw->xlat_align, 0,
81896f556f5SAlexander Motin 	    inmw->addr_limit, BUS_SPACE_MAXADDR, NULL, NULL, inmw->size, 1,
81996f556f5SAlexander Motin 	    inmw->size, 0, NULL, NULL, &inmw->dma_tag)) {
82096f556f5SAlexander Motin 		device_printf(tc->dev, "Unable to create MW tag of size "
82196f556f5SAlexander Motin 		    "%zu/%zu\n", inmw->phys_size, inmw->size);
82296f556f5SAlexander Motin 		rc = ENOMEM;
82396f556f5SAlexander Motin 		goto err_free_dma_var;
82496f556f5SAlexander Motin 	}
82596f556f5SAlexander Motin 
82696f556f5SAlexander Motin 	if (bus_dmamem_alloc(inmw->dma_tag, (void **)&inmw->virt_addr,
82796f556f5SAlexander Motin 	    BUS_DMA_WAITOK | BUS_DMA_ZERO, &inmw->dma_map)) {
82896f556f5SAlexander Motin 		device_printf(tc->dev, "Unable to allocate MW buffer of size "
82996f556f5SAlexander Motin 		    "%zu/%zu\n", inmw->phys_size, inmw->size);
83096f556f5SAlexander Motin 		rc = ENOMEM;
83196f556f5SAlexander Motin 		goto err_free_tag_rem;
83296f556f5SAlexander Motin 	}
83396f556f5SAlexander Motin 
83496f556f5SAlexander Motin 	if (bus_dmamap_load(inmw->dma_tag, inmw->dma_map, inmw->virt_addr,
83596f556f5SAlexander Motin 	    inmw->size, ntb_tool_load_cb, &cba, BUS_DMA_NOWAIT) || cba.error) {
83696f556f5SAlexander Motin 		device_printf(tc->dev, "Unable to load MW buffer of size "
83796f556f5SAlexander Motin 		    "%zu/%zu\n", inmw->phys_size, inmw->size);
83896f556f5SAlexander Motin 		rc = ENOMEM;
83996f556f5SAlexander Motin 		goto err_free_dma;
84096f556f5SAlexander Motin 	}
84196f556f5SAlexander Motin 	inmw->dma_base = cba.addr;
84296f556f5SAlexander Motin 
84396f556f5SAlexander Motin 	rc = ntb_mw_set_trans(tc->dev, widx, inmw->dma_base, inmw->size);
84496f556f5SAlexander Motin 	if (rc)
84596f556f5SAlexander Motin 		goto err_free_mw;
84696f556f5SAlexander Motin 
84796f556f5SAlexander Motin 	return (0);
84896f556f5SAlexander Motin 
84996f556f5SAlexander Motin err_free_mw:
85096f556f5SAlexander Motin 	bus_dmamap_unload(inmw->dma_tag, inmw->dma_map);
85196f556f5SAlexander Motin 
85296f556f5SAlexander Motin err_free_dma:
85396f556f5SAlexander Motin 	bus_dmamem_free(inmw->dma_tag, inmw->virt_addr, inmw->dma_map);
85496f556f5SAlexander Motin 
85596f556f5SAlexander Motin err_free_tag_rem:
85696f556f5SAlexander Motin 	bus_dma_tag_destroy(inmw->dma_tag);
85796f556f5SAlexander Motin 
85896f556f5SAlexander Motin err_free_dma_var:
85996f556f5SAlexander Motin 	inmw->size = 0;
86096f556f5SAlexander Motin 	inmw->virt_addr = 0;
86196f556f5SAlexander Motin 	inmw->dma_base = 0;
86296f556f5SAlexander Motin 	inmw->dma_tag = 0;
86396f556f5SAlexander Motin 	inmw->dma_map = 0;
86496f556f5SAlexander Motin 
86596f556f5SAlexander Motin 	return (rc);
86696f556f5SAlexander Motin }
86796f556f5SAlexander Motin 
86896f556f5SAlexander Motin static void
tool_free_mw(struct tool_ctx * tc,int pidx,int widx)86996f556f5SAlexander Motin tool_free_mw(struct tool_ctx *tc, int pidx, int widx)
87096f556f5SAlexander Motin {
87196f556f5SAlexander Motin 	struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
87296f556f5SAlexander Motin 
87396f556f5SAlexander Motin 	if (inmw->dma_base)
87496f556f5SAlexander Motin 		ntb_mw_clear_trans(tc->dev, widx);
87596f556f5SAlexander Motin 
87696f556f5SAlexander Motin 	if (inmw->virt_addr && inmw->dma_tag) {
87796f556f5SAlexander Motin 		bus_dmamap_unload(inmw->dma_tag, inmw->dma_map);
87896f556f5SAlexander Motin 		bus_dmamem_free(inmw->dma_tag, inmw->virt_addr, inmw->dma_map);
87996f556f5SAlexander Motin 		bus_dma_tag_destroy(inmw->dma_tag);
88096f556f5SAlexander Motin 	}
88196f556f5SAlexander Motin 
88296f556f5SAlexander Motin 	inmw->virt_addr = 0;
88396f556f5SAlexander Motin 	inmw->dma_base = 0;
88496f556f5SAlexander Motin 	inmw->dma_tag = 0;
88596f556f5SAlexander Motin 	inmw->dma_map = 0;
88696f556f5SAlexander Motin 	inmw->mm_base = 0;
88796f556f5SAlexander Motin 	inmw->size = 0;
88896f556f5SAlexander Motin }
88996f556f5SAlexander Motin 
89096f556f5SAlexander Motin static int
tool_mw_trans_read(struct tool_mw * inmw,struct sysctl_req * req)89196f556f5SAlexander Motin tool_mw_trans_read(struct tool_mw *inmw, struct sysctl_req *req)
89296f556f5SAlexander Motin {
89396f556f5SAlexander Motin 	ssize_t buf_size = 512;
89496f556f5SAlexander Motin 	struct sbuf *sb;
89596f556f5SAlexander Motin 	int rc = 0;
89696f556f5SAlexander Motin 
89796f556f5SAlexander Motin 	sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
89896f556f5SAlexander Motin 	if (sb == NULL) {
89996f556f5SAlexander Motin 		rc = sb->s_error;
90096f556f5SAlexander Motin 		return (rc);
90196f556f5SAlexander Motin 	}
90296f556f5SAlexander Motin 
90396f556f5SAlexander Motin 	sbuf_printf(sb, "\nInbound MW     \t%d\n", inmw->widx);
90496f556f5SAlexander Motin 	sbuf_printf(sb, "Port           \t%d (%d)\n",
90596f556f5SAlexander Motin 	    ntb_peer_port_number(inmw->tc->dev, inmw->pidx), inmw->pidx);
90696f556f5SAlexander Motin 	sbuf_printf(sb, "Window Address \t%p\n", inmw->mm_base);
90796f556f5SAlexander Motin 	sbuf_printf(sb, "DMA Address    \t0x%016llx\n", (long long)inmw->dma_base);
90896f556f5SAlexander Motin 	sbuf_printf(sb, "Window Size    \t0x%016zx[p]\n", inmw->size);
90996f556f5SAlexander Motin 	sbuf_printf(sb, "Alignment      \t0x%016zx[p]\n", inmw->xlat_align);
91096f556f5SAlexander Motin 	sbuf_printf(sb, "Size Alignment \t0x%016zx[p]\n",
91196f556f5SAlexander Motin 	    inmw->xlat_align_size);
91296f556f5SAlexander Motin 	sbuf_printf(sb, "Size Max       \t0x%016zx[p]\n", inmw->phys_size);
91396f556f5SAlexander Motin 
91496f556f5SAlexander Motin 	rc = sbuf_finish(sb);
91596f556f5SAlexander Motin 	sbuf_delete(sb);
91696f556f5SAlexander Motin 
91796f556f5SAlexander Motin 	return (rc);
91896f556f5SAlexander Motin }
91996f556f5SAlexander Motin 
92096f556f5SAlexander Motin static int
tool_mw_trans_write(struct sysctl_oid * oidp,struct sysctl_req * req,struct tool_mw * inmw,size_t wsize)92196f556f5SAlexander Motin tool_mw_trans_write(struct sysctl_oid *oidp, struct sysctl_req *req,
92296f556f5SAlexander Motin     struct tool_mw *inmw, size_t wsize)
92396f556f5SAlexander Motin {
92496f556f5SAlexander Motin 	struct tool_ctx *tc = inmw->tc;
92596f556f5SAlexander Motin 	int rc = 0;
92696f556f5SAlexander Motin 
92796f556f5SAlexander Motin 	if (wsize == 0)
92896f556f5SAlexander Motin 		return (EINVAL);
92996f556f5SAlexander Motin 
93096f556f5SAlexander Motin 	/* No need to re-setup mw */
93196f556f5SAlexander Motin 	if (inmw->size == wsize)
93296f556f5SAlexander Motin 		return (0);
93396f556f5SAlexander Motin 
93496f556f5SAlexander Motin 	/* free mw dma buffer */
93596f556f5SAlexander Motin 	if (inmw->size)
93696f556f5SAlexander Motin 		tool_free_mw(tc, inmw->pidx, inmw->widx);
93796f556f5SAlexander Motin 
93896f556f5SAlexander Motin 	rc = tool_setup_mw(tc, inmw->pidx, inmw->widx, wsize);
93996f556f5SAlexander Motin 
94096f556f5SAlexander Motin 	return (rc);
94196f556f5SAlexander Motin }
94296f556f5SAlexander Motin 
94396f556f5SAlexander Motin static int
sysctl_mw_trans_handler(SYSCTL_HANDLER_ARGS)94496f556f5SAlexander Motin sysctl_mw_trans_handler(SYSCTL_HANDLER_ARGS)
94596f556f5SAlexander Motin {
94696f556f5SAlexander Motin 	struct tool_mw *inmw = (struct tool_mw *)arg1;
94796f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
94896f556f5SAlexander Motin 	ssize_t wsize;
94996f556f5SAlexander Motin 	int rc;
95096f556f5SAlexander Motin 
95196f556f5SAlexander Motin 	if (req->newptr == NULL)
95296f556f5SAlexander Motin 		return tool_mw_trans_read(inmw, req);
95396f556f5SAlexander Motin 
95496f556f5SAlexander Motin 	rc = get_ubuf(req, buf);
95596f556f5SAlexander Motin 	if (rc == 0) {
95696f556f5SAlexander Motin 		sscanf(buf, "%zi", &wsize);
95796f556f5SAlexander Motin 		return tool_mw_trans_write(oidp, req, inmw, wsize);
95896f556f5SAlexander Motin 	}
95996f556f5SAlexander Motin 
96096f556f5SAlexander Motin 	return (rc);
96196f556f5SAlexander Motin }
96296f556f5SAlexander Motin 
96396f556f5SAlexander Motin static int
sysctl_peer_mw_handle(SYSCTL_HANDLER_ARGS)96496f556f5SAlexander Motin sysctl_peer_mw_handle(SYSCTL_HANDLER_ARGS)
96596f556f5SAlexander Motin {
96696f556f5SAlexander Motin 	struct tool_mw *inmw = (struct tool_mw *)arg1;
96796f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
96896f556f5SAlexander Motin 	int rc;
96996f556f5SAlexander Motin 
97096f556f5SAlexander Motin 	if (req->newptr == NULL)
97196f556f5SAlexander Motin 		return tool_mw_read_fn(req, inmw, (char *)inmw->virt_addr,
97296f556f5SAlexander Motin 		    &inmw->mw_peer_cmd_rw, inmw->mw_peer_buf_offset,
97396f556f5SAlexander Motin 		    inmw->mw_peer_buf_size, "mw");
97496f556f5SAlexander Motin 
97596f556f5SAlexander Motin 	rc = get_ubuf(req, buf);
97696f556f5SAlexander Motin 	if (rc == 0)
97796f556f5SAlexander Motin 		return tool_mw_write_fn(oidp, req, inmw, buf, inmw->virt_addr,
97896f556f5SAlexander Motin 		    &inmw->mw_peer_cmd_rw, &inmw->mw_peer_buf_offset,
97996f556f5SAlexander Motin 		    &inmw->mw_peer_buf_size);
98096f556f5SAlexander Motin 
98196f556f5SAlexander Motin 	return (rc);
98296f556f5SAlexander Motin }
98396f556f5SAlexander Motin 
tool_clear_mws(struct tool_ctx * tc)98496f556f5SAlexander Motin static void tool_clear_mws(struct tool_ctx *tc)
98596f556f5SAlexander Motin {
98696f556f5SAlexander Motin 	int widx, pidx;
98796f556f5SAlexander Motin 
98896f556f5SAlexander Motin 	/* Free outbound memory windows */
98996f556f5SAlexander Motin 	for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
99096f556f5SAlexander Motin 		for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++)
99196f556f5SAlexander Motin 			tool_free_mw(tc, pidx, widx);
99296f556f5SAlexander Motin 		free(tc->peers[pidx].inmws, M_NTB_TOOL);
99396f556f5SAlexander Motin 	}
99496f556f5SAlexander Motin }
99596f556f5SAlexander Motin 
99696f556f5SAlexander Motin static int
tool_init_mws(struct tool_ctx * tc)99796f556f5SAlexander Motin tool_init_mws(struct tool_ctx *tc)
99896f556f5SAlexander Motin {
99996f556f5SAlexander Motin 	struct tool_mw *mw;
100096f556f5SAlexander Motin 	int widx, pidx, rc;
100196f556f5SAlexander Motin 
100296f556f5SAlexander Motin 	/* Initialize inbound memory windows and outbound MWs wrapper */
100396f556f5SAlexander Motin 	for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
100496f556f5SAlexander Motin 		tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->dev);
100596f556f5SAlexander Motin 		tc->peers[pidx].inmws = malloc(tc->peers[pidx].inmw_cnt *
100696f556f5SAlexander Motin 		    sizeof(*tc->peers[pidx].inmws), M_NTB_TOOL,
100796f556f5SAlexander Motin 		    M_WAITOK | M_ZERO);
100896f556f5SAlexander Motin 
100996f556f5SAlexander Motin 		for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) {
101096f556f5SAlexander Motin 			mw = &tc->peers[pidx].inmws[widx];
101196f556f5SAlexander Motin 			memset((void *)mw, 0, sizeof(*mw));
101296f556f5SAlexander Motin 			mw->tc = tc;
101396f556f5SAlexander Motin 			mw->widx = widx;
101496f556f5SAlexander Motin 			mw->pidx = pidx;
101596f556f5SAlexander Motin 			mw->mw_buf_offset = DEFAULT_MW_OFF;
101696f556f5SAlexander Motin 			mw->mw_buf_size = DEFAULT_MW_SIZE;
101796f556f5SAlexander Motin 			/* get the tx buff details for each mw attached with each peer */
101896f556f5SAlexander Motin 			rc = ntb_mw_get_range(tc->dev, widx, &mw->phys_addr,
101996f556f5SAlexander Motin 			    &mw->mm_base, &mw->phys_size, &mw->xlat_align,
102096f556f5SAlexander Motin 			    &mw->xlat_align_size, &mw->addr_limit);
102196f556f5SAlexander Motin 			if (rc)
102296f556f5SAlexander Motin 				goto free_mws;
102396f556f5SAlexander Motin 		}
102496f556f5SAlexander Motin 	}
102596f556f5SAlexander Motin 
102696f556f5SAlexander Motin 	return (0);
102796f556f5SAlexander Motin 
102896f556f5SAlexander Motin free_mws:
102996f556f5SAlexander Motin 	tool_clear_mws(tc);
103096f556f5SAlexander Motin 	return (rc);
103196f556f5SAlexander Motin }
103296f556f5SAlexander Motin 
103396f556f5SAlexander Motin /*
103496f556f5SAlexander Motin  * Doorbell handler for read/write
103596f556f5SAlexander Motin  */
103696f556f5SAlexander Motin static int
sysctl_db_handle(SYSCTL_HANDLER_ARGS)103796f556f5SAlexander Motin sysctl_db_handle(SYSCTL_HANDLER_ARGS)
103896f556f5SAlexander Motin {
103996f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
104096f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
104196f556f5SAlexander Motin 	uint64_t db_bits;
104296f556f5SAlexander Motin 	int rc;
104396f556f5SAlexander Motin 
104496f556f5SAlexander Motin 	if (req->newptr == NULL) {
104596f556f5SAlexander Motin 		db_bits = ntb_db_read(tc->dev);
104696f556f5SAlexander Motin 		return read_out(req, db_bits);
104796f556f5SAlexander Motin 	}
104896f556f5SAlexander Motin 
104996f556f5SAlexander Motin 	rc = get_ubuf(req, buf);
105096f556f5SAlexander Motin 	if (rc == 0)
105196f556f5SAlexander Motin 		return tool_fn_write(tc, oidp, req, buf, NULL, false, NULL,
105296f556f5SAlexander Motin 		    ntb_db_clear);
105396f556f5SAlexander Motin 
105496f556f5SAlexander Motin 	return (rc);
105596f556f5SAlexander Motin }
105696f556f5SAlexander Motin 
105796f556f5SAlexander Motin static int
sysctl_db_valid_mask_handle(SYSCTL_HANDLER_ARGS)105896f556f5SAlexander Motin sysctl_db_valid_mask_handle(SYSCTL_HANDLER_ARGS)
105996f556f5SAlexander Motin {
106096f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
106196f556f5SAlexander Motin 
106296f556f5SAlexander Motin 	tc->db_valid_mask = ntb_db_valid_mask(tc->dev);
106396f556f5SAlexander Motin 	if (!tc->db_valid_mask) {
106496f556f5SAlexander Motin 		device_printf(tc->dev, "Error getting db_valid_mask from "
106596f556f5SAlexander Motin 		    "hw driver\n");
106696f556f5SAlexander Motin 		return (EINVAL);
106796f556f5SAlexander Motin 	} else {
106896f556f5SAlexander Motin 		return read_out(req, tc->db_valid_mask);
106996f556f5SAlexander Motin 	}
107096f556f5SAlexander Motin }
107196f556f5SAlexander Motin 
107296f556f5SAlexander Motin static int
sysctl_db_mask_handle(SYSCTL_HANDLER_ARGS)107396f556f5SAlexander Motin sysctl_db_mask_handle(SYSCTL_HANDLER_ARGS)
107496f556f5SAlexander Motin {
107596f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
107696f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
107796f556f5SAlexander Motin 	int rc;
107896f556f5SAlexander Motin 
107996f556f5SAlexander Motin 	if (req->newptr == NULL) {
108096f556f5SAlexander Motin 		if (tc->db_mask_val == 0)
108196f556f5SAlexander Motin 		     ntb_db_valid_mask(tc->dev);
108296f556f5SAlexander Motin 		return tool_fn_read(tc, req, NULL, tc->db_mask_val);
108396f556f5SAlexander Motin 	}
108496f556f5SAlexander Motin 
108596f556f5SAlexander Motin 	rc = get_ubuf(req, buf);
108696f556f5SAlexander Motin 	if (rc == 0)
108796f556f5SAlexander Motin 		return tool_fn_write(tc, oidp, req, buf, &tc->db_mask_val, true,
108896f556f5SAlexander Motin 		    ntb_db_set_mask, ntb_db_clear_mask);
108996f556f5SAlexander Motin 
109096f556f5SAlexander Motin 	return (rc);
109196f556f5SAlexander Motin }
109296f556f5SAlexander Motin 
109396f556f5SAlexander Motin static int
sysctl_peer_db_handle(SYSCTL_HANDLER_ARGS)109496f556f5SAlexander Motin sysctl_peer_db_handle(SYSCTL_HANDLER_ARGS)
109596f556f5SAlexander Motin {
109696f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
109796f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
109896f556f5SAlexander Motin 	int rc;
109996f556f5SAlexander Motin 
110096f556f5SAlexander Motin 	if (req->newptr == NULL)
110196f556f5SAlexander Motin 		return tool_fn_read(tc, req, NULL, tc->peer_db_val);
110296f556f5SAlexander Motin 
110396f556f5SAlexander Motin 	rc = get_ubuf(req, buf);
110496f556f5SAlexander Motin 	if (rc == 0)
110596f556f5SAlexander Motin 		return tool_fn_write(tc, oidp, req, buf, &tc->peer_db_val,
110696f556f5SAlexander Motin 		    false, ntb_peer_db_set, NULL);
110796f556f5SAlexander Motin 
110896f556f5SAlexander Motin 	return (rc);
110996f556f5SAlexander Motin }
111096f556f5SAlexander Motin 
111196f556f5SAlexander Motin static int
sysctl_peer_db_mask_handle(SYSCTL_HANDLER_ARGS)111296f556f5SAlexander Motin sysctl_peer_db_mask_handle(SYSCTL_HANDLER_ARGS)
111396f556f5SAlexander Motin {
111496f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
111596f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
111696f556f5SAlexander Motin 	int rc;
111796f556f5SAlexander Motin 
111896f556f5SAlexander Motin 	if (req->newptr == NULL){
111996f556f5SAlexander Motin 		if (tc->peer_db_mask_val == 0)
112096f556f5SAlexander Motin 			ntb_db_valid_mask(tc->dev);
112196f556f5SAlexander Motin 		return tool_fn_read(tc, req, NULL, tc->peer_db_mask_val);
112296f556f5SAlexander Motin 	}
112396f556f5SAlexander Motin 
112496f556f5SAlexander Motin 	rc = get_ubuf(req, buf);
112596f556f5SAlexander Motin 	if (rc == 0)
112696f556f5SAlexander Motin 		return tool_fn_write(tc, oidp, req, buf, &tc->peer_db_mask_val,
112796f556f5SAlexander Motin 		    true, NULL, NULL);
112896f556f5SAlexander Motin 
112996f556f5SAlexander Motin 	return (rc);
113096f556f5SAlexander Motin }
113196f556f5SAlexander Motin 
113296f556f5SAlexander Motin static int
sysctl_db_event_handle(SYSCTL_HANDLER_ARGS)113396f556f5SAlexander Motin sysctl_db_event_handle(SYSCTL_HANDLER_ARGS)
113496f556f5SAlexander Motin {
113596f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
113696f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
113796f556f5SAlexander Motin 	uint64_t bits;
113896f556f5SAlexander Motin 	int rc;
113996f556f5SAlexander Motin 
114096f556f5SAlexander Motin 	if (req->newptr == NULL)
114196f556f5SAlexander Motin 		return read_out(req, tc->db_event_val);
114296f556f5SAlexander Motin 
114396f556f5SAlexander Motin 	rc = get_ubuf(req, buf);
114496f556f5SAlexander Motin 	if (rc)
114596f556f5SAlexander Motin 		return (rc);
114696f556f5SAlexander Motin 
114796f556f5SAlexander Motin 	sscanf(buf, "%ju", &bits);
114896f556f5SAlexander Motin 	tc->db_event_val = bits;
114996f556f5SAlexander Motin 	callout_reset(&tc->db_event_timer, 1, tool_db_event_handler, tc);
115096f556f5SAlexander Motin 
115196f556f5SAlexander Motin 	return (0);
115296f556f5SAlexander Motin }
115396f556f5SAlexander Motin 
115496f556f5SAlexander Motin /*
115596f556f5SAlexander Motin  * Scratchpads read/write methods
115696f556f5SAlexander Motin  */
115796f556f5SAlexander Motin static int
sysctl_spad_handle(SYSCTL_HANDLER_ARGS)115896f556f5SAlexander Motin sysctl_spad_handle(SYSCTL_HANDLER_ARGS)
115996f556f5SAlexander Motin {
116096f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
116196f556f5SAlexander Motin 	unsigned int sidx = arg2;
116296f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
116396f556f5SAlexander Motin 	uint32_t bits;
116496f556f5SAlexander Motin 	int rc;
116596f556f5SAlexander Motin 
116696f556f5SAlexander Motin 	if (req->newptr == NULL) {
116796f556f5SAlexander Motin 		rc = ntb_spad_read(tc->dev, sidx, &bits);
116896f556f5SAlexander Motin 		if (rc)
116996f556f5SAlexander Motin 			return (rc);
117096f556f5SAlexander Motin 		else
117196f556f5SAlexander Motin 			return read_out(req, (uint64_t )bits);
117296f556f5SAlexander Motin 	}
117396f556f5SAlexander Motin 
117496f556f5SAlexander Motin 	rc = get_ubuf(req, buf);
117596f556f5SAlexander Motin 	if (rc == 0) {
117696f556f5SAlexander Motin 		sscanf(buf, "%i", &bits);
117796f556f5SAlexander Motin 		return ntb_spad_write(tc->dev, sidx, bits);
117896f556f5SAlexander Motin 	}
117996f556f5SAlexander Motin 
118096f556f5SAlexander Motin 	return (rc);
118196f556f5SAlexander Motin }
118296f556f5SAlexander Motin 
118396f556f5SAlexander Motin static int
sysctl_peer_spad_handle(SYSCTL_HANDLER_ARGS)118496f556f5SAlexander Motin sysctl_peer_spad_handle(SYSCTL_HANDLER_ARGS)
118596f556f5SAlexander Motin {
118696f556f5SAlexander Motin 	struct tool_ctx *tc = (struct tool_ctx *)arg1;
118796f556f5SAlexander Motin 	unsigned int sidx = arg2;
118896f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN];
118996f556f5SAlexander Motin 	uint32_t bits;
119096f556f5SAlexander Motin 	int rc;
119196f556f5SAlexander Motin 
119296f556f5SAlexander Motin 	if (req->newptr == NULL) {
119396f556f5SAlexander Motin 		rc = ntb_peer_spad_read(tc->dev, sidx, &bits);
119496f556f5SAlexander Motin 		if (rc)
119596f556f5SAlexander Motin 			return (rc);
119696f556f5SAlexander Motin 		else
119796f556f5SAlexander Motin 			return read_out(req, (uint64_t )bits);
119896f556f5SAlexander Motin 	}
119996f556f5SAlexander Motin 
120096f556f5SAlexander Motin 	rc = get_ubuf(req, buf);
120196f556f5SAlexander Motin 	if (rc == 0) {
120296f556f5SAlexander Motin 		sscanf(buf, "%i", &bits);
120396f556f5SAlexander Motin 		return ntb_peer_spad_write(tc->dev, sidx, bits);
120496f556f5SAlexander Motin 	}
120596f556f5SAlexander Motin 
120696f556f5SAlexander Motin 	return (rc);
120796f556f5SAlexander Motin }
120896f556f5SAlexander Motin 
1209dace3812SMark Johnston static void
tool_init_spads(struct tool_ctx * tc)121096f556f5SAlexander Motin tool_init_spads(struct tool_ctx *tc)
121196f556f5SAlexander Motin {
121296f556f5SAlexander Motin 	int sidx, pidx;
121396f556f5SAlexander Motin 
121496f556f5SAlexander Motin 	/* Initialize inbound scratchpad structures */
121596f556f5SAlexander Motin 	tc->inspad_cnt = ntb_spad_count(tc->dev);
121696f556f5SAlexander Motin 	tc->inspads = malloc(tc->inspad_cnt * sizeof(*tc->inspads), M_NTB_TOOL,
121796f556f5SAlexander Motin 	    M_WAITOK | M_ZERO);
121896f556f5SAlexander Motin 
121996f556f5SAlexander Motin 	for (sidx = 0; sidx < tc->inspad_cnt; sidx++) {
122096f556f5SAlexander Motin 		tc->inspads[sidx].sidx = sidx;
122196f556f5SAlexander Motin 		tc->inspads[sidx].pidx = -1;
122296f556f5SAlexander Motin 		tc->inspads[sidx].tc = tc;
122396f556f5SAlexander Motin 	}
122496f556f5SAlexander Motin 
122596f556f5SAlexander Motin 	/* Initialize outbound scratchpad structures */
122696f556f5SAlexander Motin 	for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
122796f556f5SAlexander Motin 		tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->dev);
122896f556f5SAlexander Motin 		tc->peers[pidx].outspads =  malloc(tc->peers[pidx].outspad_cnt *
122996f556f5SAlexander Motin 		    sizeof(*tc->peers[pidx].outspads), M_NTB_TOOL, M_WAITOK |
123096f556f5SAlexander Motin 		    M_ZERO);
123196f556f5SAlexander Motin 
123296f556f5SAlexander Motin 		for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) {
123396f556f5SAlexander Motin 			tc->peers[pidx].outspads[sidx].sidx = sidx;
123496f556f5SAlexander Motin 			tc->peers[pidx].outspads[sidx].pidx = pidx;
123596f556f5SAlexander Motin 			tc->peers[pidx].outspads[sidx].tc = tc;
123696f556f5SAlexander Motin 		}
123796f556f5SAlexander Motin 	}
123896f556f5SAlexander Motin }
123996f556f5SAlexander Motin 
124096f556f5SAlexander Motin static void
tool_clear_spads(struct tool_ctx * tc)124196f556f5SAlexander Motin tool_clear_spads(struct tool_ctx *tc)
124296f556f5SAlexander Motin {
124396f556f5SAlexander Motin 	int pidx;
124496f556f5SAlexander Motin 
124596f556f5SAlexander Motin 	/* Free local inspads. */
124696f556f5SAlexander Motin 	free(tc->inspads, M_NTB_TOOL);
124796f556f5SAlexander Motin 
124896f556f5SAlexander Motin 	/* Free outspads for each peer. */
124996f556f5SAlexander Motin 	for (pidx = 0; pidx < tc->peer_cnt; pidx++)
125096f556f5SAlexander Motin 		free(tc->peers[pidx].outspads, M_NTB_TOOL);
125196f556f5SAlexander Motin }
125296f556f5SAlexander Motin 
125396f556f5SAlexander Motin /*
125496f556f5SAlexander Motin  * Initialization methods
125596f556f5SAlexander Motin  */
125696f556f5SAlexander Motin static int
tool_check_ntb(struct tool_ctx * tc)125796f556f5SAlexander Motin tool_check_ntb(struct tool_ctx *tc)
125896f556f5SAlexander Motin {
125996f556f5SAlexander Motin 
126096f556f5SAlexander Motin 	/* create and initialize link callout handler */
126196f556f5SAlexander Motin 	callout_init(&tc->link_event_timer, 1);
126296f556f5SAlexander Motin 
126396f556f5SAlexander Motin 	/* create and initialize db callout handler */
126496f556f5SAlexander Motin 	callout_init(&tc->db_event_timer, 1);
126596f556f5SAlexander Motin 
126696f556f5SAlexander Motin 	/* Initialize sysctl read out values to default */
126796f556f5SAlexander Motin 	tc->link_status = 'U';
126896f556f5SAlexander Motin 	tc->db_mask_val = 0;
126996f556f5SAlexander Motin 	tc->peer_db_val = 0;
127096f556f5SAlexander Motin 	tc->peer_db_mask_val = 0;
127196f556f5SAlexander Motin 	tc->db_event_val = 0;
127296f556f5SAlexander Motin 	tc->link_bits = 0;
127396f556f5SAlexander Motin 
127496f556f5SAlexander Motin 	return (0);
127596f556f5SAlexander Motin }
127696f556f5SAlexander Motin 
127796f556f5SAlexander Motin static void
tool_clear_data(struct tool_ctx * tc)127896f556f5SAlexander Motin tool_clear_data(struct tool_ctx *tc)
127996f556f5SAlexander Motin {
128096f556f5SAlexander Motin 
128196f556f5SAlexander Motin 	callout_drain(&tc->link_event_timer);
128296f556f5SAlexander Motin 	callout_drain(&tc->db_event_timer);
128396f556f5SAlexander Motin }
128496f556f5SAlexander Motin 
128596f556f5SAlexander Motin static int
tool_init_ntb(struct tool_ctx * tc)128696f556f5SAlexander Motin tool_init_ntb(struct tool_ctx *tc)
128796f556f5SAlexander Motin {
128896f556f5SAlexander Motin 
128996f556f5SAlexander Motin 	return ntb_set_ctx(tc->dev, tc, &tool_ops);
129096f556f5SAlexander Motin }
129196f556f5SAlexander Motin 
129296f556f5SAlexander Motin static void
tool_clear_ntb(struct tool_ctx * tc)129396f556f5SAlexander Motin tool_clear_ntb(struct tool_ctx *tc)
129496f556f5SAlexander Motin {
129596f556f5SAlexander Motin 
129696f556f5SAlexander Motin 	ntb_clear_ctx(tc->dev);
129796f556f5SAlexander Motin 	ntb_link_disable(tc->dev);
129896f556f5SAlexander Motin }
129996f556f5SAlexander Motin 
130096f556f5SAlexander Motin /*
130196f556f5SAlexander Motin  *  Current sysctl implementation is made such that it gets attached to the
130296f556f5SAlexander Motin  *  device and while detach it gets cleared automatically.
130396f556f5SAlexander Motin  */
130496f556f5SAlexander Motin static void
tool_setup_sysctl(struct tool_ctx * tc)130596f556f5SAlexander Motin tool_setup_sysctl(struct tool_ctx *tc)
130696f556f5SAlexander Motin {
130796f556f5SAlexander Motin 	char buf[TOOL_BUF_LEN], desc[TOOL_BUF_LEN];
130896f556f5SAlexander Motin 	struct sysctl_oid_list *top, *peer_top;
130996f556f5SAlexander Motin 	struct sysctl_oid *parent, *peer;
131096f556f5SAlexander Motin 	struct sysctl_ctx_list *clist;
131196f556f5SAlexander Motin 	unsigned int pidx, sidx, widx;
131296f556f5SAlexander Motin 
131396f556f5SAlexander Motin 	clist = device_get_sysctl_ctx(tc->dev);
131496f556f5SAlexander Motin 	parent = device_get_sysctl_tree(tc->dev);
131596f556f5SAlexander Motin 	top = SYSCTL_CHILDREN(parent);
131696f556f5SAlexander Motin 
131796f556f5SAlexander Motin 	SYSCTL_ADD_PROC(clist, top, OID_AUTO, "port", CTLTYPE_UINT |
131896f556f5SAlexander Motin 	    CTLFLAG_RDTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_local_port_number,
131996f556f5SAlexander Motin 	    "IU", "local port number");
132096f556f5SAlexander Motin 
132196f556f5SAlexander Motin 	SYSCTL_ADD_PROC(clist, top, OID_AUTO, "link", CTLTYPE_STRING |
132296f556f5SAlexander Motin 	    CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_link_handle,
132396f556f5SAlexander Motin 	    "IU", "link info");
132496f556f5SAlexander Motin 
132596f556f5SAlexander Motin 	SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db", CTLTYPE_STRING |
132696f556f5SAlexander Motin 	    CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_db_handle,
132796f556f5SAlexander Motin 	    "A", "db info");
132896f556f5SAlexander Motin 
132996f556f5SAlexander Motin 	SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db_valid_mask", CTLTYPE_STRING |
133096f556f5SAlexander Motin 	    CTLFLAG_RD | CTLFLAG_MPSAFE, tc, 0, sysctl_db_valid_mask_handle,
133196f556f5SAlexander Motin 	    "A", "db valid mask");
133296f556f5SAlexander Motin 
133396f556f5SAlexander Motin 	SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db_mask", CTLTYPE_STRING |
133496f556f5SAlexander Motin 	    CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_db_mask_handle,
133596f556f5SAlexander Motin 	    "A", "db mask");
133696f556f5SAlexander Motin 
133796f556f5SAlexander Motin 	SYSCTL_ADD_PROC(clist, top, OID_AUTO, "db_event", CTLTYPE_STRING |
133896f556f5SAlexander Motin 	    CTLFLAG_WR | CTLFLAG_MPSAFE, tc, 0, sysctl_db_event_handle,
133996f556f5SAlexander Motin 	    "A", "db event");
134096f556f5SAlexander Motin 
134196f556f5SAlexander Motin 	SYSCTL_ADD_PROC(clist, top, OID_AUTO, "peer_db", CTLTYPE_STRING |
134296f556f5SAlexander Motin 	    CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_peer_db_handle,
134396f556f5SAlexander Motin 	    "A", "peer db");
134496f556f5SAlexander Motin 
134596f556f5SAlexander Motin 	SYSCTL_ADD_PROC(clist, top, OID_AUTO, "peer_db_mask", CTLTYPE_STRING |
134696f556f5SAlexander Motin 	    CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, 0, sysctl_peer_db_mask_handle,
134796f556f5SAlexander Motin 	    "IU", "peer db mask info");
134896f556f5SAlexander Motin 
134996f556f5SAlexander Motin 	if (tc->inspad_cnt != 0) {
135096f556f5SAlexander Motin 		for (sidx = 0; sidx < tc->inspad_cnt; sidx++) {
135196f556f5SAlexander Motin 			snprintf(buf, sizeof(buf), "spad%d", sidx);
135296f556f5SAlexander Motin 			snprintf(desc, sizeof(desc), "spad%d info", sidx);
135396f556f5SAlexander Motin 
135496f556f5SAlexander Motin 			SYSCTL_ADD_PROC(clist, top, OID_AUTO, buf,
135596f556f5SAlexander Motin 			    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
135696f556f5SAlexander Motin 			    tc, sidx, sysctl_spad_handle, "IU", desc);
135796f556f5SAlexander Motin 		}
135896f556f5SAlexander Motin 	}
135996f556f5SAlexander Motin 
136096f556f5SAlexander Motin 	for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
136196f556f5SAlexander Motin 		snprintf(buf, sizeof(buf), "peer%d", pidx);
136296f556f5SAlexander Motin 
13637029da5cSPawel Biernacki 		peer = SYSCTL_ADD_NODE(clist, top, OID_AUTO, buf,
13647029da5cSPawel Biernacki 		    CTLFLAG_RW | CTLFLAG_MPSAFE, 0, buf);
136596f556f5SAlexander Motin 		peer_top = SYSCTL_CHILDREN(peer);
136696f556f5SAlexander Motin 
136796f556f5SAlexander Motin 		SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, "port",
136896f556f5SAlexander Motin 		    CTLTYPE_UINT | CTLFLAG_RDTUN | CTLFLAG_MPSAFE, tc, pidx,
136996f556f5SAlexander Motin 		    sysctl_peer_port_number, "IU", "peer port number");
137096f556f5SAlexander Motin 
137196f556f5SAlexander Motin 		SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, "link",
137296f556f5SAlexander Motin 		    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, pidx,
137396f556f5SAlexander Motin 		    sysctl_peer_link_handle, "IU", "peer_link info");
137496f556f5SAlexander Motin 
137596f556f5SAlexander Motin 		SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, "link_event",
137696f556f5SAlexander Motin 		    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, tc, pidx,
137796f556f5SAlexander Motin 		    sysctl_peer_link_event_handle, "IU", "link event");
137896f556f5SAlexander Motin 
137996f556f5SAlexander Motin 		for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) {
138096f556f5SAlexander Motin 			snprintf(buf, sizeof(buf), "mw_trans%d", widx);
138196f556f5SAlexander Motin 			snprintf(desc, sizeof(desc), "mw trans%d info", widx);
138296f556f5SAlexander Motin 
138396f556f5SAlexander Motin 			SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, buf,
138496f556f5SAlexander Motin 			    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
138596f556f5SAlexander Motin 			    &tc->peers[pidx].inmws[widx], 0,
138696f556f5SAlexander Motin 			    sysctl_mw_trans_handler, "IU", desc);
138796f556f5SAlexander Motin 
138896f556f5SAlexander Motin 			snprintf(buf, sizeof(buf), "mw%d", widx);
138996f556f5SAlexander Motin 			snprintf(desc, sizeof(desc), "mw%d info", widx);
139096f556f5SAlexander Motin 
139196f556f5SAlexander Motin 			SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, buf,
139296f556f5SAlexander Motin 			    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
139396f556f5SAlexander Motin 			    &tc->peers[pidx].inmws[widx], 0,
139496f556f5SAlexander Motin 			    sysctl_mw_handle, "IU", desc);
139596f556f5SAlexander Motin 
139696f556f5SAlexander Motin 			snprintf(buf, sizeof(buf), "peer_mw%d", widx);
139796f556f5SAlexander Motin 			snprintf(desc, sizeof(desc), "peer_mw%d info", widx);
139896f556f5SAlexander Motin 
139996f556f5SAlexander Motin 			SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, buf,
140096f556f5SAlexander Motin 			    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
140196f556f5SAlexander Motin 			    &tc->peers[pidx].inmws[widx], 0,
140296f556f5SAlexander Motin 			    sysctl_peer_mw_handle, "IU", desc);
140396f556f5SAlexander Motin 		}
140496f556f5SAlexander Motin 
140596f556f5SAlexander Motin 		for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) {
140696f556f5SAlexander Motin 			snprintf(buf, sizeof(buf), "spad%d", sidx);
140796f556f5SAlexander Motin 			snprintf(desc, sizeof(desc), "spad%d info", sidx);
140896f556f5SAlexander Motin 
140996f556f5SAlexander Motin 			SYSCTL_ADD_PROC(clist, peer_top, OID_AUTO, buf,
141096f556f5SAlexander Motin 			    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
141196f556f5SAlexander Motin 			    tc, sidx, sysctl_peer_spad_handle, "IU", desc);
141296f556f5SAlexander Motin 		}
141396f556f5SAlexander Motin 	}
141496f556f5SAlexander Motin }
141596f556f5SAlexander Motin 
141696f556f5SAlexander Motin static int
ntb_tool_probe(device_t dev)141796f556f5SAlexander Motin ntb_tool_probe(device_t dev)
141896f556f5SAlexander Motin {
141996f556f5SAlexander Motin 	device_set_desc(dev, "NTB TOOL");
142096f556f5SAlexander Motin 	return (0);
142196f556f5SAlexander Motin }
142296f556f5SAlexander Motin 
142396f556f5SAlexander Motin static int
ntb_tool_attach(device_t dev)142496f556f5SAlexander Motin ntb_tool_attach(device_t dev)
142596f556f5SAlexander Motin {
142696f556f5SAlexander Motin 	struct tool_ctx *tc = device_get_softc(dev);
142796f556f5SAlexander Motin 	int rc = 0;
142896f556f5SAlexander Motin 
142996f556f5SAlexander Motin 	tc->dev = dev;
143096f556f5SAlexander Motin 	rc = tool_check_ntb(tc);
143196f556f5SAlexander Motin 	if (rc)
143296f556f5SAlexander Motin 		goto out;
143396f556f5SAlexander Motin 
1434dace3812SMark Johnston 	tool_init_peers(tc);
143596f556f5SAlexander Motin 
143696f556f5SAlexander Motin 	rc = tool_init_mws(tc);
143796f556f5SAlexander Motin 	if (rc)
143896f556f5SAlexander Motin 		goto err_clear_data;
143996f556f5SAlexander Motin 
1440dace3812SMark Johnston 	tool_init_spads(tc);
144196f556f5SAlexander Motin 
144296f556f5SAlexander Motin 	rc = tool_init_ntb(tc);
144396f556f5SAlexander Motin 	if (rc)
144496f556f5SAlexander Motin 		goto err_clear_spads;
144596f556f5SAlexander Motin 
144696f556f5SAlexander Motin 	tool_setup_sysctl(tc);
144796f556f5SAlexander Motin 
144896f556f5SAlexander Motin 	return (0);
144996f556f5SAlexander Motin 
145096f556f5SAlexander Motin err_clear_spads:
145196f556f5SAlexander Motin 	tool_clear_spads(tc);
145296f556f5SAlexander Motin 	tool_clear_mws(tc);
145396f556f5SAlexander Motin 	tool_clear_peers(tc);
145496f556f5SAlexander Motin err_clear_data:
145596f556f5SAlexander Motin 	tool_clear_data(tc);
145696f556f5SAlexander Motin out:
145796f556f5SAlexander Motin 	device_printf(dev, "ntb_tool attached failed with err=(%d).\n", rc);
145896f556f5SAlexander Motin 	return (rc);
145996f556f5SAlexander Motin }
146096f556f5SAlexander Motin 
146196f556f5SAlexander Motin static int
ntb_tool_detach(device_t dev)146296f556f5SAlexander Motin ntb_tool_detach(device_t dev)
146396f556f5SAlexander Motin {
146496f556f5SAlexander Motin 	struct tool_ctx *tc = device_get_softc(dev);
146596f556f5SAlexander Motin 
146696f556f5SAlexander Motin 	tool_clear_ntb(tc);
146796f556f5SAlexander Motin 
146896f556f5SAlexander Motin 	tool_clear_spads(tc);
146996f556f5SAlexander Motin 
147096f556f5SAlexander Motin 	tool_clear_mws(tc);
147196f556f5SAlexander Motin 
147296f556f5SAlexander Motin 	tool_clear_peers(tc);
147396f556f5SAlexander Motin 
147496f556f5SAlexander Motin 	tool_clear_data(tc);
147596f556f5SAlexander Motin 
147696f556f5SAlexander Motin 	return (0);
147796f556f5SAlexander Motin }
147896f556f5SAlexander Motin 
147996f556f5SAlexander Motin static device_method_t ntb_tool_methods[] = {
148096f556f5SAlexander Motin 	/* Device interface */
148196f556f5SAlexander Motin 	DEVMETHOD(device_probe,     ntb_tool_probe),
148296f556f5SAlexander Motin 	DEVMETHOD(device_attach,    ntb_tool_attach),
148396f556f5SAlexander Motin 	DEVMETHOD(device_detach,    ntb_tool_detach),
148496f556f5SAlexander Motin 	DEVMETHOD_END
148596f556f5SAlexander Motin };
148696f556f5SAlexander Motin 
148796f556f5SAlexander Motin static DEFINE_CLASS_0(ntb_tool, ntb_tool_driver, ntb_tool_methods,
148896f556f5SAlexander Motin     sizeof(struct tool_ctx));
14899940f7a7SJohn Baldwin DRIVER_MODULE(ntb_tool, ntb_hw, ntb_tool_driver, NULL, NULL);
149096f556f5SAlexander Motin MODULE_DEPEND(ntb_tool, ntb, 1, 1, 1);
149196f556f5SAlexander Motin MODULE_VERSION(ntb_tool, 1.0);
1492