1578b881bSAllen Hubbe /*
2578b881bSAllen Hubbe * This file is provided under a dual BSD/GPLv2 license. When using or
3578b881bSAllen Hubbe * redistributing this file, you may do so under either license.
4578b881bSAllen Hubbe *
5578b881bSAllen Hubbe * GPL LICENSE SUMMARY
6578b881bSAllen Hubbe *
7578b881bSAllen Hubbe * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
87f46c8b3SSerge Semin * Copyright (C) 2017 T-Platforms All Rights Reserved.
9578b881bSAllen Hubbe *
10578b881bSAllen Hubbe * This program is free software; you can redistribute it and/or modify
11578b881bSAllen Hubbe * it under the terms of version 2 of the GNU General Public License as
12578b881bSAllen Hubbe * published by the Free Software Foundation.
13578b881bSAllen Hubbe *
14578b881bSAllen Hubbe * This program is distributed in the hope that it will be useful, but
15578b881bSAllen Hubbe * WITHOUT ANY WARRANTY; without even the implied warranty of
16578b881bSAllen Hubbe * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17578b881bSAllen Hubbe * General Public License for more details.
18578b881bSAllen Hubbe *
19578b881bSAllen Hubbe * BSD LICENSE
20578b881bSAllen Hubbe *
21578b881bSAllen Hubbe * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
227f46c8b3SSerge Semin * Copyright (C) 2017 T-Platforms All Rights Reserved.
23578b881bSAllen Hubbe *
24578b881bSAllen Hubbe * Redistribution and use in source and binary forms, with or without
25578b881bSAllen Hubbe * modification, are permitted provided that the following conditions
26578b881bSAllen Hubbe * are met:
27578b881bSAllen Hubbe *
28578b881bSAllen Hubbe * * Redistributions of source code must retain the above copyright
29578b881bSAllen Hubbe * notice, this list of conditions and the following disclaimer.
30578b881bSAllen Hubbe * * Redistributions in binary form must reproduce the above copy
31578b881bSAllen Hubbe * notice, this list of conditions and the following disclaimer in
32578b881bSAllen Hubbe * the documentation and/or other materials provided with the
33578b881bSAllen Hubbe * distribution.
34578b881bSAllen Hubbe * * Neither the name of Intel Corporation nor the names of its
35578b881bSAllen Hubbe * contributors may be used to endorse or promote products derived
36578b881bSAllen Hubbe * from this software without specific prior written permission.
37578b881bSAllen Hubbe *
38578b881bSAllen Hubbe * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
39578b881bSAllen Hubbe * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
40578b881bSAllen Hubbe * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
41578b881bSAllen Hubbe * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
42578b881bSAllen Hubbe * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43578b881bSAllen Hubbe * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44578b881bSAllen Hubbe * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45578b881bSAllen Hubbe * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46578b881bSAllen Hubbe * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47578b881bSAllen Hubbe * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
48578b881bSAllen Hubbe * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49578b881bSAllen Hubbe *
50578b881bSAllen Hubbe * PCIe NTB Debugging Tool Linux driver
51578b881bSAllen Hubbe */
52578b881bSAllen Hubbe
53578b881bSAllen Hubbe /*
54578b881bSAllen Hubbe * How to use this tool, by example.
55578b881bSAllen Hubbe *
56578b881bSAllen Hubbe * Assuming $DBG_DIR is something like:
57578b881bSAllen Hubbe * '/sys/kernel/debug/ntb_tool/0000:00:03.0'
587f46c8b3SSerge Semin * Suppose aside from local device there is at least one remote device
597f46c8b3SSerge Semin * connected to NTB with index 0.
607f46c8b3SSerge Semin *-----------------------------------------------------------------------------
617f46c8b3SSerge Semin * Eg: check local/peer device information.
62578b881bSAllen Hubbe *
637f46c8b3SSerge Semin * # Get local device port number
647f46c8b3SSerge Semin * root@self# cat $DBG_DIR/port
65578b881bSAllen Hubbe *
667f46c8b3SSerge Semin * # Check local device functionality
677f46c8b3SSerge Semin * root@self# ls $DBG_DIR
687f46c8b3SSerge Semin * db msg1 msg_sts peer4/ port
697f46c8b3SSerge Semin * db_event msg2 peer0/ peer5/ spad0
707f46c8b3SSerge Semin * db_mask msg3 peer1/ peer_db spad1
717f46c8b3SSerge Semin * link msg_event peer2/ peer_db_mask spad2
727f46c8b3SSerge Semin * msg0 msg_mask peer3/ peer_spad spad3
737f46c8b3SSerge Semin * # As one can see it supports:
747f46c8b3SSerge Semin * # 1) four inbound message registers
757f46c8b3SSerge Semin * # 2) four inbound scratchpads
767f46c8b3SSerge Semin * # 3) up to six peer devices
77bfcaa396SLogan Gunthorpe *
787f46c8b3SSerge Semin * # Check peer device port number
797f46c8b3SSerge Semin * root@self# cat $DBG_DIR/peer0/port
80bfcaa396SLogan Gunthorpe *
817f46c8b3SSerge Semin * # Check peer device(s) functionality to be used
827f46c8b3SSerge Semin * root@self# ls $DBG_DIR/peer0
837f46c8b3SSerge Semin * link mw_trans0 mw_trans6 port
847f46c8b3SSerge Semin * link_event mw_trans1 mw_trans7 spad0
857f46c8b3SSerge Semin * msg0 mw_trans2 peer_mw_trans0 spad1
867f46c8b3SSerge Semin * msg1 mw_trans3 peer_mw_trans1 spad2
877f46c8b3SSerge Semin * msg2 mw_trans4 peer_mw_trans2 spad3
887f46c8b3SSerge Semin * msg3 mw_trans5 peer_mw_trans3
897f46c8b3SSerge Semin * # As one can see we got:
907f46c8b3SSerge Semin * # 1) four outbound message registers
917f46c8b3SSerge Semin * # 2) four outbound scratchpads
927f46c8b3SSerge Semin * # 3) eight inbound memory windows
937f46c8b3SSerge Semin * # 4) four outbound memory windows
947f46c8b3SSerge Semin *-----------------------------------------------------------------------------
957f46c8b3SSerge Semin * Eg: NTB link tests
96578b881bSAllen Hubbe *
977f46c8b3SSerge Semin * # Set local link up/down
987f46c8b3SSerge Semin * root@self# echo Y > $DBG_DIR/link
997f46c8b3SSerge Semin * root@self# echo N > $DBG_DIR/link
1007f46c8b3SSerge Semin *
1017f46c8b3SSerge Semin * # Check if link with peer device is up/down:
1027f46c8b3SSerge Semin * root@self# cat $DBG_DIR/peer0/link
1037f46c8b3SSerge Semin *
1047f46c8b3SSerge Semin * # Block until the link is up/down
1057f46c8b3SSerge Semin * root@self# echo Y > $DBG_DIR/peer0/link_event
1067f46c8b3SSerge Semin * root@self# echo N > $DBG_DIR/peer0/link_event
1077f46c8b3SSerge Semin *-----------------------------------------------------------------------------
1087f46c8b3SSerge Semin * Eg: Doorbell registers tests (some functionality might be absent)
1097f46c8b3SSerge Semin *
1107f46c8b3SSerge Semin * # Set/clear/get local doorbell
1117f46c8b3SSerge Semin * root@self# echo 's 1' > $DBG_DIR/db
1127f46c8b3SSerge Semin * root@self# echo 'c 1' > $DBG_DIR/db
1137f46c8b3SSerge Semin * root@self# cat $DBG_DIR/db
1147f46c8b3SSerge Semin *
1157f46c8b3SSerge Semin * # Set/clear/get local doorbell mask
1167f46c8b3SSerge Semin * root@self# echo 's 1' > $DBG_DIR/db_mask
1177f46c8b3SSerge Semin * root@self# echo 'c 1' > $DBG_DIR/db_mask
1187f46c8b3SSerge Semin * root@self# cat $DBG_DIR/db_mask
1197f46c8b3SSerge Semin *
1207f46c8b3SSerge Semin * # Ring/clear/get peer doorbell
121578b881bSAllen Hubbe * root@peer# echo 's 1' > $DBG_DIR/peer_db
1227f46c8b3SSerge Semin * root@peer# echo 'c 1' > $DBG_DIR/peer_db
1237f46c8b3SSerge Semin * root@peer# cat $DBG_DIR/peer_db
124578b881bSAllen Hubbe *
1257f46c8b3SSerge Semin * # Set/clear/get peer doorbell mask
1267f46c8b3SSerge Semin * root@self# echo 's 1' > $DBG_DIR/peer_db_mask
1277f46c8b3SSerge Semin * root@self# echo 'c 1' > $DBG_DIR/peer_db_mask
1287f46c8b3SSerge Semin * root@self# cat $DBG_DIR/peer_db_mask
129578b881bSAllen Hubbe *
1307f46c8b3SSerge Semin * # Block until local doorbell is set with specified value
1317f46c8b3SSerge Semin * root@self# echo 1 > $DBG_DIR/db_event
1327f46c8b3SSerge Semin *-----------------------------------------------------------------------------
1337f46c8b3SSerge Semin * Eg: Message registers tests (functionality might be absent)
134578b881bSAllen Hubbe *
1357f46c8b3SSerge Semin * # Set/clear/get in/out message registers status
1367f46c8b3SSerge Semin * root@self# echo 's 1' > $DBG_DIR/msg_sts
1377f46c8b3SSerge Semin * root@self# echo 'c 1' > $DBG_DIR/msg_sts
1387f46c8b3SSerge Semin * root@self# cat $DBG_DIR/msg_sts
139578b881bSAllen Hubbe *
1407f46c8b3SSerge Semin * # Set/clear in/out message registers mask
1417f46c8b3SSerge Semin * root@self# echo 's 1' > $DBG_DIR/msg_mask
1427f46c8b3SSerge Semin * root@self# echo 'c 1' > $DBG_DIR/msg_mask
143578b881bSAllen Hubbe *
1447f46c8b3SSerge Semin * # Get inbound message register #0 value and source of port index
1457f46c8b3SSerge Semin * root@self# cat $DBG_DIR/msg0
146578b881bSAllen Hubbe *
1477f46c8b3SSerge Semin * # Send some data to peer over outbound message register #0
1487f46c8b3SSerge Semin * root@self# echo 0x01020304 > $DBG_DIR/peer0/msg0
1497f46c8b3SSerge Semin *-----------------------------------------------------------------------------
1507f46c8b3SSerge Semin * Eg: Scratchpad registers tests (functionality might be absent)
151717146a2SLogan Gunthorpe *
1527f46c8b3SSerge Semin * # Write/read to/from local scratchpad register #0
1537f46c8b3SSerge Semin * root@peer# echo 0x01020304 > $DBG_DIR/spad0
1547f46c8b3SSerge Semin * root@peer# cat $DBG_DIR/spad0
155717146a2SLogan Gunthorpe *
1567f46c8b3SSerge Semin * # Write/read to/from peer scratchpad register #0
1577f46c8b3SSerge Semin * root@peer# echo 0x01020304 > $DBG_DIR/peer0/spad0
1587f46c8b3SSerge Semin * root@peer# cat $DBG_DIR/peer0/spad0
1597f46c8b3SSerge Semin *-----------------------------------------------------------------------------
1607f46c8b3SSerge Semin * Eg: Memory windows tests
161717146a2SLogan Gunthorpe *
1627f46c8b3SSerge Semin * # Create inbound memory window buffer of specified size/get its base address
1637f46c8b3SSerge Semin * root@peer# echo 16384 > $DBG_DIR/peer0/mw_trans0
1647f46c8b3SSerge Semin * root@peer# cat $DBG_DIR/peer0/mw_trans0
1657f46c8b3SSerge Semin *
1667f46c8b3SSerge Semin * # Write/read data to/from inbound memory window
1677f46c8b3SSerge Semin * root@peer# echo Hello > $DBG_DIR/peer0/mw0
1687f46c8b3SSerge Semin * root@peer# head -c 7 $DBG_DIR/peer0/mw0
1697f46c8b3SSerge Semin *
1707f46c8b3SSerge Semin * # Map outbound memory window/check it settings (on peer device)
1717f46c8b3SSerge Semin * root@peer# echo 0xADD0BA5E:16384 > $DBG_DIR/peer0/peer_mw_trans0
1727f46c8b3SSerge Semin * root@peer# cat $DBG_DIR/peer0/peer_mw_trans0
1737f46c8b3SSerge Semin *
1747f46c8b3SSerge Semin * # Write/read data to/from outbound memory window (on peer device)
1757f46c8b3SSerge Semin * root@peer# echo olleH > $DBG_DIR/peer0/peer_mw0
1767f46c8b3SSerge Semin * root@peer# head -c 7 $DBG_DIR/peer0/peer_mw0
177578b881bSAllen Hubbe */
178578b881bSAllen Hubbe
179578b881bSAllen Hubbe #include <linux/init.h>
180578b881bSAllen Hubbe #include <linux/kernel.h>
181578b881bSAllen Hubbe #include <linux/module.h>
182578b881bSAllen Hubbe
183578b881bSAllen Hubbe #include <linux/debugfs.h>
184578b881bSAllen Hubbe #include <linux/dma-mapping.h>
185578b881bSAllen Hubbe #include <linux/pci.h>
186578b881bSAllen Hubbe #include <linux/slab.h>
1878b71d285SLogan Gunthorpe #include <linux/uaccess.h>
188578b881bSAllen Hubbe
189578b881bSAllen Hubbe #include <linux/ntb.h>
190578b881bSAllen Hubbe
191578b881bSAllen Hubbe #define DRIVER_NAME "ntb_tool"
1927f46c8b3SSerge Semin #define DRIVER_VERSION "2.0"
193578b881bSAllen Hubbe
1940ed08f82SGreg Kroah-Hartman MODULE_LICENSE("Dual BSD/GPL");
195578b881bSAllen Hubbe MODULE_VERSION(DRIVER_VERSION);
1967f46c8b3SSerge Semin MODULE_AUTHOR("Allen Hubbe <Allen.Hubbe@emc.com>");
1977f46c8b3SSerge Semin MODULE_DESCRIPTION("PCIe NTB Debugging Tool");
198578b881bSAllen Hubbe
1997f46c8b3SSerge Semin /*
2007f46c8b3SSerge Semin * Inbound and outbound memory windows descriptor. Union members selection
2017f46c8b3SSerge Semin * depends on the MW type the structure describes. mm_base/dma_base are the
2027f46c8b3SSerge Semin * virtual and DMA address of an inbound MW. io_base/tr_base are the MMIO
2037f46c8b3SSerge Semin * mapped virtual and xlat addresses of an outbound MW respectively.
2047f46c8b3SSerge Semin */
2058b71d285SLogan Gunthorpe struct tool_mw {
2067f46c8b3SSerge Semin int widx;
2077f46c8b3SSerge Semin int pidx;
208717146a2SLogan Gunthorpe struct tool_ctx *tc;
2097f46c8b3SSerge Semin union {
2107f46c8b3SSerge Semin u8 *mm_base;
2117f46c8b3SSerge Semin u8 __iomem *io_base;
2127f46c8b3SSerge Semin };
2137f46c8b3SSerge Semin union {
2147f46c8b3SSerge Semin dma_addr_t dma_base;
2157f46c8b3SSerge Semin u64 tr_base;
2167f46c8b3SSerge Semin };
2178b71d285SLogan Gunthorpe resource_size_t size;
2187f46c8b3SSerge Semin struct dentry *dbgfs_file;
2197f46c8b3SSerge Semin };
2207f46c8b3SSerge Semin
2217f46c8b3SSerge Semin /*
2227f46c8b3SSerge Semin * Wrapper structure is used to distinguish the outbound MW peers reference
2237f46c8b3SSerge Semin * within the corresponding DebugFS directory IO operation.
2247f46c8b3SSerge Semin */
2257f46c8b3SSerge Semin struct tool_mw_wrap {
2267f46c8b3SSerge Semin int pidx;
2277f46c8b3SSerge Semin struct tool_mw *mw;
2287f46c8b3SSerge Semin };
2297f46c8b3SSerge Semin
2307f46c8b3SSerge Semin struct tool_msg {
2317f46c8b3SSerge Semin int midx;
2327f46c8b3SSerge Semin int pidx;
2337f46c8b3SSerge Semin struct tool_ctx *tc;
2347f46c8b3SSerge Semin };
2357f46c8b3SSerge Semin
2367f46c8b3SSerge Semin struct tool_spad {
2377f46c8b3SSerge Semin int sidx;
2387f46c8b3SSerge Semin int pidx;
2397f46c8b3SSerge Semin struct tool_ctx *tc;
2407f46c8b3SSerge Semin };
2417f46c8b3SSerge Semin
2427f46c8b3SSerge Semin struct tool_peer {
2437f46c8b3SSerge Semin int pidx;
2447f46c8b3SSerge Semin struct tool_ctx *tc;
2457f46c8b3SSerge Semin int inmw_cnt;
2467f46c8b3SSerge Semin struct tool_mw *inmws;
2477f46c8b3SSerge Semin int outmw_cnt;
2487f46c8b3SSerge Semin struct tool_mw_wrap *outmws;
2497f46c8b3SSerge Semin int outmsg_cnt;
2507f46c8b3SSerge Semin struct tool_msg *outmsgs;
2517f46c8b3SSerge Semin int outspad_cnt;
2527f46c8b3SSerge Semin struct tool_spad *outspads;
2537f46c8b3SSerge Semin struct dentry *dbgfs_dir;
2548b71d285SLogan Gunthorpe };
2558b71d285SLogan Gunthorpe
256578b881bSAllen Hubbe struct tool_ctx {
257578b881bSAllen Hubbe struct ntb_dev *ntb;
258bfcaa396SLogan Gunthorpe wait_queue_head_t link_wq;
2597f46c8b3SSerge Semin wait_queue_head_t db_wq;
2607f46c8b3SSerge Semin wait_queue_head_t msg_wq;
2617f46c8b3SSerge Semin int outmw_cnt;
2627f46c8b3SSerge Semin struct tool_mw *outmws;
2637f46c8b3SSerge Semin int peer_cnt;
2647f46c8b3SSerge Semin struct tool_peer *peers;
2657f46c8b3SSerge Semin int inmsg_cnt;
2667f46c8b3SSerge Semin struct tool_msg *inmsgs;
2677f46c8b3SSerge Semin int inspad_cnt;
2687f46c8b3SSerge Semin struct tool_spad *inspads;
2697f46c8b3SSerge Semin struct dentry *dbgfs_dir;
270578b881bSAllen Hubbe };
271578b881bSAllen Hubbe
272578b881bSAllen Hubbe #define TOOL_FOPS_RDWR(__name, __read, __write) \
273578b881bSAllen Hubbe const struct file_operations __name = { \
274578b881bSAllen Hubbe .owner = THIS_MODULE, \
275578b881bSAllen Hubbe .open = simple_open, \
276578b881bSAllen Hubbe .read = __read, \
277578b881bSAllen Hubbe .write = __write, \
278578b881bSAllen Hubbe }
279578b881bSAllen Hubbe
2807f46c8b3SSerge Semin #define TOOL_BUF_LEN 32
2817f46c8b3SSerge Semin
2827f46c8b3SSerge Semin static struct dentry *tool_dbgfs_topdir;
2837f46c8b3SSerge Semin
2847f46c8b3SSerge Semin /*==============================================================================
2857f46c8b3SSerge Semin * NTB events handlers
2867f46c8b3SSerge Semin *==============================================================================
2877f46c8b3SSerge Semin */
2887f46c8b3SSerge Semin
tool_link_event(void * ctx)289578b881bSAllen Hubbe static void tool_link_event(void *ctx)
290578b881bSAllen Hubbe {
291578b881bSAllen Hubbe struct tool_ctx *tc = ctx;
292578b881bSAllen Hubbe enum ntb_speed speed;
293578b881bSAllen Hubbe enum ntb_width width;
294578b881bSAllen Hubbe int up;
295578b881bSAllen Hubbe
296578b881bSAllen Hubbe up = ntb_link_is_up(tc->ntb, &speed, &width);
297578b881bSAllen Hubbe
298578b881bSAllen Hubbe dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n",
299578b881bSAllen Hubbe up ? "up" : "down", speed, width);
3008b71d285SLogan Gunthorpe
301bfcaa396SLogan Gunthorpe wake_up(&tc->link_wq);
302578b881bSAllen Hubbe }
303578b881bSAllen Hubbe
tool_db_event(void * ctx,int vec)304578b881bSAllen Hubbe static void tool_db_event(void *ctx, int vec)
305578b881bSAllen Hubbe {
306578b881bSAllen Hubbe struct tool_ctx *tc = ctx;
307578b881bSAllen Hubbe u64 db_bits, db_mask;
308578b881bSAllen Hubbe
309578b881bSAllen Hubbe db_mask = ntb_db_vector_mask(tc->ntb, vec);
310578b881bSAllen Hubbe db_bits = ntb_db_read(tc->ntb);
311578b881bSAllen Hubbe
312578b881bSAllen Hubbe dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n",
313578b881bSAllen Hubbe vec, db_mask, db_bits);
3147f46c8b3SSerge Semin
3157f46c8b3SSerge Semin wake_up(&tc->db_wq);
3167f46c8b3SSerge Semin }
3177f46c8b3SSerge Semin
tool_msg_event(void * ctx)3187f46c8b3SSerge Semin static void tool_msg_event(void *ctx)
3197f46c8b3SSerge Semin {
3207f46c8b3SSerge Semin struct tool_ctx *tc = ctx;
3217f46c8b3SSerge Semin u64 msg_sts;
3227f46c8b3SSerge Semin
3237f46c8b3SSerge Semin msg_sts = ntb_msg_read_sts(tc->ntb);
3247f46c8b3SSerge Semin
3257f46c8b3SSerge Semin dev_dbg(&tc->ntb->dev, "message bits %#llx\n", msg_sts);
3267f46c8b3SSerge Semin
3277f46c8b3SSerge Semin wake_up(&tc->msg_wq);
328578b881bSAllen Hubbe }
329578b881bSAllen Hubbe
330578b881bSAllen Hubbe static const struct ntb_ctx_ops tool_ops = {
331578b881bSAllen Hubbe .link_event = tool_link_event,
332578b881bSAllen Hubbe .db_event = tool_db_event,
3337f46c8b3SSerge Semin .msg_event = tool_msg_event
334578b881bSAllen Hubbe };
335578b881bSAllen Hubbe
3367f46c8b3SSerge Semin /*==============================================================================
3377f46c8b3SSerge Semin * Common read/write methods
3387f46c8b3SSerge Semin *==============================================================================
3397f46c8b3SSerge Semin */
3407f46c8b3SSerge Semin
tool_fn_read(struct tool_ctx * tc,char __user * ubuf,size_t size,loff_t * offp,u64 (* fn_read)(struct ntb_dev *))3417f46c8b3SSerge Semin static ssize_t tool_fn_read(struct tool_ctx *tc, char __user *ubuf,
342578b881bSAllen Hubbe size_t size, loff_t *offp,
3437f46c8b3SSerge Semin u64 (*fn_read)(struct ntb_dev *))
344578b881bSAllen Hubbe {
345578b881bSAllen Hubbe size_t buf_size;
3467f46c8b3SSerge Semin char buf[TOOL_BUF_LEN];
3477f46c8b3SSerge Semin ssize_t pos;
348578b881bSAllen Hubbe
3497f46c8b3SSerge Semin if (!fn_read)
350578b881bSAllen Hubbe return -EINVAL;
351578b881bSAllen Hubbe
3527f46c8b3SSerge Semin buf_size = min(size, sizeof(buf));
353578b881bSAllen Hubbe
3547f46c8b3SSerge Semin pos = scnprintf(buf, buf_size, "%#llx\n", fn_read(tc->ntb));
355578b881bSAllen Hubbe
3567f46c8b3SSerge Semin return simple_read_from_buffer(ubuf, size, offp, buf, pos);
357578b881bSAllen Hubbe }
358578b881bSAllen Hubbe
tool_fn_write(struct tool_ctx * tc,const char __user * ubuf,size_t size,loff_t * offp,int (* fn_set)(struct ntb_dev *,u64),int (* fn_clear)(struct ntb_dev *,u64))3597f46c8b3SSerge Semin static ssize_t tool_fn_write(struct tool_ctx *tc,
360578b881bSAllen Hubbe const char __user *ubuf,
361578b881bSAllen Hubbe size_t size, loff_t *offp,
3627f46c8b3SSerge Semin int (*fn_set)(struct ntb_dev *, u64),
3637f46c8b3SSerge Semin int (*fn_clear)(struct ntb_dev *, u64))
364578b881bSAllen Hubbe {
365578b881bSAllen Hubbe char *buf, cmd;
3667f46c8b3SSerge Semin ssize_t ret;
3677f46c8b3SSerge Semin u64 bits;
368578b881bSAllen Hubbe int n;
369578b881bSAllen Hubbe
37045e1058bSDan Carpenter if (*offp)
37145e1058bSDan Carpenter return 0;
37245e1058bSDan Carpenter
373*03c9e6f0SRuan Jinjie buf = memdup_user_nul(ubuf, size);
374*03c9e6f0SRuan Jinjie if (IS_ERR(buf))
375*03c9e6f0SRuan Jinjie return PTR_ERR(buf);
376578b881bSAllen Hubbe
3777f46c8b3SSerge Semin n = sscanf(buf, "%c %lli", &cmd, &bits);
378578b881bSAllen Hubbe
379578b881bSAllen Hubbe kfree(buf);
380578b881bSAllen Hubbe
381578b881bSAllen Hubbe if (n != 2) {
3827f46c8b3SSerge Semin ret = -EINVAL;
383578b881bSAllen Hubbe } else if (cmd == 's') {
3847f46c8b3SSerge Semin if (!fn_set)
3857f46c8b3SSerge Semin ret = -EINVAL;
386578b881bSAllen Hubbe else
3877f46c8b3SSerge Semin ret = fn_set(tc->ntb, bits);
388578b881bSAllen Hubbe } else if (cmd == 'c') {
3897f46c8b3SSerge Semin if (!fn_clear)
3907f46c8b3SSerge Semin ret = -EINVAL;
391578b881bSAllen Hubbe else
3927f46c8b3SSerge Semin ret = fn_clear(tc->ntb, bits);
393578b881bSAllen Hubbe } else {
3947f46c8b3SSerge Semin ret = -EINVAL;
395578b881bSAllen Hubbe }
396578b881bSAllen Hubbe
3977f46c8b3SSerge Semin return ret ? : size;
398578b881bSAllen Hubbe }
399578b881bSAllen Hubbe
4007f46c8b3SSerge Semin /*==============================================================================
4017f46c8b3SSerge Semin * Port read/write methods
4027f46c8b3SSerge Semin *==============================================================================
403625f0802SLogan Gunthorpe */
404578b881bSAllen Hubbe
tool_port_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)4057f46c8b3SSerge Semin static ssize_t tool_port_read(struct file *filep, char __user *ubuf,
4067f46c8b3SSerge Semin size_t size, loff_t *offp)
4077f46c8b3SSerge Semin {
4087f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
4097f46c8b3SSerge Semin char buf[TOOL_BUF_LEN];
4107f46c8b3SSerge Semin int pos;
4117f46c8b3SSerge Semin
4127f46c8b3SSerge Semin pos = scnprintf(buf, sizeof(buf), "%d\n", ntb_port_number(tc->ntb));
4137f46c8b3SSerge Semin
4147f46c8b3SSerge Semin return simple_read_from_buffer(ubuf, size, offp, buf, pos);
4157f46c8b3SSerge Semin }
4167f46c8b3SSerge Semin
4177f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_port_fops,
4187f46c8b3SSerge Semin tool_port_read,
4197f46c8b3SSerge Semin NULL);
4207f46c8b3SSerge Semin
tool_peer_port_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)4217f46c8b3SSerge Semin static ssize_t tool_peer_port_read(struct file *filep, char __user *ubuf,
4227f46c8b3SSerge Semin size_t size, loff_t *offp)
4237f46c8b3SSerge Semin {
4247f46c8b3SSerge Semin struct tool_peer *peer = filep->private_data;
4257f46c8b3SSerge Semin struct tool_ctx *tc = peer->tc;
4267f46c8b3SSerge Semin char buf[TOOL_BUF_LEN];
4277f46c8b3SSerge Semin int pos;
4287f46c8b3SSerge Semin
4297f46c8b3SSerge Semin pos = scnprintf(buf, sizeof(buf), "%d\n",
4307f46c8b3SSerge Semin ntb_peer_port_number(tc->ntb, peer->pidx));
4317f46c8b3SSerge Semin
4327f46c8b3SSerge Semin return simple_read_from_buffer(ubuf, size, offp, buf, pos);
4337f46c8b3SSerge Semin }
4347f46c8b3SSerge Semin
4357f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_peer_port_fops,
4367f46c8b3SSerge Semin tool_peer_port_read,
4377f46c8b3SSerge Semin NULL);
4387f46c8b3SSerge Semin
tool_init_peers(struct tool_ctx * tc)4397f46c8b3SSerge Semin static int tool_init_peers(struct tool_ctx *tc)
4407f46c8b3SSerge Semin {
4417f46c8b3SSerge Semin int pidx;
4427f46c8b3SSerge Semin
4437f46c8b3SSerge Semin tc->peer_cnt = ntb_peer_port_count(tc->ntb);
4447f46c8b3SSerge Semin tc->peers = devm_kcalloc(&tc->ntb->dev, tc->peer_cnt,
4457f46c8b3SSerge Semin sizeof(*tc->peers), GFP_KERNEL);
4467f46c8b3SSerge Semin if (tc->peers == NULL)
447578b881bSAllen Hubbe return -ENOMEM;
448578b881bSAllen Hubbe
4497f46c8b3SSerge Semin for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
4507f46c8b3SSerge Semin tc->peers[pidx].pidx = pidx;
4517f46c8b3SSerge Semin tc->peers[pidx].tc = tc;
452578b881bSAllen Hubbe }
453578b881bSAllen Hubbe
4547f46c8b3SSerge Semin return 0;
455578b881bSAllen Hubbe }
456578b881bSAllen Hubbe
4577f46c8b3SSerge Semin /*==============================================================================
4587f46c8b3SSerge Semin * Link state read/write methods
4597f46c8b3SSerge Semin *==============================================================================
4607f46c8b3SSerge Semin */
461bfcaa396SLogan Gunthorpe
tool_link_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)462bfcaa396SLogan Gunthorpe static ssize_t tool_link_write(struct file *filep, const char __user *ubuf,
463bfcaa396SLogan Gunthorpe size_t size, loff_t *offp)
464bfcaa396SLogan Gunthorpe {
465bfcaa396SLogan Gunthorpe struct tool_ctx *tc = filep->private_data;
466bfcaa396SLogan Gunthorpe bool val;
4677f46c8b3SSerge Semin int ret;
468bfcaa396SLogan Gunthorpe
4697f46c8b3SSerge Semin ret = kstrtobool_from_user(ubuf, size, &val);
4707f46c8b3SSerge Semin if (ret)
4717f46c8b3SSerge Semin return ret;
472bfcaa396SLogan Gunthorpe
473bfcaa396SLogan Gunthorpe if (val)
4747f46c8b3SSerge Semin ret = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
475bfcaa396SLogan Gunthorpe else
4767f46c8b3SSerge Semin ret = ntb_link_disable(tc->ntb);
477bfcaa396SLogan Gunthorpe
4787f46c8b3SSerge Semin if (ret)
4797f46c8b3SSerge Semin return ret;
480bfcaa396SLogan Gunthorpe
481bfcaa396SLogan Gunthorpe return size;
482bfcaa396SLogan Gunthorpe }
483bfcaa396SLogan Gunthorpe
484bfcaa396SLogan Gunthorpe static TOOL_FOPS_RDWR(tool_link_fops,
4857f46c8b3SSerge Semin NULL,
486bfcaa396SLogan Gunthorpe tool_link_write);
487bfcaa396SLogan Gunthorpe
tool_peer_link_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)4887f46c8b3SSerge Semin static ssize_t tool_peer_link_read(struct file *filep, char __user *ubuf,
4897f46c8b3SSerge Semin size_t size, loff_t *offp)
4907f46c8b3SSerge Semin {
4917f46c8b3SSerge Semin struct tool_peer *peer = filep->private_data;
4927f46c8b3SSerge Semin struct tool_ctx *tc = peer->tc;
4937f46c8b3SSerge Semin char buf[3];
4947f46c8b3SSerge Semin
4957f46c8b3SSerge Semin if (ntb_link_is_up(tc->ntb, NULL, NULL) & BIT(peer->pidx))
4967f46c8b3SSerge Semin buf[0] = 'Y';
4977f46c8b3SSerge Semin else
4987f46c8b3SSerge Semin buf[0] = 'N';
4997f46c8b3SSerge Semin buf[1] = '\n';
5007f46c8b3SSerge Semin buf[2] = '\0';
5017f46c8b3SSerge Semin
502912e1281SLogan Gunthorpe return simple_read_from_buffer(ubuf, size, offp, buf, 2);
5037f46c8b3SSerge Semin }
5047f46c8b3SSerge Semin
5057f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_peer_link_fops,
5067f46c8b3SSerge Semin tool_peer_link_read,
5077f46c8b3SSerge Semin NULL);
5087f46c8b3SSerge Semin
tool_peer_link_event_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)5097f46c8b3SSerge Semin static ssize_t tool_peer_link_event_write(struct file *filep,
510bfcaa396SLogan Gunthorpe const char __user *ubuf,
511bfcaa396SLogan Gunthorpe size_t size, loff_t *offp)
512bfcaa396SLogan Gunthorpe {
5137f46c8b3SSerge Semin struct tool_peer *peer = filep->private_data;
5147f46c8b3SSerge Semin struct tool_ctx *tc = peer->tc;
5157f46c8b3SSerge Semin u64 link_msk;
516bfcaa396SLogan Gunthorpe bool val;
5177f46c8b3SSerge Semin int ret;
518bfcaa396SLogan Gunthorpe
5197f46c8b3SSerge Semin ret = kstrtobool_from_user(ubuf, size, &val);
5207f46c8b3SSerge Semin if (ret)
5217f46c8b3SSerge Semin return ret;
522bfcaa396SLogan Gunthorpe
5237f46c8b3SSerge Semin link_msk = BIT_ULL_MASK(peer->pidx);
524bfcaa396SLogan Gunthorpe
525bfcaa396SLogan Gunthorpe if (wait_event_interruptible(tc->link_wq,
5267f46c8b3SSerge Semin !!(ntb_link_is_up(tc->ntb, NULL, NULL) & link_msk) == val))
527bfcaa396SLogan Gunthorpe return -ERESTART;
528bfcaa396SLogan Gunthorpe
529bfcaa396SLogan Gunthorpe return size;
530bfcaa396SLogan Gunthorpe }
531bfcaa396SLogan Gunthorpe
5327f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_peer_link_event_fops,
533bfcaa396SLogan Gunthorpe NULL,
5347f46c8b3SSerge Semin tool_peer_link_event_write);
5357f46c8b3SSerge Semin
5367f46c8b3SSerge Semin /*==============================================================================
5377f46c8b3SSerge Semin * Memory windows read/write/setting methods
5387f46c8b3SSerge Semin *==============================================================================
5397f46c8b3SSerge Semin */
5408b71d285SLogan Gunthorpe
tool_mw_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)5418b71d285SLogan Gunthorpe static ssize_t tool_mw_read(struct file *filep, char __user *ubuf,
5428b71d285SLogan Gunthorpe size_t size, loff_t *offp)
5438b71d285SLogan Gunthorpe {
5447f46c8b3SSerge Semin struct tool_mw *inmw = filep->private_data;
5458b71d285SLogan Gunthorpe
5467f46c8b3SSerge Semin if (inmw->mm_base == NULL)
5477f46c8b3SSerge Semin return -ENXIO;
5488b71d285SLogan Gunthorpe
5497f46c8b3SSerge Semin return simple_read_from_buffer(ubuf, size, offp,
5507f46c8b3SSerge Semin inmw->mm_base, inmw->size);
5518b71d285SLogan Gunthorpe }
5528b71d285SLogan Gunthorpe
tool_mw_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)5538b71d285SLogan Gunthorpe static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf,
5548b71d285SLogan Gunthorpe size_t size, loff_t *offp)
5558b71d285SLogan Gunthorpe {
5567f46c8b3SSerge Semin struct tool_mw *inmw = filep->private_data;
5578b71d285SLogan Gunthorpe
5587f46c8b3SSerge Semin if (inmw->mm_base == NULL)
5597f46c8b3SSerge Semin return -ENXIO;
5608b71d285SLogan Gunthorpe
5617f46c8b3SSerge Semin return simple_write_to_buffer(inmw->mm_base, inmw->size, offp,
5627f46c8b3SSerge Semin ubuf, size);
5638b71d285SLogan Gunthorpe }
5648b71d285SLogan Gunthorpe
5658b71d285SLogan Gunthorpe static TOOL_FOPS_RDWR(tool_mw_fops,
5668b71d285SLogan Gunthorpe tool_mw_read,
5678b71d285SLogan Gunthorpe tool_mw_write);
5688b71d285SLogan Gunthorpe
tool_setup_mw(struct tool_ctx * tc,int pidx,int widx,size_t req_size)5697f46c8b3SSerge Semin static int tool_setup_mw(struct tool_ctx *tc, int pidx, int widx,
5707f46c8b3SSerge Semin size_t req_size)
5718b71d285SLogan Gunthorpe {
5727f46c8b3SSerge Semin resource_size_t size, addr_align, size_align;
5737f46c8b3SSerge Semin struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
5747f46c8b3SSerge Semin char buf[TOOL_BUF_LEN];
5757f46c8b3SSerge Semin int ret;
5768b71d285SLogan Gunthorpe
5777f46c8b3SSerge Semin if (inmw->mm_base != NULL)
578717146a2SLogan Gunthorpe return 0;
579717146a2SLogan Gunthorpe
5807f46c8b3SSerge Semin ret = ntb_mw_get_align(tc->ntb, pidx, widx, &addr_align,
5817f46c8b3SSerge Semin &size_align, &size);
5827f46c8b3SSerge Semin if (ret)
5837f46c8b3SSerge Semin return ret;
584717146a2SLogan Gunthorpe
5857f46c8b3SSerge Semin inmw->size = min_t(resource_size_t, req_size, size);
5867f46c8b3SSerge Semin inmw->size = round_up(inmw->size, addr_align);
5877f46c8b3SSerge Semin inmw->size = round_up(inmw->size, size_align);
588433efe72SSanjay R Mehta inmw->mm_base = dma_alloc_coherent(&tc->ntb->pdev->dev, inmw->size,
5897f46c8b3SSerge Semin &inmw->dma_base, GFP_KERNEL);
5907f46c8b3SSerge Semin if (!inmw->mm_base)
591717146a2SLogan Gunthorpe return -ENOMEM;
592717146a2SLogan Gunthorpe
5937f46c8b3SSerge Semin if (!IS_ALIGNED(inmw->dma_base, addr_align)) {
5947f46c8b3SSerge Semin ret = -ENOMEM;
5957f46c8b3SSerge Semin goto err_free_dma;
5967f46c8b3SSerge Semin }
5977f46c8b3SSerge Semin
5987f46c8b3SSerge Semin ret = ntb_mw_set_trans(tc->ntb, pidx, widx, inmw->dma_base, inmw->size);
5997f46c8b3SSerge Semin if (ret)
600717146a2SLogan Gunthorpe goto err_free_dma;
601717146a2SLogan Gunthorpe
6027f46c8b3SSerge Semin snprintf(buf, sizeof(buf), "mw%d", widx);
6037f46c8b3SSerge Semin inmw->dbgfs_file = debugfs_create_file(buf, 0600,
6047f46c8b3SSerge Semin tc->peers[pidx].dbgfs_dir, inmw,
6057f46c8b3SSerge Semin &tool_mw_fops);
606717146a2SLogan Gunthorpe
607717146a2SLogan Gunthorpe return 0;
608717146a2SLogan Gunthorpe
609717146a2SLogan Gunthorpe err_free_dma:
610433efe72SSanjay R Mehta dma_free_coherent(&tc->ntb->pdev->dev, inmw->size, inmw->mm_base,
6117f46c8b3SSerge Semin inmw->dma_base);
6127f46c8b3SSerge Semin inmw->mm_base = NULL;
6137f46c8b3SSerge Semin inmw->dma_base = 0;
6147f46c8b3SSerge Semin inmw->size = 0;
615717146a2SLogan Gunthorpe
6167f46c8b3SSerge Semin return ret;
617717146a2SLogan Gunthorpe }
618717146a2SLogan Gunthorpe
tool_free_mw(struct tool_ctx * tc,int pidx,int widx)6197f46c8b3SSerge Semin static void tool_free_mw(struct tool_ctx *tc, int pidx, int widx)
620717146a2SLogan Gunthorpe {
6217f46c8b3SSerge Semin struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
622717146a2SLogan Gunthorpe
6237f46c8b3SSerge Semin debugfs_remove(inmw->dbgfs_file);
6247f46c8b3SSerge Semin
6257f46c8b3SSerge Semin if (inmw->mm_base != NULL) {
6267f46c8b3SSerge Semin ntb_mw_clear_trans(tc->ntb, pidx, widx);
627433efe72SSanjay R Mehta dma_free_coherent(&tc->ntb->pdev->dev, inmw->size,
6287f46c8b3SSerge Semin inmw->mm_base, inmw->dma_base);
629717146a2SLogan Gunthorpe }
630717146a2SLogan Gunthorpe
6317f46c8b3SSerge Semin inmw->mm_base = NULL;
6327f46c8b3SSerge Semin inmw->dma_base = 0;
6337f46c8b3SSerge Semin inmw->size = 0;
6347f46c8b3SSerge Semin inmw->dbgfs_file = NULL;
635717146a2SLogan Gunthorpe }
636717146a2SLogan Gunthorpe
tool_mw_trans_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)6377f46c8b3SSerge Semin static ssize_t tool_mw_trans_read(struct file *filep, char __user *ubuf,
638717146a2SLogan Gunthorpe size_t size, loff_t *offp)
639717146a2SLogan Gunthorpe {
6407f46c8b3SSerge Semin struct tool_mw *inmw = filep->private_data;
6417f46c8b3SSerge Semin resource_size_t addr_align;
6427f46c8b3SSerge Semin resource_size_t size_align;
6437f46c8b3SSerge Semin resource_size_t size_max;
644717146a2SLogan Gunthorpe ssize_t ret, off = 0;
6457f46c8b3SSerge Semin size_t buf_size;
6467f46c8b3SSerge Semin char *buf;
647717146a2SLogan Gunthorpe
648717146a2SLogan Gunthorpe buf_size = min_t(size_t, size, 512);
649717146a2SLogan Gunthorpe
650717146a2SLogan Gunthorpe buf = kmalloc(buf_size, GFP_KERNEL);
651717146a2SLogan Gunthorpe if (!buf)
652717146a2SLogan Gunthorpe return -ENOMEM;
653717146a2SLogan Gunthorpe
6547f46c8b3SSerge Semin ret = ntb_mw_get_align(inmw->tc->ntb, inmw->pidx, inmw->widx,
6557f46c8b3SSerge Semin &addr_align, &size_align, &size_max);
6567f46c8b3SSerge Semin if (ret)
6572e2bc5a9SColin Ian King goto err;
658717146a2SLogan Gunthorpe
659717146a2SLogan Gunthorpe off += scnprintf(buf + off, buf_size - off,
6607f46c8b3SSerge Semin "Inbound MW \t%d\n",
6617f46c8b3SSerge Semin inmw->widx);
662717146a2SLogan Gunthorpe
663717146a2SLogan Gunthorpe off += scnprintf(buf + off, buf_size - off,
6647f46c8b3SSerge Semin "Port \t%d (%d)\n",
6657f46c8b3SSerge Semin ntb_peer_port_number(inmw->tc->ntb, inmw->pidx),
6667f46c8b3SSerge Semin inmw->pidx);
667717146a2SLogan Gunthorpe
668717146a2SLogan Gunthorpe off += scnprintf(buf + off, buf_size - off,
6697f46c8b3SSerge Semin "Window Address \t0x%pK\n", inmw->mm_base);
670717146a2SLogan Gunthorpe
671717146a2SLogan Gunthorpe off += scnprintf(buf + off, buf_size - off,
6727f46c8b3SSerge Semin "DMA Address \t%pad\n",
6737f46c8b3SSerge Semin &inmw->dma_base);
674717146a2SLogan Gunthorpe
675717146a2SLogan Gunthorpe off += scnprintf(buf + off, buf_size - off,
6762ef97a6cSHelge Deller "Window Size \t%pap\n",
6777f46c8b3SSerge Semin &inmw->size);
678717146a2SLogan Gunthorpe
679717146a2SLogan Gunthorpe off += scnprintf(buf + off, buf_size - off,
6802ef97a6cSHelge Deller "Alignment \t%pap\n",
6817f46c8b3SSerge Semin &addr_align);
682443b9a14SSerge Semin
683443b9a14SSerge Semin off += scnprintf(buf + off, buf_size - off,
6842ef97a6cSHelge Deller "Size Alignment \t%pap\n",
6857f46c8b3SSerge Semin &size_align);
686717146a2SLogan Gunthorpe
687717146a2SLogan Gunthorpe off += scnprintf(buf + off, buf_size - off,
6882ef97a6cSHelge Deller "Size Max \t%pap\n",
6897f46c8b3SSerge Semin &size_max);
690717146a2SLogan Gunthorpe
691717146a2SLogan Gunthorpe ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
6922e2bc5a9SColin Ian King
6932e2bc5a9SColin Ian King err:
694717146a2SLogan Gunthorpe kfree(buf);
6957f46c8b3SSerge Semin
6967f46c8b3SSerge Semin return ret;
6977f46c8b3SSerge Semin }
6987f46c8b3SSerge Semin
tool_mw_trans_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)6997f46c8b3SSerge Semin static ssize_t tool_mw_trans_write(struct file *filep, const char __user *ubuf,
7007f46c8b3SSerge Semin size_t size, loff_t *offp)
7017f46c8b3SSerge Semin {
7027f46c8b3SSerge Semin struct tool_mw *inmw = filep->private_data;
7037f46c8b3SSerge Semin unsigned int val;
7047f46c8b3SSerge Semin int ret;
7057f46c8b3SSerge Semin
7067f46c8b3SSerge Semin ret = kstrtouint_from_user(ubuf, size, 0, &val);
7077f46c8b3SSerge Semin if (ret)
7087f46c8b3SSerge Semin return ret;
7097f46c8b3SSerge Semin
7107f46c8b3SSerge Semin tool_free_mw(inmw->tc, inmw->pidx, inmw->widx);
7117f46c8b3SSerge Semin if (val) {
7127f46c8b3SSerge Semin ret = tool_setup_mw(inmw->tc, inmw->pidx, inmw->widx, val);
7137f46c8b3SSerge Semin if (ret)
7147f46c8b3SSerge Semin return ret;
7157f46c8b3SSerge Semin }
7167f46c8b3SSerge Semin
7177f46c8b3SSerge Semin return size;
7187f46c8b3SSerge Semin }
7197f46c8b3SSerge Semin
7207f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_mw_trans_fops,
7217f46c8b3SSerge Semin tool_mw_trans_read,
7227f46c8b3SSerge Semin tool_mw_trans_write);
7237f46c8b3SSerge Semin
tool_peer_mw_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)7247f46c8b3SSerge Semin static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf,
7257f46c8b3SSerge Semin size_t size, loff_t *offp)
7267f46c8b3SSerge Semin {
7277f46c8b3SSerge Semin struct tool_mw *outmw = filep->private_data;
7287f46c8b3SSerge Semin loff_t pos = *offp;
7297f46c8b3SSerge Semin ssize_t ret;
7307f46c8b3SSerge Semin void *buf;
7317f46c8b3SSerge Semin
7327f46c8b3SSerge Semin if (outmw->io_base == NULL)
7337f46c8b3SSerge Semin return -EIO;
7347f46c8b3SSerge Semin
7357f46c8b3SSerge Semin if (pos >= outmw->size || !size)
7367f46c8b3SSerge Semin return 0;
7377f46c8b3SSerge Semin
7387f46c8b3SSerge Semin if (size > outmw->size - pos)
7397f46c8b3SSerge Semin size = outmw->size - pos;
7407f46c8b3SSerge Semin
7417f46c8b3SSerge Semin buf = kmalloc(size, GFP_KERNEL);
7427f46c8b3SSerge Semin if (!buf)
7437f46c8b3SSerge Semin return -ENOMEM;
7447f46c8b3SSerge Semin
7457f46c8b3SSerge Semin memcpy_fromio(buf, outmw->io_base + pos, size);
7467f46c8b3SSerge Semin ret = copy_to_user(ubuf, buf, size);
7477f46c8b3SSerge Semin if (ret == size) {
7487f46c8b3SSerge Semin ret = -EFAULT;
7497f46c8b3SSerge Semin goto err_free;
7507f46c8b3SSerge Semin }
7517f46c8b3SSerge Semin
7527f46c8b3SSerge Semin size -= ret;
7537f46c8b3SSerge Semin *offp = pos + size;
7547f46c8b3SSerge Semin ret = size;
7557f46c8b3SSerge Semin
7567f46c8b3SSerge Semin err_free:
7577f46c8b3SSerge Semin kfree(buf);
7587f46c8b3SSerge Semin
7597f46c8b3SSerge Semin return ret;
7607f46c8b3SSerge Semin }
7617f46c8b3SSerge Semin
tool_peer_mw_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)7627f46c8b3SSerge Semin static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf,
7637f46c8b3SSerge Semin size_t size, loff_t *offp)
7647f46c8b3SSerge Semin {
7657f46c8b3SSerge Semin struct tool_mw *outmw = filep->private_data;
7667f46c8b3SSerge Semin ssize_t ret;
7677f46c8b3SSerge Semin loff_t pos = *offp;
7687f46c8b3SSerge Semin void *buf;
7697f46c8b3SSerge Semin
7707f46c8b3SSerge Semin if (outmw->io_base == NULL)
7717f46c8b3SSerge Semin return -EIO;
7727f46c8b3SSerge Semin
7737f46c8b3SSerge Semin if (pos >= outmw->size || !size)
7747f46c8b3SSerge Semin return 0;
7757f46c8b3SSerge Semin if (size > outmw->size - pos)
7767f46c8b3SSerge Semin size = outmw->size - pos;
7777f46c8b3SSerge Semin
7787f46c8b3SSerge Semin buf = kmalloc(size, GFP_KERNEL);
7797f46c8b3SSerge Semin if (!buf)
7807f46c8b3SSerge Semin return -ENOMEM;
7817f46c8b3SSerge Semin
7827f46c8b3SSerge Semin ret = copy_from_user(buf, ubuf, size);
7837f46c8b3SSerge Semin if (ret == size) {
7847f46c8b3SSerge Semin ret = -EFAULT;
7857f46c8b3SSerge Semin goto err_free;
7867f46c8b3SSerge Semin }
7877f46c8b3SSerge Semin
7887f46c8b3SSerge Semin size -= ret;
7897f46c8b3SSerge Semin *offp = pos + size;
7907f46c8b3SSerge Semin ret = size;
7917f46c8b3SSerge Semin
7927f46c8b3SSerge Semin memcpy_toio(outmw->io_base + pos, buf, size);
7937f46c8b3SSerge Semin
7947f46c8b3SSerge Semin err_free:
7957f46c8b3SSerge Semin kfree(buf);
7967f46c8b3SSerge Semin
7977f46c8b3SSerge Semin return ret;
7987f46c8b3SSerge Semin }
7997f46c8b3SSerge Semin
8007f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_peer_mw_fops,
8017f46c8b3SSerge Semin tool_peer_mw_read,
8027f46c8b3SSerge Semin tool_peer_mw_write);
8037f46c8b3SSerge Semin
tool_setup_peer_mw(struct tool_ctx * tc,int pidx,int widx,u64 req_addr,size_t req_size)8047f46c8b3SSerge Semin static int tool_setup_peer_mw(struct tool_ctx *tc, int pidx, int widx,
8057f46c8b3SSerge Semin u64 req_addr, size_t req_size)
8067f46c8b3SSerge Semin {
8077f46c8b3SSerge Semin struct tool_mw *outmw = &tc->outmws[widx];
8087f46c8b3SSerge Semin resource_size_t map_size;
8097f46c8b3SSerge Semin phys_addr_t map_base;
8107f46c8b3SSerge Semin char buf[TOOL_BUF_LEN];
8117f46c8b3SSerge Semin int ret;
8127f46c8b3SSerge Semin
8137f46c8b3SSerge Semin if (outmw->io_base != NULL)
8147f46c8b3SSerge Semin return 0;
8157f46c8b3SSerge Semin
8167f46c8b3SSerge Semin ret = ntb_peer_mw_get_addr(tc->ntb, widx, &map_base, &map_size);
8177f46c8b3SSerge Semin if (ret)
8187f46c8b3SSerge Semin return ret;
8197f46c8b3SSerge Semin
8207f46c8b3SSerge Semin ret = ntb_peer_mw_set_trans(tc->ntb, pidx, widx, req_addr, req_size);
8217f46c8b3SSerge Semin if (ret)
8227f46c8b3SSerge Semin return ret;
8237f46c8b3SSerge Semin
8247f46c8b3SSerge Semin outmw->io_base = ioremap_wc(map_base, map_size);
8257f46c8b3SSerge Semin if (outmw->io_base == NULL) {
8267f46c8b3SSerge Semin ret = -EFAULT;
8277f46c8b3SSerge Semin goto err_clear_trans;
8287f46c8b3SSerge Semin }
8297f46c8b3SSerge Semin
8307f46c8b3SSerge Semin outmw->tr_base = req_addr;
8317f46c8b3SSerge Semin outmw->size = req_size;
8327f46c8b3SSerge Semin outmw->pidx = pidx;
8337f46c8b3SSerge Semin
8347f46c8b3SSerge Semin snprintf(buf, sizeof(buf), "peer_mw%d", widx);
8357f46c8b3SSerge Semin outmw->dbgfs_file = debugfs_create_file(buf, 0600,
8367f46c8b3SSerge Semin tc->peers[pidx].dbgfs_dir, outmw,
8377f46c8b3SSerge Semin &tool_peer_mw_fops);
8387f46c8b3SSerge Semin
8397f46c8b3SSerge Semin return 0;
8407f46c8b3SSerge Semin
8417f46c8b3SSerge Semin err_clear_trans:
8427f46c8b3SSerge Semin ntb_peer_mw_clear_trans(tc->ntb, pidx, widx);
8437f46c8b3SSerge Semin
8447f46c8b3SSerge Semin return ret;
8457f46c8b3SSerge Semin }
8467f46c8b3SSerge Semin
tool_free_peer_mw(struct tool_ctx * tc,int widx)8477f46c8b3SSerge Semin static void tool_free_peer_mw(struct tool_ctx *tc, int widx)
8487f46c8b3SSerge Semin {
8497f46c8b3SSerge Semin struct tool_mw *outmw = &tc->outmws[widx];
8507f46c8b3SSerge Semin
8517f46c8b3SSerge Semin debugfs_remove(outmw->dbgfs_file);
8527f46c8b3SSerge Semin
8537f46c8b3SSerge Semin if (outmw->io_base != NULL) {
8547f46c8b3SSerge Semin iounmap(tc->outmws[widx].io_base);
8557f46c8b3SSerge Semin ntb_peer_mw_clear_trans(tc->ntb, outmw->pidx, widx);
8567f46c8b3SSerge Semin }
8577f46c8b3SSerge Semin
8587f46c8b3SSerge Semin outmw->io_base = NULL;
8597f46c8b3SSerge Semin outmw->tr_base = 0;
8607f46c8b3SSerge Semin outmw->size = 0;
8617f46c8b3SSerge Semin outmw->pidx = -1;
8627f46c8b3SSerge Semin outmw->dbgfs_file = NULL;
8637f46c8b3SSerge Semin }
8647f46c8b3SSerge Semin
tool_peer_mw_trans_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)8657f46c8b3SSerge Semin static ssize_t tool_peer_mw_trans_read(struct file *filep, char __user *ubuf,
8667f46c8b3SSerge Semin size_t size, loff_t *offp)
8677f46c8b3SSerge Semin {
8687f46c8b3SSerge Semin struct tool_mw_wrap *outmw_wrap = filep->private_data;
8697f46c8b3SSerge Semin struct tool_mw *outmw = outmw_wrap->mw;
8707f46c8b3SSerge Semin resource_size_t map_size;
8717f46c8b3SSerge Semin phys_addr_t map_base;
8727f46c8b3SSerge Semin ssize_t off = 0;
8737f46c8b3SSerge Semin size_t buf_size;
8747f46c8b3SSerge Semin char *buf;
8757f46c8b3SSerge Semin int ret;
8767f46c8b3SSerge Semin
8777f46c8b3SSerge Semin ret = ntb_peer_mw_get_addr(outmw->tc->ntb, outmw->widx,
8787f46c8b3SSerge Semin &map_base, &map_size);
8797f46c8b3SSerge Semin if (ret)
8807f46c8b3SSerge Semin return ret;
8817f46c8b3SSerge Semin
8827f46c8b3SSerge Semin buf_size = min_t(size_t, size, 512);
8837f46c8b3SSerge Semin
8847f46c8b3SSerge Semin buf = kmalloc(buf_size, GFP_KERNEL);
8857f46c8b3SSerge Semin if (!buf)
8867f46c8b3SSerge Semin return -ENOMEM;
8877f46c8b3SSerge Semin
8887f46c8b3SSerge Semin off += scnprintf(buf + off, buf_size - off,
8897f46c8b3SSerge Semin "Outbound MW: \t%d\n", outmw->widx);
8907f46c8b3SSerge Semin
8917f46c8b3SSerge Semin if (outmw->io_base != NULL) {
8927f46c8b3SSerge Semin off += scnprintf(buf + off, buf_size - off,
8937f46c8b3SSerge Semin "Port attached \t%d (%d)\n",
8947f46c8b3SSerge Semin ntb_peer_port_number(outmw->tc->ntb, outmw->pidx),
8957f46c8b3SSerge Semin outmw->pidx);
8967f46c8b3SSerge Semin } else {
8977f46c8b3SSerge Semin off += scnprintf(buf + off, buf_size - off,
8987f46c8b3SSerge Semin "Port attached \t-1 (-1)\n");
8997f46c8b3SSerge Semin }
9007f46c8b3SSerge Semin
9017f46c8b3SSerge Semin off += scnprintf(buf + off, buf_size - off,
9027f46c8b3SSerge Semin "Virtual address \t0x%pK\n", outmw->io_base);
9037f46c8b3SSerge Semin
9047f46c8b3SSerge Semin off += scnprintf(buf + off, buf_size - off,
9052ef97a6cSHelge Deller "Phys Address \t%pap\n", &map_base);
9067f46c8b3SSerge Semin
9077f46c8b3SSerge Semin off += scnprintf(buf + off, buf_size - off,
9082ef97a6cSHelge Deller "Mapping Size \t%pap\n", &map_size);
9097f46c8b3SSerge Semin
9107f46c8b3SSerge Semin off += scnprintf(buf + off, buf_size - off,
9117f46c8b3SSerge Semin "Translation Address \t0x%016llx\n", outmw->tr_base);
9127f46c8b3SSerge Semin
9137f46c8b3SSerge Semin off += scnprintf(buf + off, buf_size - off,
9142ef97a6cSHelge Deller "Window Size \t%pap\n", &outmw->size);
9157f46c8b3SSerge Semin
9167f46c8b3SSerge Semin ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
9177f46c8b3SSerge Semin kfree(buf);
9187f46c8b3SSerge Semin
919717146a2SLogan Gunthorpe return ret;
920717146a2SLogan Gunthorpe }
921717146a2SLogan Gunthorpe
tool_peer_mw_trans_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)922717146a2SLogan Gunthorpe static ssize_t tool_peer_mw_trans_write(struct file *filep,
923717146a2SLogan Gunthorpe const char __user *ubuf,
924717146a2SLogan Gunthorpe size_t size, loff_t *offp)
925717146a2SLogan Gunthorpe {
9267f46c8b3SSerge Semin struct tool_mw_wrap *outmw_wrap = filep->private_data;
9277f46c8b3SSerge Semin struct tool_mw *outmw = outmw_wrap->mw;
9287f46c8b3SSerge Semin size_t buf_size, wsize;
9297f46c8b3SSerge Semin char buf[TOOL_BUF_LEN];
9307f46c8b3SSerge Semin int ret, n;
9317f46c8b3SSerge Semin u64 addr;
932717146a2SLogan Gunthorpe
933717146a2SLogan Gunthorpe buf_size = min(size, (sizeof(buf) - 1));
934717146a2SLogan Gunthorpe if (copy_from_user(buf, ubuf, buf_size))
935717146a2SLogan Gunthorpe return -EFAULT;
936717146a2SLogan Gunthorpe
937717146a2SLogan Gunthorpe buf[buf_size] = '\0';
938717146a2SLogan Gunthorpe
9397f46c8b3SSerge Semin n = sscanf(buf, "%lli:%zi", &addr, &wsize);
9407f46c8b3SSerge Semin if (n != 2)
9417f46c8b3SSerge Semin return -EINVAL;
942717146a2SLogan Gunthorpe
9437f46c8b3SSerge Semin tool_free_peer_mw(outmw->tc, outmw->widx);
9447f46c8b3SSerge Semin if (wsize) {
9457f46c8b3SSerge Semin ret = tool_setup_peer_mw(outmw->tc, outmw_wrap->pidx,
9467f46c8b3SSerge Semin outmw->widx, addr, wsize);
9477f46c8b3SSerge Semin if (ret)
9487f46c8b3SSerge Semin return ret;
9497f46c8b3SSerge Semin }
950717146a2SLogan Gunthorpe
951717146a2SLogan Gunthorpe return size;
952717146a2SLogan Gunthorpe }
953717146a2SLogan Gunthorpe
954717146a2SLogan Gunthorpe static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops,
955717146a2SLogan Gunthorpe tool_peer_mw_trans_read,
956717146a2SLogan Gunthorpe tool_peer_mw_trans_write);
957717146a2SLogan Gunthorpe
tool_init_mws(struct tool_ctx * tc)9587f46c8b3SSerge Semin static int tool_init_mws(struct tool_ctx *tc)
959717146a2SLogan Gunthorpe {
9607f46c8b3SSerge Semin int widx, pidx;
961717146a2SLogan Gunthorpe
9627f46c8b3SSerge Semin /* Initialize outbound memory windows */
9637f46c8b3SSerge Semin tc->outmw_cnt = ntb_peer_mw_count(tc->ntb);
9647f46c8b3SSerge Semin tc->outmws = devm_kcalloc(&tc->ntb->dev, tc->outmw_cnt,
9657f46c8b3SSerge Semin sizeof(*tc->outmws), GFP_KERNEL);
9667f46c8b3SSerge Semin if (tc->outmws == NULL)
9677f46c8b3SSerge Semin return -ENOMEM;
968717146a2SLogan Gunthorpe
9697f46c8b3SSerge Semin for (widx = 0; widx < tc->outmw_cnt; widx++) {
9707f46c8b3SSerge Semin tc->outmws[widx].widx = widx;
9717f46c8b3SSerge Semin tc->outmws[widx].pidx = -1;
9727f46c8b3SSerge Semin tc->outmws[widx].tc = tc;
9737f46c8b3SSerge Semin }
9747f46c8b3SSerge Semin
9757f46c8b3SSerge Semin /* Initialize inbound memory windows and outbound MWs wrapper */
9767f46c8b3SSerge Semin for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
9777f46c8b3SSerge Semin tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->ntb, pidx);
9787f46c8b3SSerge Semin tc->peers[pidx].inmws =
9797f46c8b3SSerge Semin devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].inmw_cnt,
9807f46c8b3SSerge Semin sizeof(*tc->peers[pidx].inmws), GFP_KERNEL);
9817f46c8b3SSerge Semin if (tc->peers[pidx].inmws == NULL)
9827f46c8b3SSerge Semin return -ENOMEM;
9837f46c8b3SSerge Semin
9847f46c8b3SSerge Semin for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) {
9857f46c8b3SSerge Semin tc->peers[pidx].inmws[widx].widx = widx;
9867f46c8b3SSerge Semin tc->peers[pidx].inmws[widx].pidx = pidx;
9877f46c8b3SSerge Semin tc->peers[pidx].inmws[widx].tc = tc;
9887f46c8b3SSerge Semin }
9897f46c8b3SSerge Semin
9907f46c8b3SSerge Semin tc->peers[pidx].outmw_cnt = ntb_peer_mw_count(tc->ntb);
9917f46c8b3SSerge Semin tc->peers[pidx].outmws =
9927f46c8b3SSerge Semin devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmw_cnt,
9937f46c8b3SSerge Semin sizeof(*tc->peers[pidx].outmws), GFP_KERNEL);
9942790143fSJiasheng Jiang if (tc->peers[pidx].outmws == NULL)
9952790143fSJiasheng Jiang return -ENOMEM;
9967f46c8b3SSerge Semin
9977f46c8b3SSerge Semin for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) {
9987f46c8b3SSerge Semin tc->peers[pidx].outmws[widx].pidx = pidx;
9997f46c8b3SSerge Semin tc->peers[pidx].outmws[widx].mw = &tc->outmws[widx];
10007f46c8b3SSerge Semin }
10017f46c8b3SSerge Semin }
1002717146a2SLogan Gunthorpe
1003717146a2SLogan Gunthorpe return 0;
1004717146a2SLogan Gunthorpe }
1005717146a2SLogan Gunthorpe
tool_clear_mws(struct tool_ctx * tc)10067f46c8b3SSerge Semin static void tool_clear_mws(struct tool_ctx *tc)
1007717146a2SLogan Gunthorpe {
10087f46c8b3SSerge Semin int widx, pidx;
1009717146a2SLogan Gunthorpe
10107f46c8b3SSerge Semin /* Free outbound memory windows */
10117f46c8b3SSerge Semin for (widx = 0; widx < tc->outmw_cnt; widx++)
10127f46c8b3SSerge Semin tool_free_peer_mw(tc, widx);
1013717146a2SLogan Gunthorpe
10147f46c8b3SSerge Semin /* Free outbound memory windows */
10157f46c8b3SSerge Semin for (pidx = 0; pidx < tc->peer_cnt; pidx++)
10167f46c8b3SSerge Semin for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++)
10177f46c8b3SSerge Semin tool_free_mw(tc, pidx, widx);
1018717146a2SLogan Gunthorpe }
1019717146a2SLogan Gunthorpe
10207f46c8b3SSerge Semin /*==============================================================================
10217f46c8b3SSerge Semin * Doorbell read/write methods
10227f46c8b3SSerge Semin *==============================================================================
10237f46c8b3SSerge Semin */
10247f46c8b3SSerge Semin
tool_db_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)10257f46c8b3SSerge Semin static ssize_t tool_db_read(struct file *filep, char __user *ubuf,
10267f46c8b3SSerge Semin size_t size, loff_t *offp)
1027578b881bSAllen Hubbe {
10287f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
10298b71d285SLogan Gunthorpe
10307f46c8b3SSerge Semin return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read);
1031578b881bSAllen Hubbe }
1032578b881bSAllen Hubbe
tool_db_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)10337f46c8b3SSerge Semin static ssize_t tool_db_write(struct file *filep, const char __user *ubuf,
10347f46c8b3SSerge Semin size_t size, loff_t *offp)
10357f46c8b3SSerge Semin {
10367f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
1037578b881bSAllen Hubbe
10387f46c8b3SSerge Semin return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set,
10397f46c8b3SSerge Semin tc->ntb->ops->db_clear);
10407f46c8b3SSerge Semin }
1041578b881bSAllen Hubbe
10427f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_db_fops,
10437f46c8b3SSerge Semin tool_db_read,
10447f46c8b3SSerge Semin tool_db_write);
1045578b881bSAllen Hubbe
tool_db_valid_mask_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)10467f46c8b3SSerge Semin static ssize_t tool_db_valid_mask_read(struct file *filep, char __user *ubuf,
10477f46c8b3SSerge Semin size_t size, loff_t *offp)
10487f46c8b3SSerge Semin {
10497f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
1050578b881bSAllen Hubbe
10517f46c8b3SSerge Semin return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_valid_mask);
10527f46c8b3SSerge Semin }
1053578b881bSAllen Hubbe
10547f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_db_valid_mask_fops,
10557f46c8b3SSerge Semin tool_db_valid_mask_read,
10567f46c8b3SSerge Semin NULL);
1057578b881bSAllen Hubbe
tool_db_mask_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)10587f46c8b3SSerge Semin static ssize_t tool_db_mask_read(struct file *filep, char __user *ubuf,
10597f46c8b3SSerge Semin size_t size, loff_t *offp)
10607f46c8b3SSerge Semin {
10617f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
10628b71d285SLogan Gunthorpe
10637f46c8b3SSerge Semin return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read_mask);
10647f46c8b3SSerge Semin }
1065bfcaa396SLogan Gunthorpe
tool_db_mask_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)10667f46c8b3SSerge Semin static ssize_t tool_db_mask_write(struct file *filep, const char __user *ubuf,
10677f46c8b3SSerge Semin size_t size, loff_t *offp)
10687f46c8b3SSerge Semin {
10697f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
1070bfcaa396SLogan Gunthorpe
10717f46c8b3SSerge Semin return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set_mask,
10727f46c8b3SSerge Semin tc->ntb->ops->db_clear_mask);
10737f46c8b3SSerge Semin }
10748b71d285SLogan Gunthorpe
10757f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_db_mask_fops,
10767f46c8b3SSerge Semin tool_db_mask_read,
10777f46c8b3SSerge Semin tool_db_mask_write);
10788b71d285SLogan Gunthorpe
tool_peer_db_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)10797f46c8b3SSerge Semin static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf,
10807f46c8b3SSerge Semin size_t size, loff_t *offp)
10817f46c8b3SSerge Semin {
10827f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
10837f46c8b3SSerge Semin
10847f46c8b3SSerge Semin return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->peer_db_read);
10857f46c8b3SSerge Semin }
10867f46c8b3SSerge Semin
tool_peer_db_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)10877f46c8b3SSerge Semin static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf,
10887f46c8b3SSerge Semin size_t size, loff_t *offp)
10897f46c8b3SSerge Semin {
10907f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
10917f46c8b3SSerge Semin
10927f46c8b3SSerge Semin return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->peer_db_set,
10937f46c8b3SSerge Semin tc->ntb->ops->peer_db_clear);
10947f46c8b3SSerge Semin }
10957f46c8b3SSerge Semin
10967f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_peer_db_fops,
10977f46c8b3SSerge Semin tool_peer_db_read,
10987f46c8b3SSerge Semin tool_peer_db_write);
10997f46c8b3SSerge Semin
tool_peer_db_mask_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)11007f46c8b3SSerge Semin static ssize_t tool_peer_db_mask_read(struct file *filep, char __user *ubuf,
11017f46c8b3SSerge Semin size_t size, loff_t *offp)
11027f46c8b3SSerge Semin {
11037f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
11047f46c8b3SSerge Semin
11057f46c8b3SSerge Semin return tool_fn_read(tc, ubuf, size, offp,
11067f46c8b3SSerge Semin tc->ntb->ops->peer_db_read_mask);
11077f46c8b3SSerge Semin }
11087f46c8b3SSerge Semin
tool_peer_db_mask_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)11097f46c8b3SSerge Semin static ssize_t tool_peer_db_mask_write(struct file *filep,
11107f46c8b3SSerge Semin const char __user *ubuf,
11117f46c8b3SSerge Semin size_t size, loff_t *offp)
11127f46c8b3SSerge Semin {
11137f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
11147f46c8b3SSerge Semin
11157f46c8b3SSerge Semin return tool_fn_write(tc, ubuf, size, offp,
11167f46c8b3SSerge Semin tc->ntb->ops->peer_db_set_mask,
11177f46c8b3SSerge Semin tc->ntb->ops->peer_db_clear_mask);
11187f46c8b3SSerge Semin }
11197f46c8b3SSerge Semin
11207f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_peer_db_mask_fops,
11217f46c8b3SSerge Semin tool_peer_db_mask_read,
11227f46c8b3SSerge Semin tool_peer_db_mask_write);
11237f46c8b3SSerge Semin
tool_db_event_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)11247f46c8b3SSerge Semin static ssize_t tool_db_event_write(struct file *filep,
11257f46c8b3SSerge Semin const char __user *ubuf,
11267f46c8b3SSerge Semin size_t size, loff_t *offp)
11277f46c8b3SSerge Semin {
11287f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
11297f46c8b3SSerge Semin u64 val;
11307f46c8b3SSerge Semin int ret;
11317f46c8b3SSerge Semin
11327f46c8b3SSerge Semin ret = kstrtou64_from_user(ubuf, size, 0, &val);
11337f46c8b3SSerge Semin if (ret)
11347f46c8b3SSerge Semin return ret;
11357f46c8b3SSerge Semin
11367f46c8b3SSerge Semin if (wait_event_interruptible(tc->db_wq, ntb_db_read(tc->ntb) == val))
11377f46c8b3SSerge Semin return -ERESTART;
11387f46c8b3SSerge Semin
11397f46c8b3SSerge Semin return size;
11407f46c8b3SSerge Semin }
11417f46c8b3SSerge Semin
11427f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_db_event_fops,
11437f46c8b3SSerge Semin NULL,
11447f46c8b3SSerge Semin tool_db_event_write);
11457f46c8b3SSerge Semin
11467f46c8b3SSerge Semin /*==============================================================================
11477f46c8b3SSerge Semin * Scratchpads read/write methods
11487f46c8b3SSerge Semin *==============================================================================
11497f46c8b3SSerge Semin */
11507f46c8b3SSerge Semin
tool_spad_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)11517f46c8b3SSerge Semin static ssize_t tool_spad_read(struct file *filep, char __user *ubuf,
11527f46c8b3SSerge Semin size_t size, loff_t *offp)
11537f46c8b3SSerge Semin {
11547f46c8b3SSerge Semin struct tool_spad *spad = filep->private_data;
11557f46c8b3SSerge Semin char buf[TOOL_BUF_LEN];
11567f46c8b3SSerge Semin ssize_t pos;
11577f46c8b3SSerge Semin
11587f46c8b3SSerge Semin if (!spad->tc->ntb->ops->spad_read)
11597f46c8b3SSerge Semin return -EINVAL;
11607f46c8b3SSerge Semin
11617f46c8b3SSerge Semin pos = scnprintf(buf, sizeof(buf), "%#x\n",
11627f46c8b3SSerge Semin ntb_spad_read(spad->tc->ntb, spad->sidx));
11637f46c8b3SSerge Semin
11647f46c8b3SSerge Semin return simple_read_from_buffer(ubuf, size, offp, buf, pos);
11657f46c8b3SSerge Semin }
11667f46c8b3SSerge Semin
tool_spad_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)11677f46c8b3SSerge Semin static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
11687f46c8b3SSerge Semin size_t size, loff_t *offp)
11697f46c8b3SSerge Semin {
11707f46c8b3SSerge Semin struct tool_spad *spad = filep->private_data;
11717f46c8b3SSerge Semin u32 val;
11727f46c8b3SSerge Semin int ret;
11737f46c8b3SSerge Semin
11747f46c8b3SSerge Semin if (!spad->tc->ntb->ops->spad_write) {
11757f46c8b3SSerge Semin dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n");
11767f46c8b3SSerge Semin return -EINVAL;
11777f46c8b3SSerge Semin }
11787f46c8b3SSerge Semin
11797f46c8b3SSerge Semin ret = kstrtou32_from_user(ubuf, size, 0, &val);
11807f46c8b3SSerge Semin if (ret)
11817f46c8b3SSerge Semin return ret;
11827f46c8b3SSerge Semin
11837f46c8b3SSerge Semin ret = ntb_spad_write(spad->tc->ntb, spad->sidx, val);
11847f46c8b3SSerge Semin
11857f46c8b3SSerge Semin return ret ?: size;
11867f46c8b3SSerge Semin }
11877f46c8b3SSerge Semin
11887f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_spad_fops,
11897f46c8b3SSerge Semin tool_spad_read,
11907f46c8b3SSerge Semin tool_spad_write);
11917f46c8b3SSerge Semin
tool_peer_spad_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)11927f46c8b3SSerge Semin static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
11937f46c8b3SSerge Semin size_t size, loff_t *offp)
11947f46c8b3SSerge Semin {
11957f46c8b3SSerge Semin struct tool_spad *spad = filep->private_data;
11967f46c8b3SSerge Semin char buf[TOOL_BUF_LEN];
11977f46c8b3SSerge Semin ssize_t pos;
11987f46c8b3SSerge Semin
11997f46c8b3SSerge Semin if (!spad->tc->ntb->ops->peer_spad_read)
12007f46c8b3SSerge Semin return -EINVAL;
12017f46c8b3SSerge Semin
12027f46c8b3SSerge Semin pos = scnprintf(buf, sizeof(buf), "%#x\n",
12037f46c8b3SSerge Semin ntb_peer_spad_read(spad->tc->ntb, spad->pidx, spad->sidx));
12047f46c8b3SSerge Semin
12057f46c8b3SSerge Semin return simple_read_from_buffer(ubuf, size, offp, buf, pos);
12067f46c8b3SSerge Semin }
12077f46c8b3SSerge Semin
tool_peer_spad_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)12087f46c8b3SSerge Semin static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
12097f46c8b3SSerge Semin size_t size, loff_t *offp)
12107f46c8b3SSerge Semin {
12117f46c8b3SSerge Semin struct tool_spad *spad = filep->private_data;
12127f46c8b3SSerge Semin u32 val;
12137f46c8b3SSerge Semin int ret;
12147f46c8b3SSerge Semin
12157f46c8b3SSerge Semin if (!spad->tc->ntb->ops->peer_spad_write) {
12167f46c8b3SSerge Semin dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n");
12177f46c8b3SSerge Semin return -EINVAL;
12187f46c8b3SSerge Semin }
12197f46c8b3SSerge Semin
12207f46c8b3SSerge Semin ret = kstrtou32_from_user(ubuf, size, 0, &val);
12217f46c8b3SSerge Semin if (ret)
12227f46c8b3SSerge Semin return ret;
12237f46c8b3SSerge Semin
12247f46c8b3SSerge Semin ret = ntb_peer_spad_write(spad->tc->ntb, spad->pidx, spad->sidx, val);
12257f46c8b3SSerge Semin
12267f46c8b3SSerge Semin return ret ?: size;
12277f46c8b3SSerge Semin }
12287f46c8b3SSerge Semin
12297f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_peer_spad_fops,
12307f46c8b3SSerge Semin tool_peer_spad_read,
12317f46c8b3SSerge Semin tool_peer_spad_write);
12327f46c8b3SSerge Semin
tool_init_spads(struct tool_ctx * tc)12337f46c8b3SSerge Semin static int tool_init_spads(struct tool_ctx *tc)
12347f46c8b3SSerge Semin {
12357f46c8b3SSerge Semin int sidx, pidx;
12367f46c8b3SSerge Semin
12377f46c8b3SSerge Semin /* Initialize inbound scratchpad structures */
12387f46c8b3SSerge Semin tc->inspad_cnt = ntb_spad_count(tc->ntb);
12397f46c8b3SSerge Semin tc->inspads = devm_kcalloc(&tc->ntb->dev, tc->inspad_cnt,
12407f46c8b3SSerge Semin sizeof(*tc->inspads), GFP_KERNEL);
12417f46c8b3SSerge Semin if (tc->inspads == NULL)
12427f46c8b3SSerge Semin return -ENOMEM;
12437f46c8b3SSerge Semin
12447f46c8b3SSerge Semin for (sidx = 0; sidx < tc->inspad_cnt; sidx++) {
12457f46c8b3SSerge Semin tc->inspads[sidx].sidx = sidx;
12467f46c8b3SSerge Semin tc->inspads[sidx].pidx = -1;
12477f46c8b3SSerge Semin tc->inspads[sidx].tc = tc;
12487f46c8b3SSerge Semin }
12497f46c8b3SSerge Semin
12507f46c8b3SSerge Semin /* Initialize outbound scratchpad structures */
12517f46c8b3SSerge Semin for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
12527f46c8b3SSerge Semin tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->ntb);
12537f46c8b3SSerge Semin tc->peers[pidx].outspads =
12547f46c8b3SSerge Semin devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outspad_cnt,
12557f46c8b3SSerge Semin sizeof(*tc->peers[pidx].outspads), GFP_KERNEL);
12567f46c8b3SSerge Semin if (tc->peers[pidx].outspads == NULL)
12577f46c8b3SSerge Semin return -ENOMEM;
12587f46c8b3SSerge Semin
12597f46c8b3SSerge Semin for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) {
12607f46c8b3SSerge Semin tc->peers[pidx].outspads[sidx].sidx = sidx;
12617f46c8b3SSerge Semin tc->peers[pidx].outspads[sidx].pidx = pidx;
12627f46c8b3SSerge Semin tc->peers[pidx].outspads[sidx].tc = tc;
12638b71d285SLogan Gunthorpe }
1264578b881bSAllen Hubbe }
1265578b881bSAllen Hubbe
12667f46c8b3SSerge Semin return 0;
12677f46c8b3SSerge Semin }
12687f46c8b3SSerge Semin
12697f46c8b3SSerge Semin /*==============================================================================
12707f46c8b3SSerge Semin * Messages read/write methods
12717f46c8b3SSerge Semin *==============================================================================
12727f46c8b3SSerge Semin */
12737f46c8b3SSerge Semin
tool_inmsg_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)12747f46c8b3SSerge Semin static ssize_t tool_inmsg_read(struct file *filep, char __user *ubuf,
12757f46c8b3SSerge Semin size_t size, loff_t *offp)
12767f46c8b3SSerge Semin {
12777f46c8b3SSerge Semin struct tool_msg *msg = filep->private_data;
12787f46c8b3SSerge Semin char buf[TOOL_BUF_LEN];
12797f46c8b3SSerge Semin ssize_t pos;
12807f46c8b3SSerge Semin u32 data;
12817f46c8b3SSerge Semin int pidx;
12827f46c8b3SSerge Semin
12837f46c8b3SSerge Semin data = ntb_msg_read(msg->tc->ntb, &pidx, msg->midx);
12847f46c8b3SSerge Semin
12857f46c8b3SSerge Semin pos = scnprintf(buf, sizeof(buf), "0x%08x<-%d\n", data, pidx);
12867f46c8b3SSerge Semin
12877f46c8b3SSerge Semin return simple_read_from_buffer(ubuf, size, offp, buf, pos);
12887f46c8b3SSerge Semin }
12897f46c8b3SSerge Semin
12907f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_inmsg_fops,
12917f46c8b3SSerge Semin tool_inmsg_read,
12927f46c8b3SSerge Semin NULL);
12937f46c8b3SSerge Semin
tool_outmsg_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)12947f46c8b3SSerge Semin static ssize_t tool_outmsg_write(struct file *filep,
12957f46c8b3SSerge Semin const char __user *ubuf,
12967f46c8b3SSerge Semin size_t size, loff_t *offp)
12977f46c8b3SSerge Semin {
12987f46c8b3SSerge Semin struct tool_msg *msg = filep->private_data;
12997f46c8b3SSerge Semin u32 val;
13007f46c8b3SSerge Semin int ret;
13017f46c8b3SSerge Semin
13027f46c8b3SSerge Semin ret = kstrtou32_from_user(ubuf, size, 0, &val);
13037f46c8b3SSerge Semin if (ret)
13047f46c8b3SSerge Semin return ret;
13057f46c8b3SSerge Semin
13067f46c8b3SSerge Semin ret = ntb_peer_msg_write(msg->tc->ntb, msg->pidx, msg->midx, val);
13077f46c8b3SSerge Semin
13087f46c8b3SSerge Semin return ret ? : size;
13097f46c8b3SSerge Semin }
13107f46c8b3SSerge Semin
13117f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_outmsg_fops,
13127f46c8b3SSerge Semin NULL,
13137f46c8b3SSerge Semin tool_outmsg_write);
13147f46c8b3SSerge Semin
tool_msg_sts_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)13157f46c8b3SSerge Semin static ssize_t tool_msg_sts_read(struct file *filep, char __user *ubuf,
13167f46c8b3SSerge Semin size_t size, loff_t *offp)
13177f46c8b3SSerge Semin {
13187f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
13197f46c8b3SSerge Semin
13207f46c8b3SSerge Semin return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_read_sts);
13217f46c8b3SSerge Semin }
13227f46c8b3SSerge Semin
tool_msg_sts_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)13237f46c8b3SSerge Semin static ssize_t tool_msg_sts_write(struct file *filep, const char __user *ubuf,
13247f46c8b3SSerge Semin size_t size, loff_t *offp)
13257f46c8b3SSerge Semin {
13267f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
13277f46c8b3SSerge Semin
13287f46c8b3SSerge Semin return tool_fn_write(tc, ubuf, size, offp, NULL,
13297f46c8b3SSerge Semin tc->ntb->ops->msg_clear_sts);
13307f46c8b3SSerge Semin }
13317f46c8b3SSerge Semin
13327f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_msg_sts_fops,
13337f46c8b3SSerge Semin tool_msg_sts_read,
13347f46c8b3SSerge Semin tool_msg_sts_write);
13357f46c8b3SSerge Semin
tool_msg_inbits_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)13367f46c8b3SSerge Semin static ssize_t tool_msg_inbits_read(struct file *filep, char __user *ubuf,
13377f46c8b3SSerge Semin size_t size, loff_t *offp)
13387f46c8b3SSerge Semin {
13397f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
13407f46c8b3SSerge Semin
13417f46c8b3SSerge Semin return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_inbits);
13427f46c8b3SSerge Semin }
13437f46c8b3SSerge Semin
13447f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_msg_inbits_fops,
13457f46c8b3SSerge Semin tool_msg_inbits_read,
13467f46c8b3SSerge Semin NULL);
13477f46c8b3SSerge Semin
tool_msg_outbits_read(struct file * filep,char __user * ubuf,size_t size,loff_t * offp)13487f46c8b3SSerge Semin static ssize_t tool_msg_outbits_read(struct file *filep, char __user *ubuf,
13497f46c8b3SSerge Semin size_t size, loff_t *offp)
13507f46c8b3SSerge Semin {
13517f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
13527f46c8b3SSerge Semin
13537f46c8b3SSerge Semin return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_outbits);
13547f46c8b3SSerge Semin }
13557f46c8b3SSerge Semin
13567f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_msg_outbits_fops,
13577f46c8b3SSerge Semin tool_msg_outbits_read,
13587f46c8b3SSerge Semin NULL);
13597f46c8b3SSerge Semin
tool_msg_mask_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)13607f46c8b3SSerge Semin static ssize_t tool_msg_mask_write(struct file *filep, const char __user *ubuf,
13617f46c8b3SSerge Semin size_t size, loff_t *offp)
13627f46c8b3SSerge Semin {
13637f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
13647f46c8b3SSerge Semin
13657f46c8b3SSerge Semin return tool_fn_write(tc, ubuf, size, offp,
13667f46c8b3SSerge Semin tc->ntb->ops->msg_set_mask,
13677f46c8b3SSerge Semin tc->ntb->ops->msg_clear_mask);
13687f46c8b3SSerge Semin }
13697f46c8b3SSerge Semin
13707f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_msg_mask_fops,
13717f46c8b3SSerge Semin NULL,
13727f46c8b3SSerge Semin tool_msg_mask_write);
13737f46c8b3SSerge Semin
tool_msg_event_write(struct file * filep,const char __user * ubuf,size_t size,loff_t * offp)13747f46c8b3SSerge Semin static ssize_t tool_msg_event_write(struct file *filep,
13757f46c8b3SSerge Semin const char __user *ubuf,
13767f46c8b3SSerge Semin size_t size, loff_t *offp)
13777f46c8b3SSerge Semin {
13787f46c8b3SSerge Semin struct tool_ctx *tc = filep->private_data;
13797f46c8b3SSerge Semin u64 val;
13807f46c8b3SSerge Semin int ret;
13817f46c8b3SSerge Semin
13827f46c8b3SSerge Semin ret = kstrtou64_from_user(ubuf, size, 0, &val);
13837f46c8b3SSerge Semin if (ret)
13847f46c8b3SSerge Semin return ret;
13857f46c8b3SSerge Semin
13867f46c8b3SSerge Semin if (wait_event_interruptible(tc->msg_wq,
13877f46c8b3SSerge Semin ntb_msg_read_sts(tc->ntb) == val))
13887f46c8b3SSerge Semin return -ERESTART;
13897f46c8b3SSerge Semin
13907f46c8b3SSerge Semin return size;
13917f46c8b3SSerge Semin }
13927f46c8b3SSerge Semin
13937f46c8b3SSerge Semin static TOOL_FOPS_RDWR(tool_msg_event_fops,
13947f46c8b3SSerge Semin NULL,
13957f46c8b3SSerge Semin tool_msg_event_write);
13967f46c8b3SSerge Semin
tool_init_msgs(struct tool_ctx * tc)13977f46c8b3SSerge Semin static int tool_init_msgs(struct tool_ctx *tc)
13987f46c8b3SSerge Semin {
13997f46c8b3SSerge Semin int midx, pidx;
14007f46c8b3SSerge Semin
14017f46c8b3SSerge Semin /* Initialize inbound message structures */
14027f46c8b3SSerge Semin tc->inmsg_cnt = ntb_msg_count(tc->ntb);
14037f46c8b3SSerge Semin tc->inmsgs = devm_kcalloc(&tc->ntb->dev, tc->inmsg_cnt,
14047f46c8b3SSerge Semin sizeof(*tc->inmsgs), GFP_KERNEL);
14057f46c8b3SSerge Semin if (tc->inmsgs == NULL)
14067f46c8b3SSerge Semin return -ENOMEM;
14077f46c8b3SSerge Semin
14087f46c8b3SSerge Semin for (midx = 0; midx < tc->inmsg_cnt; midx++) {
14097f46c8b3SSerge Semin tc->inmsgs[midx].midx = midx;
14107f46c8b3SSerge Semin tc->inmsgs[midx].pidx = -1;
14117f46c8b3SSerge Semin tc->inmsgs[midx].tc = tc;
14127f46c8b3SSerge Semin }
14137f46c8b3SSerge Semin
14147f46c8b3SSerge Semin /* Initialize outbound message structures */
14157f46c8b3SSerge Semin for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
14167f46c8b3SSerge Semin tc->peers[pidx].outmsg_cnt = ntb_msg_count(tc->ntb);
14177f46c8b3SSerge Semin tc->peers[pidx].outmsgs =
14187f46c8b3SSerge Semin devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmsg_cnt,
14197f46c8b3SSerge Semin sizeof(*tc->peers[pidx].outmsgs), GFP_KERNEL);
14207f46c8b3SSerge Semin if (tc->peers[pidx].outmsgs == NULL)
14217f46c8b3SSerge Semin return -ENOMEM;
14227f46c8b3SSerge Semin
14237f46c8b3SSerge Semin for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) {
14247f46c8b3SSerge Semin tc->peers[pidx].outmsgs[midx].midx = midx;
14257f46c8b3SSerge Semin tc->peers[pidx].outmsgs[midx].pidx = pidx;
14267f46c8b3SSerge Semin tc->peers[pidx].outmsgs[midx].tc = tc;
14277f46c8b3SSerge Semin }
14287f46c8b3SSerge Semin }
14297f46c8b3SSerge Semin
14307f46c8b3SSerge Semin return 0;
14317f46c8b3SSerge Semin }
14327f46c8b3SSerge Semin
14337f46c8b3SSerge Semin /*==============================================================================
14347f46c8b3SSerge Semin * Initialization methods
14357f46c8b3SSerge Semin *==============================================================================
14367f46c8b3SSerge Semin */
14377f46c8b3SSerge Semin
tool_create_data(struct ntb_dev * ntb)14387f46c8b3SSerge Semin static struct tool_ctx *tool_create_data(struct ntb_dev *ntb)
1439578b881bSAllen Hubbe {
1440578b881bSAllen Hubbe struct tool_ctx *tc;
1441578b881bSAllen Hubbe
14427f46c8b3SSerge Semin tc = devm_kzalloc(&ntb->dev, sizeof(*tc), GFP_KERNEL);
14437f46c8b3SSerge Semin if (tc == NULL)
14447f46c8b3SSerge Semin return ERR_PTR(-ENOMEM);
1445443b9a14SSerge Semin
14467f46c8b3SSerge Semin tc->ntb = ntb;
14477f46c8b3SSerge Semin init_waitqueue_head(&tc->link_wq);
14487f46c8b3SSerge Semin init_waitqueue_head(&tc->db_wq);
14497f46c8b3SSerge Semin init_waitqueue_head(&tc->msg_wq);
1450d67288a3SSerge Semin
1451578b881bSAllen Hubbe if (ntb_db_is_unsafe(ntb))
1452578b881bSAllen Hubbe dev_dbg(&ntb->dev, "doorbell is unsafe\n");
1453578b881bSAllen Hubbe
1454578b881bSAllen Hubbe if (ntb_spad_is_unsafe(ntb))
1455578b881bSAllen Hubbe dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
1456578b881bSAllen Hubbe
14577f46c8b3SSerge Semin return tc;
1458578b881bSAllen Hubbe }
1459578b881bSAllen Hubbe
tool_clear_data(struct tool_ctx * tc)14607f46c8b3SSerge Semin static void tool_clear_data(struct tool_ctx *tc)
14617f46c8b3SSerge Semin {
14627f46c8b3SSerge Semin wake_up(&tc->link_wq);
14637f46c8b3SSerge Semin wake_up(&tc->db_wq);
14647f46c8b3SSerge Semin wake_up(&tc->msg_wq);
1465717146a2SLogan Gunthorpe }
1466578b881bSAllen Hubbe
tool_init_ntb(struct tool_ctx * tc)14677f46c8b3SSerge Semin static int tool_init_ntb(struct tool_ctx *tc)
14687f46c8b3SSerge Semin {
14697f46c8b3SSerge Semin return ntb_set_ctx(tc->ntb, tc, &tool_ops);
14707f46c8b3SSerge Semin }
14717f46c8b3SSerge Semin
tool_clear_ntb(struct tool_ctx * tc)14727f46c8b3SSerge Semin static void tool_clear_ntb(struct tool_ctx *tc)
14737f46c8b3SSerge Semin {
14747f46c8b3SSerge Semin ntb_clear_ctx(tc->ntb);
14757f46c8b3SSerge Semin ntb_link_disable(tc->ntb);
14767f46c8b3SSerge Semin }
14777f46c8b3SSerge Semin
tool_setup_dbgfs(struct tool_ctx * tc)14787f46c8b3SSerge Semin static void tool_setup_dbgfs(struct tool_ctx *tc)
14797f46c8b3SSerge Semin {
14807f46c8b3SSerge Semin int pidx, widx, sidx, midx;
14817f46c8b3SSerge Semin char buf[TOOL_BUF_LEN];
14827f46c8b3SSerge Semin
14837f46c8b3SSerge Semin /* This modules is useless without dbgfs... */
14847f46c8b3SSerge Semin if (!tool_dbgfs_topdir) {
14857f46c8b3SSerge Semin tc->dbgfs_dir = NULL;
14867f46c8b3SSerge Semin return;
14877f46c8b3SSerge Semin }
14887f46c8b3SSerge Semin
14897f46c8b3SSerge Semin tc->dbgfs_dir = debugfs_create_dir(dev_name(&tc->ntb->dev),
14907f46c8b3SSerge Semin tool_dbgfs_topdir);
14917f46c8b3SSerge Semin
14927f46c8b3SSerge Semin debugfs_create_file("port", 0600, tc->dbgfs_dir,
14937f46c8b3SSerge Semin tc, &tool_port_fops);
14947f46c8b3SSerge Semin
14957f46c8b3SSerge Semin debugfs_create_file("link", 0600, tc->dbgfs_dir,
14967f46c8b3SSerge Semin tc, &tool_link_fops);
14977f46c8b3SSerge Semin
14987f46c8b3SSerge Semin debugfs_create_file("db", 0600, tc->dbgfs_dir,
14997f46c8b3SSerge Semin tc, &tool_db_fops);
15007f46c8b3SSerge Semin
15017f46c8b3SSerge Semin debugfs_create_file("db_valid_mask", 0600, tc->dbgfs_dir,
15027f46c8b3SSerge Semin tc, &tool_db_valid_mask_fops);
15037f46c8b3SSerge Semin
15047f46c8b3SSerge Semin debugfs_create_file("db_mask", 0600, tc->dbgfs_dir,
15057f46c8b3SSerge Semin tc, &tool_db_mask_fops);
15067f46c8b3SSerge Semin
15077f46c8b3SSerge Semin debugfs_create_file("db_event", 0600, tc->dbgfs_dir,
15087f46c8b3SSerge Semin tc, &tool_db_event_fops);
15097f46c8b3SSerge Semin
15107f46c8b3SSerge Semin debugfs_create_file("peer_db", 0600, tc->dbgfs_dir,
15117f46c8b3SSerge Semin tc, &tool_peer_db_fops);
15127f46c8b3SSerge Semin
15137f46c8b3SSerge Semin debugfs_create_file("peer_db_mask", 0600, tc->dbgfs_dir,
15147f46c8b3SSerge Semin tc, &tool_peer_db_mask_fops);
15157f46c8b3SSerge Semin
15167f46c8b3SSerge Semin if (tc->inspad_cnt != 0) {
15177f46c8b3SSerge Semin for (sidx = 0; sidx < tc->inspad_cnt; sidx++) {
15187f46c8b3SSerge Semin snprintf(buf, sizeof(buf), "spad%d", sidx);
15197f46c8b3SSerge Semin
15207f46c8b3SSerge Semin debugfs_create_file(buf, 0600, tc->dbgfs_dir,
15217f46c8b3SSerge Semin &tc->inspads[sidx], &tool_spad_fops);
15227f46c8b3SSerge Semin }
15237f46c8b3SSerge Semin }
15247f46c8b3SSerge Semin
15257f46c8b3SSerge Semin if (tc->inmsg_cnt != 0) {
15267f46c8b3SSerge Semin for (midx = 0; midx < tc->inmsg_cnt; midx++) {
15277f46c8b3SSerge Semin snprintf(buf, sizeof(buf), "msg%d", midx);
15287f46c8b3SSerge Semin debugfs_create_file(buf, 0600, tc->dbgfs_dir,
15297f46c8b3SSerge Semin &tc->inmsgs[midx], &tool_inmsg_fops);
15307f46c8b3SSerge Semin }
15317f46c8b3SSerge Semin
15327f46c8b3SSerge Semin debugfs_create_file("msg_sts", 0600, tc->dbgfs_dir,
15337f46c8b3SSerge Semin tc, &tool_msg_sts_fops);
15347f46c8b3SSerge Semin
15357f46c8b3SSerge Semin debugfs_create_file("msg_inbits", 0600, tc->dbgfs_dir,
15367f46c8b3SSerge Semin tc, &tool_msg_inbits_fops);
15377f46c8b3SSerge Semin
15387f46c8b3SSerge Semin debugfs_create_file("msg_outbits", 0600, tc->dbgfs_dir,
15397f46c8b3SSerge Semin tc, &tool_msg_outbits_fops);
15407f46c8b3SSerge Semin
15417f46c8b3SSerge Semin debugfs_create_file("msg_mask", 0600, tc->dbgfs_dir,
15427f46c8b3SSerge Semin tc, &tool_msg_mask_fops);
15437f46c8b3SSerge Semin
15447f46c8b3SSerge Semin debugfs_create_file("msg_event", 0600, tc->dbgfs_dir,
15457f46c8b3SSerge Semin tc, &tool_msg_event_fops);
15467f46c8b3SSerge Semin }
15477f46c8b3SSerge Semin
15487f46c8b3SSerge Semin for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
15497f46c8b3SSerge Semin snprintf(buf, sizeof(buf), "peer%d", pidx);
15507f46c8b3SSerge Semin tc->peers[pidx].dbgfs_dir =
15517f46c8b3SSerge Semin debugfs_create_dir(buf, tc->dbgfs_dir);
15527f46c8b3SSerge Semin
15537f46c8b3SSerge Semin debugfs_create_file("port", 0600,
15547f46c8b3SSerge Semin tc->peers[pidx].dbgfs_dir,
15557f46c8b3SSerge Semin &tc->peers[pidx], &tool_peer_port_fops);
15567f46c8b3SSerge Semin
15577f46c8b3SSerge Semin debugfs_create_file("link", 0200,
15587f46c8b3SSerge Semin tc->peers[pidx].dbgfs_dir,
15597f46c8b3SSerge Semin &tc->peers[pidx], &tool_peer_link_fops);
15607f46c8b3SSerge Semin
15617f46c8b3SSerge Semin debugfs_create_file("link_event", 0200,
15627f46c8b3SSerge Semin tc->peers[pidx].dbgfs_dir,
15637f46c8b3SSerge Semin &tc->peers[pidx], &tool_peer_link_event_fops);
15647f46c8b3SSerge Semin
15657f46c8b3SSerge Semin for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) {
15667f46c8b3SSerge Semin snprintf(buf, sizeof(buf), "mw_trans%d", widx);
15677f46c8b3SSerge Semin debugfs_create_file(buf, 0600,
15687f46c8b3SSerge Semin tc->peers[pidx].dbgfs_dir,
15697f46c8b3SSerge Semin &tc->peers[pidx].inmws[widx],
15707f46c8b3SSerge Semin &tool_mw_trans_fops);
15717f46c8b3SSerge Semin }
15727f46c8b3SSerge Semin
15737f46c8b3SSerge Semin for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) {
15747f46c8b3SSerge Semin snprintf(buf, sizeof(buf), "peer_mw_trans%d", widx);
15757f46c8b3SSerge Semin debugfs_create_file(buf, 0600,
15767f46c8b3SSerge Semin tc->peers[pidx].dbgfs_dir,
15777f46c8b3SSerge Semin &tc->peers[pidx].outmws[widx],
15787f46c8b3SSerge Semin &tool_peer_mw_trans_fops);
15797f46c8b3SSerge Semin }
15807f46c8b3SSerge Semin
15817f46c8b3SSerge Semin for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) {
15827f46c8b3SSerge Semin snprintf(buf, sizeof(buf), "spad%d", sidx);
15837f46c8b3SSerge Semin
15847f46c8b3SSerge Semin debugfs_create_file(buf, 0600,
15857f46c8b3SSerge Semin tc->peers[pidx].dbgfs_dir,
15867f46c8b3SSerge Semin &tc->peers[pidx].outspads[sidx],
15877f46c8b3SSerge Semin &tool_peer_spad_fops);
15887f46c8b3SSerge Semin }
15897f46c8b3SSerge Semin
15907f46c8b3SSerge Semin for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) {
15917f46c8b3SSerge Semin snprintf(buf, sizeof(buf), "msg%d", midx);
15927f46c8b3SSerge Semin debugfs_create_file(buf, 0600,
15937f46c8b3SSerge Semin tc->peers[pidx].dbgfs_dir,
15947f46c8b3SSerge Semin &tc->peers[pidx].outmsgs[midx],
15957f46c8b3SSerge Semin &tool_outmsg_fops);
15967f46c8b3SSerge Semin }
15977f46c8b3SSerge Semin }
15987f46c8b3SSerge Semin }
15997f46c8b3SSerge Semin
tool_clear_dbgfs(struct tool_ctx * tc)16007f46c8b3SSerge Semin static void tool_clear_dbgfs(struct tool_ctx *tc)
16017f46c8b3SSerge Semin {
16027f46c8b3SSerge Semin debugfs_remove_recursive(tc->dbgfs_dir);
16037f46c8b3SSerge Semin }
16047f46c8b3SSerge Semin
tool_probe(struct ntb_client * self,struct ntb_dev * ntb)16057f46c8b3SSerge Semin static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
16067f46c8b3SSerge Semin {
16077f46c8b3SSerge Semin struct tool_ctx *tc;
16087f46c8b3SSerge Semin int ret;
16097f46c8b3SSerge Semin
16107f46c8b3SSerge Semin tc = tool_create_data(ntb);
16117f46c8b3SSerge Semin if (IS_ERR(tc))
16127f46c8b3SSerge Semin return PTR_ERR(tc);
16137f46c8b3SSerge Semin
16147f46c8b3SSerge Semin ret = tool_init_peers(tc);
16157f46c8b3SSerge Semin if (ret != 0)
16167f46c8b3SSerge Semin goto err_clear_data;
16177f46c8b3SSerge Semin
16187f46c8b3SSerge Semin ret = tool_init_mws(tc);
16197f46c8b3SSerge Semin if (ret != 0)
16207f46c8b3SSerge Semin goto err_clear_data;
16217f46c8b3SSerge Semin
16227f46c8b3SSerge Semin ret = tool_init_spads(tc);
16237f46c8b3SSerge Semin if (ret != 0)
16247f46c8b3SSerge Semin goto err_clear_mws;
16257f46c8b3SSerge Semin
16267f46c8b3SSerge Semin ret = tool_init_msgs(tc);
16277f46c8b3SSerge Semin if (ret != 0)
16287f46c8b3SSerge Semin goto err_clear_mws;
16297f46c8b3SSerge Semin
16307f46c8b3SSerge Semin ret = tool_init_ntb(tc);
16317f46c8b3SSerge Semin if (ret != 0)
16327f46c8b3SSerge Semin goto err_clear_mws;
16337f46c8b3SSerge Semin
1634578b881bSAllen Hubbe tool_setup_dbgfs(tc);
1635578b881bSAllen Hubbe
1636578b881bSAllen Hubbe return 0;
1637578b881bSAllen Hubbe
16387f46c8b3SSerge Semin err_clear_mws:
16397f46c8b3SSerge Semin tool_clear_mws(tc);
16407f46c8b3SSerge Semin
16417f46c8b3SSerge Semin err_clear_data:
16427f46c8b3SSerge Semin tool_clear_data(tc);
16437f46c8b3SSerge Semin
16447f46c8b3SSerge Semin return ret;
1645578b881bSAllen Hubbe }
1646578b881bSAllen Hubbe
tool_remove(struct ntb_client * self,struct ntb_dev * ntb)1647578b881bSAllen Hubbe static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb)
1648578b881bSAllen Hubbe {
1649578b881bSAllen Hubbe struct tool_ctx *tc = ntb->ctx;
1650578b881bSAllen Hubbe
16517f46c8b3SSerge Semin tool_clear_dbgfs(tc);
16528b71d285SLogan Gunthorpe
16537f46c8b3SSerge Semin tool_clear_ntb(tc);
1654578b881bSAllen Hubbe
16557f46c8b3SSerge Semin tool_clear_mws(tc);
16567f46c8b3SSerge Semin
16577f46c8b3SSerge Semin tool_clear_data(tc);
1658578b881bSAllen Hubbe }
1659578b881bSAllen Hubbe
1660578b881bSAllen Hubbe static struct ntb_client tool_client = {
1661578b881bSAllen Hubbe .ops = {
1662578b881bSAllen Hubbe .probe = tool_probe,
1663578b881bSAllen Hubbe .remove = tool_remove,
16647f46c8b3SSerge Semin }
1665578b881bSAllen Hubbe };
1666578b881bSAllen Hubbe
tool_init(void)1667578b881bSAllen Hubbe static int __init tool_init(void)
1668578b881bSAllen Hubbe {
16697f46c8b3SSerge Semin int ret;
1670578b881bSAllen Hubbe
1671578b881bSAllen Hubbe if (debugfs_initialized())
16727f46c8b3SSerge Semin tool_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
1673578b881bSAllen Hubbe
16747f46c8b3SSerge Semin ret = ntb_register_client(&tool_client);
16757f46c8b3SSerge Semin if (ret)
16767f46c8b3SSerge Semin debugfs_remove_recursive(tool_dbgfs_topdir);
1677578b881bSAllen Hubbe
16787f46c8b3SSerge Semin return ret;
1679578b881bSAllen Hubbe }
1680578b881bSAllen Hubbe module_init(tool_init);
1681578b881bSAllen Hubbe
tool_exit(void)1682578b881bSAllen Hubbe static void __exit tool_exit(void)
1683578b881bSAllen Hubbe {
1684578b881bSAllen Hubbe ntb_unregister_client(&tool_client);
16857f46c8b3SSerge Semin debugfs_remove_recursive(tool_dbgfs_topdir);
1686578b881bSAllen Hubbe }
1687578b881bSAllen Hubbe module_exit(tool_exit);
1688