summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerge Semin <fancer.lancer@gmail.com>2017-12-06 09:31:56 -0500
committerJon Mason <jdmason@kudzu.us>2018-01-28 22:17:24 -0500
commit7f46c8b3a5523a28cb81c2c12bc3dcc76ed52d59 (patch)
tree97579c0e33f34510cc1e6063ca037433fe6743f9
parentc7aeb0afdcc2d1ec5945e164d3fb97c5ae3edd1a (diff)
NTB: ntb_tool: Add full multi-port NTB API support
Former NTB Debugging tool driver supported only the limited functionality of the recently updated NTB API, which is now available to work with the truly NTB multi-port devices and devices, which got NTB Message registers instead of Scratchpads. This patch fully rewrites the driver so one would fully expose all the new NTB API interfaces. Particularly it concerns the Message registers, peer ports API, NTB link settings. Additional cleanups are also added here. Signed-off-by: Serge Semin <fancer.lancer@gmail.com> Signed-off-by: Jon Mason <jdmason@kudzu.us>
-rw-r--r--drivers/ntb/test/ntb_tool.c1820
1 files changed, 1240 insertions, 580 deletions
diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
index e490bbc8726c..920fc9b161b0 100644
--- a/drivers/ntb/test/ntb_tool.c
+++ b/drivers/ntb/test/ntb_tool.c
@@ -5,6 +5,7 @@
5 * GPL LICENSE SUMMARY 5 * GPL LICENSE SUMMARY
6 * 6 *
7 * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 7 * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
8 * Copyright (C) 2017 T-Platforms All Rights Reserved.
8 * 9 *
9 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License as 11 * it under the terms of version 2 of the GNU General Public License as
@@ -18,6 +19,7 @@
18 * BSD LICENSE 19 * BSD LICENSE
19 * 20 *
20 * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 21 * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
22 * Copyright (C) 2017 T-Platforms All Rights Reserved.
21 * 23 *
22 * Redistribution and use in source and binary forms, with or without 24 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions 25 * modification, are permitted provided that the following conditions
@@ -46,9 +48,6 @@
46 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * 49 *
48 * PCIe NTB Debugging Tool Linux driver 50 * PCIe NTB Debugging Tool Linux driver
49 *
50 * Contact Information:
51 * Allen Hubbe <Allen.Hubbe@emc.com>
52 */ 51 */
53 52
54/* 53/*
@@ -56,42 +55,125 @@
56 * 55 *
57 * Assuming $DBG_DIR is something like: 56 * Assuming $DBG_DIR is something like:
58 * '/sys/kernel/debug/ntb_tool/0000:00:03.0' 57 * '/sys/kernel/debug/ntb_tool/0000:00:03.0'
58 * Suppose aside from local device there is at least one remote device
59 * connected to NTB with index 0.
60 *-----------------------------------------------------------------------------
61 * Eg: check local/peer device information.
62 *
63 * # Get local device port number
64 * root@self# cat $DBG_DIR/port
65 *
66 * # Check local device functionality
67 * root@self# ls $DBG_DIR
68 * db msg1 msg_sts peer4/ port
69 * db_event msg2 peer0/ peer5/ spad0
70 * db_mask msg3 peer1/ peer_db spad1
71 * link msg_event peer2/ peer_db_mask spad2
72 * msg0 msg_mask peer3/ peer_spad spad3
73 * # As one can see it supports:
74 * # 1) four inbound message registers
75 * # 2) four inbound scratchpads
76 * # 3) up to six peer devices
77 *
78 * # Check peer device port number
79 * root@self# cat $DBG_DIR/peer0/port
80 *
81 * # Check peer device(s) functionality to be used
82 * root@self# ls $DBG_DIR/peer0
83 * link mw_trans0 mw_trans6 port
84 * link_event mw_trans1 mw_trans7 spad0
85 * msg0 mw_trans2 peer_mw_trans0 spad1
86 * msg1 mw_trans3 peer_mw_trans1 spad2
87 * msg2 mw_trans4 peer_mw_trans2 spad3
88 * msg3 mw_trans5 peer_mw_trans3
89 * # As one can see we got:
90 * # 1) four outbound message registers
91 * # 2) four outbound scratchpads
92 * # 3) eight inbound memory windows
93 * # 4) four outbound memory windows
94 *-----------------------------------------------------------------------------
95 * Eg: NTB link tests
59 * 96 *
60 * Eg: check if clearing the doorbell mask generates an interrupt. 97 * # Set local link up/down
98 * root@self# echo Y > $DBG_DIR/link
99 * root@self# echo N > $DBG_DIR/link
61 * 100 *
62 * # Check the link status 101 * # Check if link with peer device is up/down:
63 * root@self# cat $DBG_DIR/link 102 * root@self# cat $DBG_DIR/peer0/link
64 * 103 *
65 * # Block until the link is up 104 * # Block until the link is up/down
66 * root@self# echo Y > $DBG_DIR/link_event 105 * root@self# echo Y > $DBG_DIR/peer0/link_event
106 * root@self# echo N > $DBG_DIR/peer0/link_event
107 *-----------------------------------------------------------------------------
108 * Eg: Doorbell registers tests (some functionality might be absent)
67 * 109 *
68 * # Set the doorbell mask 110 * # Set/clear/get local doorbell
69 * root@self# echo 's 1' > $DBG_DIR/mask 111 * root@self# echo 's 1' > $DBG_DIR/db
112 * root@self# echo 'c 1' > $DBG_DIR/db
113 * root@self# cat $DBG_DIR/db
70 * 114 *
71 * # Ring the doorbell from the peer 115 * # Set/clear/get local doorbell mask
116 * root@self# echo 's 1' > $DBG_DIR/db_mask
117 * root@self# echo 'c 1' > $DBG_DIR/db_mask
118 * root@self# cat $DBG_DIR/db_mask
119 *
120 * # Ring/clear/get peer doorbell
72 * root@peer# echo 's 1' > $DBG_DIR/peer_db 121 * root@peer# echo 's 1' > $DBG_DIR/peer_db
122 * root@peer# echo 'c 1' > $DBG_DIR/peer_db
123 * root@peer# cat $DBG_DIR/peer_db
124 *
125 * # Set/clear/get peer doorbell mask
126 * root@self# echo 's 1' > $DBG_DIR/peer_db_mask
127 * root@self# echo 'c 1' > $DBG_DIR/peer_db_mask
128 * root@self# cat $DBG_DIR/peer_db_mask
129 *
130 * # Block until local doorbell is set with specified value
131 * root@self# echo 1 > $DBG_DIR/db_event
132 *-----------------------------------------------------------------------------
133 * Eg: Message registers tests (functionality might be absent)
73 * 134 *
74 * # Clear the doorbell mask 135 * # Set/clear/get in/out message registers status
75 * root@self# echo 'c 1' > $DBG_DIR/mask 136 * root@self# echo 's 1' > $DBG_DIR/msg_sts
137 * root@self# echo 'c 1' > $DBG_DIR/msg_sts
138 * root@self# cat $DBG_DIR/msg_sts
76 * 139 *
77 * Observe debugging output in dmesg or your console. You should see a 140 * # Set/clear in/out message registers mask
78 * doorbell event triggered by clearing the mask. If not, this may indicate an 141 * root@self# echo 's 1' > $DBG_DIR/msg_mask
79 * issue with the hardware that needs to be worked around in the driver. 142 * root@self# echo 'c 1' > $DBG_DIR/msg_mask
80 * 143 *
81 * Eg: read and write scratchpad registers 144 * # Get inbound message register #0 value and source of port index
145 * root@self# cat $DBG_DIR/msg0
82 * 146 *
83 * root@peer# echo '0 0x01010101 1 0x7f7f7f7f' > $DBG_DIR/peer_spad 147 * # Send some data to peer over outbound message register #0
148 * root@self# echo 0x01020304 > $DBG_DIR/peer0/msg0
149 *-----------------------------------------------------------------------------
150 * Eg: Scratchpad registers tests (functionality might be absent)
84 * 151 *
85 * root@self# cat $DBG_DIR/spad 152 * # Write/read to/from local scratchpad register #0
153 * root@peer# echo 0x01020304 > $DBG_DIR/spad0
154 * root@peer# cat $DBG_DIR/spad0
86 * 155 *
87 * Observe that spad 0 and 1 have the values set by the peer. 156 * # Write/read to/from peer scratchpad register #0
157 * root@peer# echo 0x01020304 > $DBG_DIR/peer0/spad0
158 * root@peer# cat $DBG_DIR/peer0/spad0
159 *-----------------------------------------------------------------------------
160 * Eg: Memory windows tests
88 * 161 *
89 * # Check the memory window translation info 162 * # Create inbound memory window buffer of specified size/get its base address
90 * cat $DBG_DIR/peer_trans0 163 * root@peer# echo 16384 > $DBG_DIR/peer0/mw_trans0
164 * root@peer# cat $DBG_DIR/peer0/mw_trans0
91 * 165 *
92 * # Setup a 16k memory window buffer 166 * # Write/read data to/from inbound memory window
93 * echo 16384 > $DBG_DIR/peer_trans0 167 * root@peer# echo Hello > $DBG_DIR/peer0/mw0
168 * root@peer# head -c 7 $DBG_DIR/peer0/mw0
94 * 169 *
170 * # Map outbound memory window/check it settings (on peer device)
171 * root@peer# echo 0xADD0BA5E:16384 > $DBG_DIR/peer0/peer_mw_trans0
172 * root@peer# cat $DBG_DIR/peer0/peer_mw_trans0
173 *
174 * # Write/read data to/from outbound memory window (on peer device)
175 * root@peer# echo olleH > $DBG_DIR/peer0/peer_mw0
176 * root@peer# head -c 7 $DBG_DIR/peer0/peer_mw0
95 */ 177 */
96 178
97#include <linux/init.h> 179#include <linux/init.h>
@@ -106,48 +188,87 @@
106 188
107#include <linux/ntb.h> 189#include <linux/ntb.h>
108 190
109#define DRIVER_NAME "ntb_tool" 191#define DRIVER_NAME "ntb_tool"
110#define DRIVER_DESCRIPTION "PCIe NTB Debugging Tool" 192#define DRIVER_VERSION "2.0"
111
112#define DRIVER_VERSION "1.0"
113#define DRIVER_RELDATE "22 April 2015"
114#define DRIVER_AUTHOR "Allen Hubbe <Allen.Hubbe@emc.com>"
115 193
116MODULE_LICENSE("Dual BSD/GPL"); 194MODULE_LICENSE("Dual BSD/GPL");
117MODULE_VERSION(DRIVER_VERSION); 195MODULE_VERSION(DRIVER_VERSION);
118MODULE_AUTHOR(DRIVER_AUTHOR); 196MODULE_AUTHOR("Allen Hubbe <Allen.Hubbe@emc.com>");
119MODULE_DESCRIPTION(DRIVER_DESCRIPTION); 197MODULE_DESCRIPTION("PCIe NTB Debugging Tool");
120
121/* It is rare to have hadrware with greater than six MWs */
122#define MAX_MWS 6
123/* Only two-ports devices are supported */
124#define PIDX NTB_DEF_PEER_IDX
125
126static struct dentry *tool_dbgfs;
127 198
199/*
200 * Inbound and outbound memory windows descriptor. Union members selection
201 * depends on the MW type the structure describes. mm_base/dma_base are the
202 * virtual and DMA address of an inbound MW. io_base/tr_base are the MMIO
203 * mapped virtual and xlat addresses of an outbound MW respectively.
204 */
128struct tool_mw { 205struct tool_mw {
129 int idx; 206 int widx;
207 int pidx;
130 struct tool_ctx *tc; 208 struct tool_ctx *tc;
131 resource_size_t win_size; 209 union {
210 u8 *mm_base;
211 u8 __iomem *io_base;
212 };
213 union {
214 dma_addr_t dma_base;
215 u64 tr_base;
216 };
132 resource_size_t size; 217 resource_size_t size;
133 u8 __iomem *local; 218 struct dentry *dbgfs_file;
134 u8 *peer; 219};
135 dma_addr_t peer_dma; 220
136 struct dentry *peer_dbg_file; 221/*
222 * Wrapper structure is used to distinguish the outbound MW peers reference
223 * within the corresponding DebugFS directory IO operation.
224 */
225struct tool_mw_wrap {
226 int pidx;
227 struct tool_mw *mw;
228};
229
230struct tool_msg {
231 int midx;
232 int pidx;
233 struct tool_ctx *tc;
234};
235
236struct tool_spad {
237 int sidx;
238 int pidx;
239 struct tool_ctx *tc;
240};
241
242struct tool_peer {
243 int pidx;
244 struct tool_ctx *tc;
245 int inmw_cnt;
246 struct tool_mw *inmws;
247 int outmw_cnt;
248 struct tool_mw_wrap *outmws;
249 int outmsg_cnt;
250 struct tool_msg *outmsgs;
251 int outspad_cnt;
252 struct tool_spad *outspads;
253 struct dentry *dbgfs_dir;
137}; 254};
138 255
139struct tool_ctx { 256struct tool_ctx {
140 struct ntb_dev *ntb; 257 struct ntb_dev *ntb;
141 struct dentry *dbgfs;
142 wait_queue_head_t link_wq; 258 wait_queue_head_t link_wq;
143 int mw_count; 259 wait_queue_head_t db_wq;
144 struct tool_mw mws[MAX_MWS]; 260 wait_queue_head_t msg_wq;
261 int outmw_cnt;
262 struct tool_mw *outmws;
263 int peer_cnt;
264 struct tool_peer *peers;
265 int inmsg_cnt;
266 struct tool_msg *inmsgs;
267 int inspad_cnt;
268 struct tool_spad *inspads;
269 struct dentry *dbgfs_dir;
145}; 270};
146 271
147#define SPAD_FNAME_SIZE 0x10
148#define INT_PTR(x) ((void *)(unsigned long)x)
149#define PTR_INT(x) ((int)(unsigned long)x)
150
151#define TOOL_FOPS_RDWR(__name, __read, __write) \ 272#define TOOL_FOPS_RDWR(__name, __read, __write) \
152 const struct file_operations __name = { \ 273 const struct file_operations __name = { \
153 .owner = THIS_MODULE, \ 274 .owner = THIS_MODULE, \
@@ -156,6 +277,15 @@ struct tool_ctx {
156 .write = __write, \ 277 .write = __write, \
157 } 278 }
158 279
280#define TOOL_BUF_LEN 32
281
282static struct dentry *tool_dbgfs_topdir;
283
284/*==============================================================================
285 * NTB events handlers
286 *==============================================================================
287 */
288
159static void tool_link_event(void *ctx) 289static void tool_link_event(void *ctx)
160{ 290{
161 struct tool_ctx *tc = ctx; 291 struct tool_ctx *tc = ctx;
@@ -181,580 +311,576 @@ static void tool_db_event(void *ctx, int vec)
181 311
182 dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n", 312 dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n",
183 vec, db_mask, db_bits); 313 vec, db_mask, db_bits);
314
315 wake_up(&tc->db_wq);
316}
317
318static void tool_msg_event(void *ctx)
319{
320 struct tool_ctx *tc = ctx;
321 u64 msg_sts;
322
323 msg_sts = ntb_msg_read_sts(tc->ntb);
324
325 dev_dbg(&tc->ntb->dev, "message bits %#llx\n", msg_sts);
326
327 wake_up(&tc->msg_wq);
184} 328}
185 329
186static const struct ntb_ctx_ops tool_ops = { 330static const struct ntb_ctx_ops tool_ops = {
187 .link_event = tool_link_event, 331 .link_event = tool_link_event,
188 .db_event = tool_db_event, 332 .db_event = tool_db_event,
333 .msg_event = tool_msg_event
189}; 334};
190 335
191static ssize_t tool_dbfn_read(struct tool_ctx *tc, char __user *ubuf, 336/*==============================================================================
192 size_t size, loff_t *offp, 337 * Common read/write methods
193 u64 (*db_read_fn)(struct ntb_dev *)) 338 *==============================================================================
339 */
340
341static ssize_t tool_fn_read(struct tool_ctx *tc, char __user *ubuf,
342 size_t size, loff_t *offp,
343 u64 (*fn_read)(struct ntb_dev *))
194{ 344{
195 size_t buf_size; 345 size_t buf_size;
196 char *buf; 346 char buf[TOOL_BUF_LEN];
197 ssize_t pos, rc; 347 ssize_t pos;
198 348
199 if (!db_read_fn) 349 if (!fn_read)
200 return -EINVAL; 350 return -EINVAL;
201 351
202 buf_size = min_t(size_t, size, 0x20); 352 buf_size = min(size, sizeof(buf));
203
204 buf = kmalloc(buf_size, GFP_KERNEL);
205 if (!buf)
206 return -ENOMEM;
207
208 pos = scnprintf(buf, buf_size, "%#llx\n",
209 db_read_fn(tc->ntb));
210 353
211 rc = simple_read_from_buffer(ubuf, size, offp, buf, pos); 354 pos = scnprintf(buf, buf_size, "%#llx\n", fn_read(tc->ntb));
212 355
213 kfree(buf); 356 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
214
215 return rc;
216} 357}
217 358
218static ssize_t tool_dbfn_write(struct tool_ctx *tc, 359static ssize_t tool_fn_write(struct tool_ctx *tc,
219 const char __user *ubuf, 360 const char __user *ubuf,
220 size_t size, loff_t *offp, 361 size_t size, loff_t *offp,
221 int (*db_set_fn)(struct ntb_dev *, u64), 362 int (*fn_set)(struct ntb_dev *, u64),
222 int (*db_clear_fn)(struct ntb_dev *, u64)) 363 int (*fn_clear)(struct ntb_dev *, u64))
223{ 364{
224 u64 db_bits;
225 char *buf, cmd; 365 char *buf, cmd;
226 ssize_t rc; 366 ssize_t ret;
367 u64 bits;
227 int n; 368 int n;
228 369
229 buf = kmalloc(size + 1, GFP_KERNEL); 370 buf = kmalloc(size + 1, GFP_KERNEL);
230 if (!buf) 371 if (!buf)
231 return -ENOMEM; 372 return -ENOMEM;
232 373
233 rc = simple_write_to_buffer(buf, size, offp, ubuf, size); 374 ret = simple_write_to_buffer(buf, size, offp, ubuf, size);
234 if (rc < 0) { 375 if (ret < 0) {
235 kfree(buf); 376 kfree(buf);
236 return rc; 377 return ret;
237 } 378 }
238 379
239 buf[size] = 0; 380 buf[size] = 0;
240 381
241 n = sscanf(buf, "%c %lli", &cmd, &db_bits); 382 n = sscanf(buf, "%c %lli", &cmd, &bits);
242 383
243 kfree(buf); 384 kfree(buf);
244 385
245 if (n != 2) { 386 if (n != 2) {
246 rc = -EINVAL; 387 ret = -EINVAL;
247 } else if (cmd == 's') { 388 } else if (cmd == 's') {
248 if (!db_set_fn) 389 if (!fn_set)
249 rc = -EINVAL; 390 ret = -EINVAL;
250 else 391 else
251 rc = db_set_fn(tc->ntb, db_bits); 392 ret = fn_set(tc->ntb, bits);
252 } else if (cmd == 'c') { 393 } else if (cmd == 'c') {
253 if (!db_clear_fn) 394 if (!fn_clear)
254 rc = -EINVAL; 395 ret = -EINVAL;
255 else 396 else
256 rc = db_clear_fn(tc->ntb, db_bits); 397 ret = fn_clear(tc->ntb, bits);
257 } else { 398 } else {
258 rc = -EINVAL; 399 ret = -EINVAL;
259 } 400 }
260 401
261 return rc ? : size; 402 return ret ? : size;
262} 403}
263 404
264static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf, 405/*==============================================================================
265 size_t size, loff_t *offp, 406 * Port read/write methods
266 u32 (*spad_read_fn)(struct ntb_dev *, int)) 407 *==============================================================================
267{ 408 */
268 size_t buf_size;
269 char *buf;
270 ssize_t pos, rc;
271 int i, spad_count;
272
273 if (!spad_read_fn)
274 return -EINVAL;
275
276 spad_count = ntb_spad_count(tc->ntb);
277 409
278 /* 410static ssize_t tool_port_read(struct file *filep, char __user *ubuf,
279 * We multiply the number of spads by 15 to get the buffer size 411 size_t size, loff_t *offp)
280 * this is from 3 for the %d, 10 for the largest hex value 412{
281 * (0x00000000) and 2 for the tab and line feed. 413 struct tool_ctx *tc = filep->private_data;
282 */ 414 char buf[TOOL_BUF_LEN];
283 buf_size = min_t(size_t, size, spad_count * 15); 415 int pos;
284 416
285 buf = kmalloc(buf_size, GFP_KERNEL); 417 pos = scnprintf(buf, sizeof(buf), "%d\n", ntb_port_number(tc->ntb));
286 if (!buf)
287 return -ENOMEM;
288 418
289 pos = 0; 419 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
420}
290 421
291 for (i = 0; i < spad_count; ++i) { 422static TOOL_FOPS_RDWR(tool_port_fops,
292 pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n", 423 tool_port_read,
293 i, spad_read_fn(tc->ntb, i)); 424 NULL);
294 }
295 425
296 rc = simple_read_from_buffer(ubuf, size, offp, buf, pos); 426static ssize_t tool_peer_port_read(struct file *filep, char __user *ubuf,
427 size_t size, loff_t *offp)
428{
429 struct tool_peer *peer = filep->private_data;
430 struct tool_ctx *tc = peer->tc;
431 char buf[TOOL_BUF_LEN];
432 int pos;
297 433
298 kfree(buf); 434 pos = scnprintf(buf, sizeof(buf), "%d\n",
435 ntb_peer_port_number(tc->ntb, peer->pidx));
299 436
300 return rc; 437 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
301} 438}
302 439
303static ssize_t tool_spadfn_write(struct tool_ctx *tc, 440static TOOL_FOPS_RDWR(tool_peer_port_fops,
304 const char __user *ubuf, 441 tool_peer_port_read,
305 size_t size, loff_t *offp, 442 NULL);
306 int (*spad_write_fn)(struct ntb_dev *, 443
307 int, u32)) 444static int tool_init_peers(struct tool_ctx *tc)
308{ 445{
309 int spad_idx; 446 int pidx;
310 u32 spad_val;
311 char *buf, *buf_ptr;
312 int pos, n;
313 ssize_t rc;
314
315 if (!spad_write_fn) {
316 dev_dbg(&tc->ntb->dev, "no spad write fn\n");
317 return -EINVAL;
318 }
319 447
320 buf = kmalloc(size + 1, GFP_KERNEL); 448 tc->peer_cnt = ntb_peer_port_count(tc->ntb);
321 if (!buf) 449 tc->peers = devm_kcalloc(&tc->ntb->dev, tc->peer_cnt,
450 sizeof(*tc->peers), GFP_KERNEL);
451 if (tc->peers == NULL)
322 return -ENOMEM; 452 return -ENOMEM;
323 453
324 rc = simple_write_to_buffer(buf, size, offp, ubuf, size); 454 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
325 if (rc < 0) { 455 tc->peers[pidx].pidx = pidx;
326 kfree(buf); 456 tc->peers[pidx].tc = tc;
327 return rc;
328 } 457 }
329 458
330 buf[size] = 0; 459 return 0;
331 buf_ptr = buf;
332 n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos);
333 while (n == 2) {
334 buf_ptr += pos;
335 rc = spad_write_fn(tc->ntb, spad_idx, spad_val);
336 if (rc)
337 break;
338
339 n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos);
340 }
341
342 if (n < 0)
343 rc = n;
344
345 kfree(buf);
346
347 return rc ? : size;
348} 460}
349 461
350static ssize_t tool_db_read(struct file *filep, char __user *ubuf, 462/*==============================================================================
351 size_t size, loff_t *offp) 463 * Link state read/write methods
352{ 464 *==============================================================================
353 struct tool_ctx *tc = filep->private_data; 465 */
354
355 return tool_dbfn_read(tc, ubuf, size, offp,
356 tc->ntb->ops->db_read);
357}
358 466
359static ssize_t tool_db_write(struct file *filep, const char __user *ubuf, 467static ssize_t tool_link_write(struct file *filep, const char __user *ubuf,
360 size_t size, loff_t *offp) 468 size_t size, loff_t *offp)
361{ 469{
362 struct tool_ctx *tc = filep->private_data; 470 struct tool_ctx *tc = filep->private_data;
471 bool val;
472 int ret;
363 473
364 return tool_dbfn_write(tc, ubuf, size, offp, 474 ret = kstrtobool_from_user(ubuf, size, &val);
365 tc->ntb->ops->db_set, 475 if (ret)
366 tc->ntb->ops->db_clear); 476 return ret;
367}
368 477
369static TOOL_FOPS_RDWR(tool_db_fops, 478 if (val)
370 tool_db_read, 479 ret = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
371 tool_db_write); 480 else
481 ret = ntb_link_disable(tc->ntb);
372 482
373static ssize_t tool_mask_read(struct file *filep, char __user *ubuf, 483 if (ret)
374 size_t size, loff_t *offp) 484 return ret;
375{
376 struct tool_ctx *tc = filep->private_data;
377 485
378 return tool_dbfn_read(tc, ubuf, size, offp, 486 return size;
379 tc->ntb->ops->db_read_mask);
380} 487}
381 488
382static ssize_t tool_mask_write(struct file *filep, const char __user *ubuf, 489static TOOL_FOPS_RDWR(tool_link_fops,
383 size_t size, loff_t *offp) 490 NULL,
491 tool_link_write);
492
493static ssize_t tool_peer_link_read(struct file *filep, char __user *ubuf,
494 size_t size, loff_t *offp)
384{ 495{
385 struct tool_ctx *tc = filep->private_data; 496 struct tool_peer *peer = filep->private_data;
497 struct tool_ctx *tc = peer->tc;
498 char buf[3];
386 499
387 return tool_dbfn_write(tc, ubuf, size, offp, 500 if (ntb_link_is_up(tc->ntb, NULL, NULL) & BIT(peer->pidx))
388 tc->ntb->ops->db_set_mask, 501 buf[0] = 'Y';
389 tc->ntb->ops->db_clear_mask); 502 else
503 buf[0] = 'N';
504 buf[1] = '\n';
505 buf[2] = '\0';
506
507 return simple_read_from_buffer(ubuf, size, offp, buf, 3);
390} 508}
391 509
392static TOOL_FOPS_RDWR(tool_mask_fops, 510static TOOL_FOPS_RDWR(tool_peer_link_fops,
393 tool_mask_read, 511 tool_peer_link_read,
394 tool_mask_write); 512 NULL);
395 513
396static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf, 514static ssize_t tool_peer_link_event_write(struct file *filep,
397 size_t size, loff_t *offp) 515 const char __user *ubuf,
516 size_t size, loff_t *offp)
398{ 517{
399 struct tool_ctx *tc = filep->private_data; 518 struct tool_peer *peer = filep->private_data;
519 struct tool_ctx *tc = peer->tc;
520 u64 link_msk;
521 bool val;
522 int ret;
400 523
401 return tool_dbfn_read(tc, ubuf, size, offp, 524 ret = kstrtobool_from_user(ubuf, size, &val);
402 tc->ntb->ops->peer_db_read); 525 if (ret)
403} 526 return ret;
404 527
405static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf, 528 link_msk = BIT_ULL_MASK(peer->pidx);
406 size_t size, loff_t *offp)
407{
408 struct tool_ctx *tc = filep->private_data;
409 529
410 return tool_dbfn_write(tc, ubuf, size, offp, 530 if (wait_event_interruptible(tc->link_wq,
411 tc->ntb->ops->peer_db_set, 531 !!(ntb_link_is_up(tc->ntb, NULL, NULL) & link_msk) == val))
412 tc->ntb->ops->peer_db_clear); 532 return -ERESTART;
533
534 return size;
413} 535}
414 536
415static TOOL_FOPS_RDWR(tool_peer_db_fops, 537static TOOL_FOPS_RDWR(tool_peer_link_event_fops,
416 tool_peer_db_read, 538 NULL,
417 tool_peer_db_write); 539 tool_peer_link_event_write);
418 540
419static ssize_t tool_peer_mask_read(struct file *filep, char __user *ubuf, 541/*==============================================================================
420 size_t size, loff_t *offp) 542 * Memory windows read/write/setting methods
543 *==============================================================================
544 */
545
546static ssize_t tool_mw_read(struct file *filep, char __user *ubuf,
547 size_t size, loff_t *offp)
421{ 548{
422 struct tool_ctx *tc = filep->private_data; 549 struct tool_mw *inmw = filep->private_data;
550
551 if (inmw->mm_base == NULL)
552 return -ENXIO;
423 553
424 return tool_dbfn_read(tc, ubuf, size, offp, 554 return simple_read_from_buffer(ubuf, size, offp,
425 tc->ntb->ops->peer_db_read_mask); 555 inmw->mm_base, inmw->size);
426} 556}
427 557
428static ssize_t tool_peer_mask_write(struct file *filep, const char __user *ubuf, 558static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf,
429 size_t size, loff_t *offp) 559 size_t size, loff_t *offp)
430{ 560{
431 struct tool_ctx *tc = filep->private_data; 561 struct tool_mw *inmw = filep->private_data;
432 562
433 return tool_dbfn_write(tc, ubuf, size, offp, 563 if (inmw->mm_base == NULL)
434 tc->ntb->ops->peer_db_set_mask, 564 return -ENXIO;
435 tc->ntb->ops->peer_db_clear_mask); 565
566 return simple_write_to_buffer(inmw->mm_base, inmw->size, offp,
567 ubuf, size);
436} 568}
437 569
438static TOOL_FOPS_RDWR(tool_peer_mask_fops, 570static TOOL_FOPS_RDWR(tool_mw_fops,
439 tool_peer_mask_read, 571 tool_mw_read,
440 tool_peer_mask_write); 572 tool_mw_write);
441 573
442static ssize_t tool_spad_read(struct file *filep, char __user *ubuf, 574static int tool_setup_mw(struct tool_ctx *tc, int pidx, int widx,
443 size_t size, loff_t *offp) 575 size_t req_size)
444{ 576{
445 struct tool_ctx *tc = filep->private_data; 577 resource_size_t size, addr_align, size_align;
578 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
579 char buf[TOOL_BUF_LEN];
580 int ret;
446 581
447 return tool_spadfn_read(tc, ubuf, size, offp, 582 if (inmw->mm_base != NULL)
448 tc->ntb->ops->spad_read); 583 return 0;
449}
450 584
451static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf, 585 ret = ntb_mw_get_align(tc->ntb, pidx, widx, &addr_align,
452 size_t size, loff_t *offp) 586 &size_align, &size);
453{ 587 if (ret)
454 struct tool_ctx *tc = filep->private_data; 588 return ret;
589
590 inmw->size = min_t(resource_size_t, req_size, size);
591 inmw->size = round_up(inmw->size, addr_align);
592 inmw->size = round_up(inmw->size, size_align);
593 inmw->mm_base = dma_alloc_coherent(&tc->ntb->dev, inmw->size,
594 &inmw->dma_base, GFP_KERNEL);
595 if (!inmw->mm_base)
596 return -ENOMEM;
455 597
456 return tool_spadfn_write(tc, ubuf, size, offp, 598 if (!IS_ALIGNED(inmw->dma_base, addr_align)) {
457 tc->ntb->ops->spad_write); 599 ret = -ENOMEM;
458} 600 goto err_free_dma;
601 }
459 602
460static TOOL_FOPS_RDWR(tool_spad_fops, 603 ret = ntb_mw_set_trans(tc->ntb, pidx, widx, inmw->dma_base, inmw->size);
461 tool_spad_read, 604 if (ret)
462 tool_spad_write); 605 goto err_free_dma;
463 606
464static u32 ntb_tool_peer_spad_read(struct ntb_dev *ntb, int sidx) 607 snprintf(buf, sizeof(buf), "mw%d", widx);
465{ 608 inmw->dbgfs_file = debugfs_create_file(buf, 0600,
466 return ntb_peer_spad_read(ntb, PIDX, sidx); 609 tc->peers[pidx].dbgfs_dir, inmw,
467} 610 &tool_mw_fops);
468 611
469static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf, 612 return 0;
470 size_t size, loff_t *offp)
471{
472 struct tool_ctx *tc = filep->private_data;
473 613
474 return tool_spadfn_read(tc, ubuf, size, offp, ntb_tool_peer_spad_read); 614err_free_dma:
475} 615 dma_free_coherent(&tc->ntb->dev, inmw->size, inmw->mm_base,
616 inmw->dma_base);
617 inmw->mm_base = NULL;
618 inmw->dma_base = 0;
619 inmw->size = 0;
476 620
477static int ntb_tool_peer_spad_write(struct ntb_dev *ntb, int sidx, u32 val) 621 return ret;
478{
479 return ntb_peer_spad_write(ntb, PIDX, sidx, val);
480} 622}
481 623
482static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf, 624static void tool_free_mw(struct tool_ctx *tc, int pidx, int widx)
483 size_t size, loff_t *offp)
484{ 625{
485 struct tool_ctx *tc = filep->private_data; 626 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
486
487 return tool_spadfn_write(tc, ubuf, size, offp,
488 ntb_tool_peer_spad_write);
489}
490
491static TOOL_FOPS_RDWR(tool_peer_spad_fops,
492 tool_peer_spad_read,
493 tool_peer_spad_write);
494 627
495static ssize_t tool_link_read(struct file *filep, char __user *ubuf, 628 debugfs_remove(inmw->dbgfs_file);
496 size_t size, loff_t *offp)
497{
498 struct tool_ctx *tc = filep->private_data;
499 char buf[3];
500 629
501 buf[0] = ntb_link_is_up(tc->ntb, NULL, NULL) ? 'Y' : 'N'; 630 if (inmw->mm_base != NULL) {
502 buf[1] = '\n'; 631 ntb_mw_clear_trans(tc->ntb, pidx, widx);
503 buf[2] = '\0'; 632 dma_free_coherent(&tc->ntb->dev, inmw->size,
633 inmw->mm_base, inmw->dma_base);
634 }
504 635
505 return simple_read_from_buffer(ubuf, size, offp, buf, 2); 636 inmw->mm_base = NULL;
637 inmw->dma_base = 0;
638 inmw->size = 0;
639 inmw->dbgfs_file = NULL;
506} 640}
507 641
508static ssize_t tool_link_write(struct file *filep, const char __user *ubuf, 642static ssize_t tool_mw_trans_read(struct file *filep, char __user *ubuf,
509 size_t size, loff_t *offp) 643 size_t size, loff_t *offp)
510{ 644{
511 struct tool_ctx *tc = filep->private_data; 645 struct tool_mw *inmw = filep->private_data;
512 char buf[32]; 646 resource_size_t addr_align;
647 resource_size_t size_align;
648 resource_size_t size_max;
649 ssize_t ret, off = 0;
513 size_t buf_size; 650 size_t buf_size;
514 bool val; 651 char *buf;
515 int rc;
516 652
517 buf_size = min(size, (sizeof(buf) - 1)); 653 buf_size = min_t(size_t, size, 512);
518 if (copy_from_user(buf, ubuf, buf_size))
519 return -EFAULT;
520 654
521 buf[buf_size] = '\0'; 655 buf = kmalloc(buf_size, GFP_KERNEL);
656 if (!buf)
657 return -ENOMEM;
522 658
523 rc = strtobool(buf, &val); 659 ret = ntb_mw_get_align(inmw->tc->ntb, inmw->pidx, inmw->widx,
524 if (rc) 660 &addr_align, &size_align, &size_max);
525 return rc; 661 if (ret)
662 return ret;
526 663
527 if (val) 664 off += scnprintf(buf + off, buf_size - off,
528 rc = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 665 "Inbound MW \t%d\n",
529 else 666 inmw->widx);
530 rc = ntb_link_disable(tc->ntb);
531 667
532 if (rc) 668 off += scnprintf(buf + off, buf_size - off,
533 return rc; 669 "Port \t%d (%d)\n",
670 ntb_peer_port_number(inmw->tc->ntb, inmw->pidx),
671 inmw->pidx);
534 672
535 return size; 673 off += scnprintf(buf + off, buf_size - off,
536} 674 "Window Address \t0x%pK\n", inmw->mm_base);
537 675
538static TOOL_FOPS_RDWR(tool_link_fops, 676 off += scnprintf(buf + off, buf_size - off,
539 tool_link_read, 677 "DMA Address \t%pad\n",
540 tool_link_write); 678 &inmw->dma_base);
541 679
542static ssize_t tool_link_event_write(struct file *filep, 680 off += scnprintf(buf + off, buf_size - off,
543 const char __user *ubuf, 681 "Window Size \t%pa[p]\n",
544 size_t size, loff_t *offp) 682 &inmw->size);
545{
546 struct tool_ctx *tc = filep->private_data;
547 char buf[32];
548 size_t buf_size;
549 bool val;
550 int rc;
551 683
552 buf_size = min(size, (sizeof(buf) - 1)); 684 off += scnprintf(buf + off, buf_size - off,
553 if (copy_from_user(buf, ubuf, buf_size)) 685 "Alignment \t%pa[p]\n",
554 return -EFAULT; 686 &addr_align);
555 687
556 buf[buf_size] = '\0'; 688 off += scnprintf(buf + off, buf_size - off,
689 "Size Alignment \t%pa[p]\n",
690 &size_align);
557 691
558 rc = strtobool(buf, &val); 692 off += scnprintf(buf + off, buf_size - off,
559 if (rc) 693 "Size Max \t%pa[p]\n",
560 return rc; 694 &size_max);
561 695
562 if (wait_event_interruptible(tc->link_wq, 696 ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
563 ntb_link_is_up(tc->ntb, NULL, NULL) == val)) 697 kfree(buf);
564 return -ERESTART; 698
699 return ret;
700}
701
702static ssize_t tool_mw_trans_write(struct file *filep, const char __user *ubuf,
703 size_t size, loff_t *offp)
704{
705 struct tool_mw *inmw = filep->private_data;
706 unsigned int val;
707 int ret;
708
709 ret = kstrtouint_from_user(ubuf, size, 0, &val);
710 if (ret)
711 return ret;
712
713 tool_free_mw(inmw->tc, inmw->pidx, inmw->widx);
714 if (val) {
715 ret = tool_setup_mw(inmw->tc, inmw->pidx, inmw->widx, val);
716 if (ret)
717 return ret;
718 }
565 719
566 return size; 720 return size;
567} 721}
568 722
569static TOOL_FOPS_RDWR(tool_link_event_fops, 723static TOOL_FOPS_RDWR(tool_mw_trans_fops,
570 NULL, 724 tool_mw_trans_read,
571 tool_link_event_write); 725 tool_mw_trans_write);
572 726
573static ssize_t tool_mw_read(struct file *filep, char __user *ubuf, 727static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf,
574 size_t size, loff_t *offp) 728 size_t size, loff_t *offp)
575{ 729{
576 struct tool_mw *mw = filep->private_data; 730 struct tool_mw *outmw = filep->private_data;
577 ssize_t rc;
578 loff_t pos = *offp; 731 loff_t pos = *offp;
732 ssize_t ret;
579 void *buf; 733 void *buf;
580 734
581 if (mw->local == NULL) 735 if (outmw->io_base == NULL)
582 return -EIO; 736 return -EIO;
583 if (pos < 0) 737
584 return -EINVAL; 738 if (pos >= outmw->size || !size)
585 if (pos >= mw->win_size || !size)
586 return 0; 739 return 0;
587 if (size > mw->win_size - pos) 740
588 size = mw->win_size - pos; 741 if (size > outmw->size - pos)
742 size = outmw->size - pos;
589 743
590 buf = kmalloc(size, GFP_KERNEL); 744 buf = kmalloc(size, GFP_KERNEL);
591 if (!buf) 745 if (!buf)
592 return -ENOMEM; 746 return -ENOMEM;
593 747
594 memcpy_fromio(buf, mw->local + pos, size); 748 memcpy_fromio(buf, outmw->io_base + pos, size);
595 rc = copy_to_user(ubuf, buf, size); 749 ret = copy_to_user(ubuf, buf, size);
596 if (rc == size) { 750 if (ret == size) {
597 rc = -EFAULT; 751 ret = -EFAULT;
598 goto err_free; 752 goto err_free;
599 } 753 }
600 754
601 size -= rc; 755 size -= ret;
602 *offp = pos + size; 756 *offp = pos + size;
603 rc = size; 757 ret = size;
604 758
605err_free: 759err_free:
606 kfree(buf); 760 kfree(buf);
607 761
608 return rc; 762 return ret;
609} 763}
610 764
611static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf, 765static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf,
612 size_t size, loff_t *offp) 766 size_t size, loff_t *offp)
613{ 767{
614 struct tool_mw *mw = filep->private_data; 768 struct tool_mw *outmw = filep->private_data;
615 ssize_t rc; 769 ssize_t ret;
616 loff_t pos = *offp; 770 loff_t pos = *offp;
617 void *buf; 771 void *buf;
618 772
619 if (pos < 0) 773 if (outmw->io_base == NULL)
620 return -EINVAL; 774 return -EIO;
621 if (pos >= mw->win_size || !size) 775
776 if (pos >= outmw->size || !size)
622 return 0; 777 return 0;
623 if (size > mw->win_size - pos) 778 if (size > outmw->size - pos)
624 size = mw->win_size - pos; 779 size = outmw->size - pos;
625 780
626 buf = kmalloc(size, GFP_KERNEL); 781 buf = kmalloc(size, GFP_KERNEL);
627 if (!buf) 782 if (!buf)
628 return -ENOMEM; 783 return -ENOMEM;
629 784
630 rc = copy_from_user(buf, ubuf, size); 785 ret = copy_from_user(buf, ubuf, size);
631 if (rc == size) { 786 if (ret == size) {
632 rc = -EFAULT; 787 ret = -EFAULT;
633 goto err_free; 788 goto err_free;
634 } 789 }
635 790
636 size -= rc; 791 size -= ret;
637 *offp = pos + size; 792 *offp = pos + size;
638 rc = size; 793 ret = size;
639 794
640 memcpy_toio(mw->local + pos, buf, size); 795 memcpy_toio(outmw->io_base + pos, buf, size);
641 796
642err_free: 797err_free:
643 kfree(buf); 798 kfree(buf);
644 799
645 return rc; 800 return ret;
646}
647
648static TOOL_FOPS_RDWR(tool_mw_fops,
649 tool_mw_read,
650 tool_mw_write);
651
652static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf,
653 size_t size, loff_t *offp)
654{
655 struct tool_mw *mw = filep->private_data;
656
657 if (!mw->peer)
658 return -ENXIO;
659
660 return simple_read_from_buffer(ubuf, size, offp, mw->peer, mw->size);
661}
662
663static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf,
664 size_t size, loff_t *offp)
665{
666 struct tool_mw *mw = filep->private_data;
667
668 if (!mw->peer)
669 return -ENXIO;
670
671 return simple_write_to_buffer(mw->peer, mw->size, offp, ubuf, size);
672} 801}
673 802
674static TOOL_FOPS_RDWR(tool_peer_mw_fops, 803static TOOL_FOPS_RDWR(tool_peer_mw_fops,
675 tool_peer_mw_read, 804 tool_peer_mw_read,
676 tool_peer_mw_write); 805 tool_peer_mw_write);
677 806
678static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size) 807static int tool_setup_peer_mw(struct tool_ctx *tc, int pidx, int widx,
808 u64 req_addr, size_t req_size)
679{ 809{
680 int rc; 810 struct tool_mw *outmw = &tc->outmws[widx];
681 struct tool_mw *mw = &tc->mws[idx]; 811 resource_size_t map_size;
682 resource_size_t size, align_addr, align_size; 812 phys_addr_t map_base;
683 char buf[16]; 813 char buf[TOOL_BUF_LEN];
814 int ret;
684 815
685 if (mw->peer) 816 if (outmw->io_base != NULL)
686 return 0; 817 return 0;
687 818
688 rc = ntb_mw_get_align(tc->ntb, PIDX, idx, &align_addr, 819 ret = ntb_peer_mw_get_addr(tc->ntb, widx, &map_base, &map_size);
689 &align_size, &size); 820 if (ret)
690 if (rc) 821 return ret;
691 return rc;
692 822
693 mw->size = min_t(resource_size_t, req_size, size); 823 ret = ntb_peer_mw_set_trans(tc->ntb, pidx, widx, req_addr, req_size);
694 mw->size = round_up(mw->size, align_addr); 824 if (ret)
695 mw->size = round_up(mw->size, align_size); 825 return ret;
696 mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
697 &mw->peer_dma, GFP_KERNEL);
698 826
699 if (!mw->peer || !IS_ALIGNED(mw->peer_dma, align_addr)) 827 outmw->io_base = ioremap_wc(map_base, map_size);
700 return -ENOMEM; 828 if (outmw->io_base == NULL) {
829 ret = -EFAULT;
830 goto err_clear_trans;
831 }
701 832
702 rc = ntb_mw_set_trans(tc->ntb, PIDX, idx, mw->peer_dma, mw->size); 833 outmw->tr_base = req_addr;
703 if (rc) 834 outmw->size = req_size;
704 goto err_free_dma; 835 outmw->pidx = pidx;
705 836
706 snprintf(buf, sizeof(buf), "peer_mw%d", idx); 837 snprintf(buf, sizeof(buf), "peer_mw%d", widx);
707 mw->peer_dbg_file = debugfs_create_file(buf, S_IRUSR | S_IWUSR, 838 outmw->dbgfs_file = debugfs_create_file(buf, 0600,
708 mw->tc->dbgfs, mw, 839 tc->peers[pidx].dbgfs_dir, outmw,
709 &tool_peer_mw_fops); 840 &tool_peer_mw_fops);
710 841
711 return 0; 842 return 0;
712 843
713err_free_dma: 844err_clear_trans:
714 dma_free_coherent(&tc->ntb->pdev->dev, mw->size, 845 ntb_peer_mw_clear_trans(tc->ntb, pidx, widx);
715 mw->peer, 846
716 mw->peer_dma); 847 return ret;
717 mw->peer = NULL;
718 mw->peer_dma = 0;
719 mw->size = 0;
720
721 return rc;
722} 848}
723 849
724static void tool_free_mw(struct tool_ctx *tc, int idx) 850static void tool_free_peer_mw(struct tool_ctx *tc, int widx)
725{ 851{
726 struct tool_mw *mw = &tc->mws[idx]; 852 struct tool_mw *outmw = &tc->outmws[widx];
727
728 if (mw->peer) {
729 ntb_mw_clear_trans(tc->ntb, PIDX, idx);
730 dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
731 mw->peer,
732 mw->peer_dma);
733 }
734 853
735 mw->peer = NULL; 854 debugfs_remove(outmw->dbgfs_file);
736 mw->peer_dma = 0;
737 855
738 debugfs_remove(mw->peer_dbg_file); 856 if (outmw->io_base != NULL) {
857 iounmap(tc->outmws[widx].io_base);
858 ntb_peer_mw_clear_trans(tc->ntb, outmw->pidx, widx);
859 }
739 860
740 mw->peer_dbg_file = NULL; 861 outmw->io_base = NULL;
862 outmw->tr_base = 0;
863 outmw->size = 0;
864 outmw->pidx = -1;
865 outmw->dbgfs_file = NULL;
741} 866}
742 867
743static ssize_t tool_peer_mw_trans_read(struct file *filep, 868static ssize_t tool_peer_mw_trans_read(struct file *filep, char __user *ubuf,
744 char __user *ubuf, 869 size_t size, loff_t *offp)
745 size_t size, loff_t *offp)
746{ 870{
747 struct tool_mw *mw = filep->private_data; 871 struct tool_mw_wrap *outmw_wrap = filep->private_data;
748 872 struct tool_mw *outmw = outmw_wrap->mw;
749 char *buf; 873 resource_size_t map_size;
874 phys_addr_t map_base;
875 ssize_t off = 0;
750 size_t buf_size; 876 size_t buf_size;
751 ssize_t ret, off = 0; 877 char *buf;
878 int ret;
752 879
753 phys_addr_t base; 880 ret = ntb_peer_mw_get_addr(outmw->tc->ntb, outmw->widx,
754 resource_size_t mw_size; 881 &map_base, &map_size);
755 resource_size_t align_addr = 0; 882 if (ret)
756 resource_size_t align_size = 0; 883 return ret;
757 resource_size_t max_size = 0;
758 884
759 buf_size = min_t(size_t, size, 512); 885 buf_size = min_t(size_t, size, 512);
760 886
@@ -762,43 +888,37 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
762 if (!buf) 888 if (!buf)
763 return -ENOMEM; 889 return -ENOMEM;
764 890
765 ntb_mw_get_align(mw->tc->ntb, PIDX, mw->idx,
766 &align_addr, &align_size, &max_size);
767 ntb_peer_mw_get_addr(mw->tc->ntb, mw->idx, &base, &mw_size);
768
769 off += scnprintf(buf + off, buf_size - off,
770 "Peer MW %d Information:\n", mw->idx);
771
772 off += scnprintf(buf + off, buf_size - off, 891 off += scnprintf(buf + off, buf_size - off,
773 "Physical Address \t%pa[p]\n", 892 "Outbound MW: \t%d\n", outmw->widx);
774 &base);
775 893
776 off += scnprintf(buf + off, buf_size - off, 894 if (outmw->io_base != NULL) {
777 "Window Size \t%lld\n", 895 off += scnprintf(buf + off, buf_size - off,
778 (unsigned long long)mw_size); 896 "Port attached \t%d (%d)\n",
897 ntb_peer_port_number(outmw->tc->ntb, outmw->pidx),
898 outmw->pidx);
899 } else {
900 off += scnprintf(buf + off, buf_size - off,
901 "Port attached \t-1 (-1)\n");
902 }
779 903
780 off += scnprintf(buf + off, buf_size - off, 904 off += scnprintf(buf + off, buf_size - off,
781 "Alignment \t%lld\n", 905 "Virtual address \t0x%pK\n", outmw->io_base);
782 (unsigned long long)align_addr);
783 906
784 off += scnprintf(buf + off, buf_size - off, 907 off += scnprintf(buf + off, buf_size - off,
785 "Size Alignment \t%lld\n", 908 "Phys Address \t%pa[p]\n", &map_base);
786 (unsigned long long)align_size);
787 909
788 off += scnprintf(buf + off, buf_size - off, 910 off += scnprintf(buf + off, buf_size - off,
789 "Size Max \t%lld\n", 911 "Mapping Size \t%pa[p]\n", &map_size);
790 (unsigned long long)max_size);
791 912
792 off += scnprintf(buf + off, buf_size - off, 913 off += scnprintf(buf + off, buf_size - off,
793 "Ready \t%c\n", 914 "Translation Address \t0x%016llx\n", outmw->tr_base);
794 (mw->peer) ? 'Y' : 'N');
795 915
796 off += scnprintf(buf + off, buf_size - off, 916 off += scnprintf(buf + off, buf_size - off,
797 "Allocated Size \t%zd\n", 917 "Window Size \t%pa[p]\n", &outmw->size);
798 (mw->peer) ? (size_t)mw->size : 0);
799 918
800 ret = simple_read_from_buffer(ubuf, size, offp, buf, off); 919 ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
801 kfree(buf); 920 kfree(buf);
921
802 return ret; 922 return ret;
803} 923}
804 924
@@ -806,12 +926,12 @@ static ssize_t tool_peer_mw_trans_write(struct file *filep,
806 const char __user *ubuf, 926 const char __user *ubuf,
807 size_t size, loff_t *offp) 927 size_t size, loff_t *offp)
808{ 928{
809 struct tool_mw *mw = filep->private_data; 929 struct tool_mw_wrap *outmw_wrap = filep->private_data;
810 930 struct tool_mw *outmw = outmw_wrap->mw;
811 char buf[32]; 931 size_t buf_size, wsize;
812 size_t buf_size; 932 char buf[TOOL_BUF_LEN];
813 unsigned long long val; 933 int ret, n;
814 int rc; 934 u64 addr;
815 935
816 buf_size = min(size, (sizeof(buf) - 1)); 936 buf_size = min(size, (sizeof(buf) - 1));
817 if (copy_from_user(buf, ubuf, buf_size)) 937 if (copy_from_user(buf, ubuf, buf_size))
@@ -819,16 +939,17 @@ static ssize_t tool_peer_mw_trans_write(struct file *filep,
819 939
820 buf[buf_size] = '\0'; 940 buf[buf_size] = '\0';
821 941
822 rc = kstrtoull(buf, 0, &val); 942 n = sscanf(buf, "%lli:%zi", &addr, &wsize);
823 if (rc) 943 if (n != 2)
824 return rc; 944 return -EINVAL;
825
826 tool_free_mw(mw->tc, mw->idx);
827 if (val)
828 rc = tool_setup_mw(mw->tc, mw->idx, val);
829 945
830 if (rc) 946 tool_free_peer_mw(outmw->tc, outmw->widx);
831 return rc; 947 if (wsize) {
948 ret = tool_setup_peer_mw(outmw->tc, outmw_wrap->pidx,
949 outmw->widx, addr, wsize);
950 if (ret)
951 return ret;
952 }
832 953
833 return size; 954 return size;
834} 955}
@@ -837,195 +958,734 @@ static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops,
837 tool_peer_mw_trans_read, 958 tool_peer_mw_trans_read,
838 tool_peer_mw_trans_write); 959 tool_peer_mw_trans_write);
839 960
840static int tool_init_mw(struct tool_ctx *tc, int idx) 961static int tool_init_mws(struct tool_ctx *tc)
841{ 962{
842 struct tool_mw *mw = &tc->mws[idx]; 963 int widx, pidx;
843 phys_addr_t base; 964
844 int rc; 965 /* Initialize outbound memory windows */
845 966 tc->outmw_cnt = ntb_peer_mw_count(tc->ntb);
846 rc = ntb_peer_mw_get_addr(tc->ntb, idx, &base, &mw->win_size); 967 tc->outmws = devm_kcalloc(&tc->ntb->dev, tc->outmw_cnt,
847 if (rc) 968 sizeof(*tc->outmws), GFP_KERNEL);
848 return rc; 969 if (tc->outmws == NULL)
849 970 return -ENOMEM;
850 mw->tc = tc; 971
851 mw->idx = idx; 972 for (widx = 0; widx < tc->outmw_cnt; widx++) {
852 mw->local = ioremap_wc(base, mw->win_size); 973 tc->outmws[widx].widx = widx;
853 if (!mw->local) 974 tc->outmws[widx].pidx = -1;
854 return -EFAULT; 975 tc->outmws[widx].tc = tc;
976 }
977
978 /* Initialize inbound memory windows and outbound MWs wrapper */
979 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
980 tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->ntb, pidx);
981 tc->peers[pidx].inmws =
982 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].inmw_cnt,
983 sizeof(*tc->peers[pidx].inmws), GFP_KERNEL);
984 if (tc->peers[pidx].inmws == NULL)
985 return -ENOMEM;
986
987 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) {
988 tc->peers[pidx].inmws[widx].widx = widx;
989 tc->peers[pidx].inmws[widx].pidx = pidx;
990 tc->peers[pidx].inmws[widx].tc = tc;
991 }
992
993 tc->peers[pidx].outmw_cnt = ntb_peer_mw_count(tc->ntb);
994 tc->peers[pidx].outmws =
995 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmw_cnt,
996 sizeof(*tc->peers[pidx].outmws), GFP_KERNEL);
997
998 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) {
999 tc->peers[pidx].outmws[widx].pidx = pidx;
1000 tc->peers[pidx].outmws[widx].mw = &tc->outmws[widx];
1001 }
1002 }
855 1003
856 return 0; 1004 return 0;
857} 1005}
858 1006
859static void tool_free_mws(struct tool_ctx *tc) 1007static void tool_clear_mws(struct tool_ctx *tc)
860{ 1008{
861 int i; 1009 int widx, pidx;
1010
1011 /* Free outbound memory windows */
1012 for (widx = 0; widx < tc->outmw_cnt; widx++)
1013 tool_free_peer_mw(tc, widx);
862 1014
863 for (i = 0; i < tc->mw_count; i++) { 1015 /* Free outbound memory windows */
864 tool_free_mw(tc, i); 1016 for (pidx = 0; pidx < tc->peer_cnt; pidx++)
1017 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++)
1018 tool_free_mw(tc, pidx, widx);
1019}
865 1020
866 if (tc->mws[i].local) 1021/*==============================================================================
867 iounmap(tc->mws[i].local); 1022 * Doorbell read/write methods
1023 *==============================================================================
1024 */
868 1025
869 tc->mws[i].local = NULL; 1026static ssize_t tool_db_read(struct file *filep, char __user *ubuf,
870 } 1027 size_t size, loff_t *offp)
1028{
1029 struct tool_ctx *tc = filep->private_data;
1030
1031 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read);
871} 1032}
872 1033
873static void tool_setup_dbgfs(struct tool_ctx *tc) 1034static ssize_t tool_db_write(struct file *filep, const char __user *ubuf,
1035 size_t size, loff_t *offp)
874{ 1036{
875 int i; 1037 struct tool_ctx *tc = filep->private_data;
876 1038
877 /* This modules is useless without dbgfs... */ 1039 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set,
878 if (!tool_dbgfs) { 1040 tc->ntb->ops->db_clear);
879 tc->dbgfs = NULL; 1041}
880 return; 1042
1043static TOOL_FOPS_RDWR(tool_db_fops,
1044 tool_db_read,
1045 tool_db_write);
1046
1047static ssize_t tool_db_valid_mask_read(struct file *filep, char __user *ubuf,
1048 size_t size, loff_t *offp)
1049{
1050 struct tool_ctx *tc = filep->private_data;
1051
1052 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_valid_mask);
1053}
1054
1055static TOOL_FOPS_RDWR(tool_db_valid_mask_fops,
1056 tool_db_valid_mask_read,
1057 NULL);
1058
1059static ssize_t tool_db_mask_read(struct file *filep, char __user *ubuf,
1060 size_t size, loff_t *offp)
1061{
1062 struct tool_ctx *tc = filep->private_data;
1063
1064 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read_mask);
1065}
1066
1067static ssize_t tool_db_mask_write(struct file *filep, const char __user *ubuf,
1068 size_t size, loff_t *offp)
1069{
1070 struct tool_ctx *tc = filep->private_data;
1071
1072 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set_mask,
1073 tc->ntb->ops->db_clear_mask);
1074}
1075
1076static TOOL_FOPS_RDWR(tool_db_mask_fops,
1077 tool_db_mask_read,
1078 tool_db_mask_write);
1079
1080static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf,
1081 size_t size, loff_t *offp)
1082{
1083 struct tool_ctx *tc = filep->private_data;
1084
1085 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->peer_db_read);
1086}
1087
1088static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf,
1089 size_t size, loff_t *offp)
1090{
1091 struct tool_ctx *tc = filep->private_data;
1092
1093 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->peer_db_set,
1094 tc->ntb->ops->peer_db_clear);
1095}
1096
1097static TOOL_FOPS_RDWR(tool_peer_db_fops,
1098 tool_peer_db_read,
1099 tool_peer_db_write);
1100
1101static ssize_t tool_peer_db_mask_read(struct file *filep, char __user *ubuf,
1102 size_t size, loff_t *offp)
1103{
1104 struct tool_ctx *tc = filep->private_data;
1105
1106 return tool_fn_read(tc, ubuf, size, offp,
1107 tc->ntb->ops->peer_db_read_mask);
1108}
1109
1110static ssize_t tool_peer_db_mask_write(struct file *filep,
1111 const char __user *ubuf,
1112 size_t size, loff_t *offp)
1113{
1114 struct tool_ctx *tc = filep->private_data;
1115
1116 return tool_fn_write(tc, ubuf, size, offp,
1117 tc->ntb->ops->peer_db_set_mask,
1118 tc->ntb->ops->peer_db_clear_mask);
1119}
1120
1121static TOOL_FOPS_RDWR(tool_peer_db_mask_fops,
1122 tool_peer_db_mask_read,
1123 tool_peer_db_mask_write);
1124
1125static ssize_t tool_db_event_write(struct file *filep,
1126 const char __user *ubuf,
1127 size_t size, loff_t *offp)
1128{
1129 struct tool_ctx *tc = filep->private_data;
1130 u64 val;
1131 int ret;
1132
1133 ret = kstrtou64_from_user(ubuf, size, 0, &val);
1134 if (ret)
1135 return ret;
1136
1137 if (wait_event_interruptible(tc->db_wq, ntb_db_read(tc->ntb) == val))
1138 return -ERESTART;
1139
1140 return size;
1141}
1142
1143static TOOL_FOPS_RDWR(tool_db_event_fops,
1144 NULL,
1145 tool_db_event_write);
1146
1147/*==============================================================================
1148 * Scratchpads read/write methods
1149 *==============================================================================
1150 */
1151
1152static ssize_t tool_spad_read(struct file *filep, char __user *ubuf,
1153 size_t size, loff_t *offp)
1154{
1155 struct tool_spad *spad = filep->private_data;
1156 char buf[TOOL_BUF_LEN];
1157 ssize_t pos;
1158
1159 if (!spad->tc->ntb->ops->spad_read)
1160 return -EINVAL;
1161
1162 pos = scnprintf(buf, sizeof(buf), "%#x\n",
1163 ntb_spad_read(spad->tc->ntb, spad->sidx));
1164
1165 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
1166}
1167
1168static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
1169 size_t size, loff_t *offp)
1170{
1171 struct tool_spad *spad = filep->private_data;
1172 u32 val;
1173 int ret;
1174
1175 if (!spad->tc->ntb->ops->spad_write) {
1176 dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n");
1177 return -EINVAL;
881 } 1178 }
882 1179
883 tc->dbgfs = debugfs_create_dir(dev_name(&tc->ntb->dev), 1180 ret = kstrtou32_from_user(ubuf, size, 0, &val);
884 tool_dbgfs); 1181 if (ret)
885 if (!tc->dbgfs) 1182 return ret;
886 return;
887 1183
888 debugfs_create_file("db", S_IRUSR | S_IWUSR, tc->dbgfs, 1184 ret = ntb_spad_write(spad->tc->ntb, spad->sidx, val);
889 tc, &tool_db_fops);
890 1185
891 debugfs_create_file("mask", S_IRUSR | S_IWUSR, tc->dbgfs, 1186 return ret ?: size;
892 tc, &tool_mask_fops); 1187}
893 1188
894 debugfs_create_file("peer_db", S_IRUSR | S_IWUSR, tc->dbgfs, 1189static TOOL_FOPS_RDWR(tool_spad_fops,
895 tc, &tool_peer_db_fops); 1190 tool_spad_read,
1191 tool_spad_write);
896 1192
897 debugfs_create_file("peer_mask", S_IRUSR | S_IWUSR, tc->dbgfs, 1193static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
898 tc, &tool_peer_mask_fops); 1194 size_t size, loff_t *offp)
1195{
1196 struct tool_spad *spad = filep->private_data;
1197 char buf[TOOL_BUF_LEN];
1198 ssize_t pos;
899 1199
900 debugfs_create_file("spad", S_IRUSR | S_IWUSR, tc->dbgfs, 1200 if (!spad->tc->ntb->ops->peer_spad_read)
901 tc, &tool_spad_fops); 1201 return -EINVAL;
902 1202
903 debugfs_create_file("peer_spad", S_IRUSR | S_IWUSR, tc->dbgfs, 1203 pos = scnprintf(buf, sizeof(buf), "%#x\n",
904 tc, &tool_peer_spad_fops); 1204 ntb_peer_spad_read(spad->tc->ntb, spad->pidx, spad->sidx));
905 1205
906 debugfs_create_file("link", S_IRUSR | S_IWUSR, tc->dbgfs, 1206 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
907 tc, &tool_link_fops); 1207}
908 1208
909 debugfs_create_file("link_event", S_IWUSR, tc->dbgfs, 1209static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
910 tc, &tool_link_event_fops); 1210 size_t size, loff_t *offp)
1211{
1212 struct tool_spad *spad = filep->private_data;
1213 u32 val;
1214 int ret;
1215
1216 if (!spad->tc->ntb->ops->peer_spad_write) {
1217 dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n");
1218 return -EINVAL;
1219 }
1220
1221 ret = kstrtou32_from_user(ubuf, size, 0, &val);
1222 if (ret)
1223 return ret;
1224
1225 ret = ntb_peer_spad_write(spad->tc->ntb, spad->pidx, spad->sidx, val);
1226
1227 return ret ?: size;
1228}
911 1229
912 for (i = 0; i < tc->mw_count; i++) { 1230static TOOL_FOPS_RDWR(tool_peer_spad_fops,
913 char buf[30]; 1231 tool_peer_spad_read,
1232 tool_peer_spad_write);
914 1233
915 snprintf(buf, sizeof(buf), "mw%d", i); 1234static int tool_init_spads(struct tool_ctx *tc)
916 debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs, 1235{
917 &tc->mws[i], &tool_mw_fops); 1236 int sidx, pidx;
1237
1238 /* Initialize inbound scratchpad structures */
1239 tc->inspad_cnt = ntb_spad_count(tc->ntb);
1240 tc->inspads = devm_kcalloc(&tc->ntb->dev, tc->inspad_cnt,
1241 sizeof(*tc->inspads), GFP_KERNEL);
1242 if (tc->inspads == NULL)
1243 return -ENOMEM;
1244
1245 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) {
1246 tc->inspads[sidx].sidx = sidx;
1247 tc->inspads[sidx].pidx = -1;
1248 tc->inspads[sidx].tc = tc;
1249 }
918 1250
919 snprintf(buf, sizeof(buf), "peer_trans%d", i); 1251 /* Initialize outbound scratchpad structures */
920 debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs, 1252 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
921 &tc->mws[i], &tool_peer_mw_trans_fops); 1253 tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->ntb);
1254 tc->peers[pidx].outspads =
1255 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outspad_cnt,
1256 sizeof(*tc->peers[pidx].outspads), GFP_KERNEL);
1257 if (tc->peers[pidx].outspads == NULL)
1258 return -ENOMEM;
1259
1260 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) {
1261 tc->peers[pidx].outspads[sidx].sidx = sidx;
1262 tc->peers[pidx].outspads[sidx].pidx = pidx;
1263 tc->peers[pidx].outspads[sidx].tc = tc;
1264 }
922 } 1265 }
1266
1267 return 0;
923} 1268}
924 1269
925static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) 1270/*==============================================================================
1271 * Messages read/write methods
1272 *==============================================================================
1273 */
1274
1275static ssize_t tool_inmsg_read(struct file *filep, char __user *ubuf,
1276 size_t size, loff_t *offp)
926{ 1277{
927 struct tool_ctx *tc; 1278 struct tool_msg *msg = filep->private_data;
928 int rc; 1279 char buf[TOOL_BUF_LEN];
929 int i; 1280 ssize_t pos;
1281 u32 data;
1282 int pidx;
1283
1284 data = ntb_msg_read(msg->tc->ntb, &pidx, msg->midx);
1285
1286 pos = scnprintf(buf, sizeof(buf), "0x%08x<-%d\n", data, pidx);
1287
1288 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
1289}
1290
1291static TOOL_FOPS_RDWR(tool_inmsg_fops,
1292 tool_inmsg_read,
1293 NULL);
1294
1295static ssize_t tool_outmsg_write(struct file *filep,
1296 const char __user *ubuf,
1297 size_t size, loff_t *offp)
1298{
1299 struct tool_msg *msg = filep->private_data;
1300 u32 val;
1301 int ret;
1302
1303 ret = kstrtou32_from_user(ubuf, size, 0, &val);
1304 if (ret)
1305 return ret;
1306
1307 ret = ntb_peer_msg_write(msg->tc->ntb, msg->pidx, msg->midx, val);
1308
1309 return ret ? : size;
1310}
1311
1312static TOOL_FOPS_RDWR(tool_outmsg_fops,
1313 NULL,
1314 tool_outmsg_write);
1315
1316static ssize_t tool_msg_sts_read(struct file *filep, char __user *ubuf,
1317 size_t size, loff_t *offp)
1318{
1319 struct tool_ctx *tc = filep->private_data;
1320
1321 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_read_sts);
1322}
1323
1324static ssize_t tool_msg_sts_write(struct file *filep, const char __user *ubuf,
1325 size_t size, loff_t *offp)
1326{
1327 struct tool_ctx *tc = filep->private_data;
1328
1329 return tool_fn_write(tc, ubuf, size, offp, NULL,
1330 tc->ntb->ops->msg_clear_sts);
1331}
1332
1333static TOOL_FOPS_RDWR(tool_msg_sts_fops,
1334 tool_msg_sts_read,
1335 tool_msg_sts_write);
1336
1337static ssize_t tool_msg_inbits_read(struct file *filep, char __user *ubuf,
1338 size_t size, loff_t *offp)
1339{
1340 struct tool_ctx *tc = filep->private_data;
1341
1342 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_inbits);
1343}
1344
1345static TOOL_FOPS_RDWR(tool_msg_inbits_fops,
1346 tool_msg_inbits_read,
1347 NULL);
930 1348
931 if (!ntb->ops->mw_set_trans) { 1349static ssize_t tool_msg_outbits_read(struct file *filep, char __user *ubuf,
932 dev_dbg(&ntb->dev, "need inbound MW based NTB API\n"); 1350 size_t size, loff_t *offp)
933 rc = -EINVAL; 1351{
934 goto err_tc; 1352 struct tool_ctx *tc = filep->private_data;
1353
1354 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_outbits);
1355}
1356
1357static TOOL_FOPS_RDWR(tool_msg_outbits_fops,
1358 tool_msg_outbits_read,
1359 NULL);
1360
1361static ssize_t tool_msg_mask_write(struct file *filep, const char __user *ubuf,
1362 size_t size, loff_t *offp)
1363{
1364 struct tool_ctx *tc = filep->private_data;
1365
1366 return tool_fn_write(tc, ubuf, size, offp,
1367 tc->ntb->ops->msg_set_mask,
1368 tc->ntb->ops->msg_clear_mask);
1369}
1370
1371static TOOL_FOPS_RDWR(tool_msg_mask_fops,
1372 NULL,
1373 tool_msg_mask_write);
1374
1375static ssize_t tool_msg_event_write(struct file *filep,
1376 const char __user *ubuf,
1377 size_t size, loff_t *offp)
1378{
1379 struct tool_ctx *tc = filep->private_data;
1380 u64 val;
1381 int ret;
1382
1383 ret = kstrtou64_from_user(ubuf, size, 0, &val);
1384 if (ret)
1385 return ret;
1386
1387 if (wait_event_interruptible(tc->msg_wq,
1388 ntb_msg_read_sts(tc->ntb) == val))
1389 return -ERESTART;
1390
1391 return size;
1392}
1393
1394static TOOL_FOPS_RDWR(tool_msg_event_fops,
1395 NULL,
1396 tool_msg_event_write);
1397
1398static int tool_init_msgs(struct tool_ctx *tc)
1399{
1400 int midx, pidx;
1401
1402 /* Initialize inbound message structures */
1403 tc->inmsg_cnt = ntb_msg_count(tc->ntb);
1404 tc->inmsgs = devm_kcalloc(&tc->ntb->dev, tc->inmsg_cnt,
1405 sizeof(*tc->inmsgs), GFP_KERNEL);
1406 if (tc->inmsgs == NULL)
1407 return -ENOMEM;
1408
1409 for (midx = 0; midx < tc->inmsg_cnt; midx++) {
1410 tc->inmsgs[midx].midx = midx;
1411 tc->inmsgs[midx].pidx = -1;
1412 tc->inmsgs[midx].tc = tc;
935 } 1413 }
936 1414
937 if (ntb_spad_count(ntb) < 1) { 1415 /* Initialize outbound message structures */
938 dev_dbg(&ntb->dev, "no enough scratchpads\n"); 1416 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
939 rc = -EINVAL; 1417 tc->peers[pidx].outmsg_cnt = ntb_msg_count(tc->ntb);
940 goto err_tc; 1418 tc->peers[pidx].outmsgs =
1419 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmsg_cnt,
1420 sizeof(*tc->peers[pidx].outmsgs), GFP_KERNEL);
1421 if (tc->peers[pidx].outmsgs == NULL)
1422 return -ENOMEM;
1423
1424 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) {
1425 tc->peers[pidx].outmsgs[midx].midx = midx;
1426 tc->peers[pidx].outmsgs[midx].pidx = pidx;
1427 tc->peers[pidx].outmsgs[midx].tc = tc;
1428 }
941 } 1429 }
942 1430
1431 return 0;
1432}
1433
1434/*==============================================================================
1435 * Initialization methods
1436 *==============================================================================
1437 */
1438
1439static struct tool_ctx *tool_create_data(struct ntb_dev *ntb)
1440{
1441 struct tool_ctx *tc;
1442
1443 tc = devm_kzalloc(&ntb->dev, sizeof(*tc), GFP_KERNEL);
1444 if (tc == NULL)
1445 return ERR_PTR(-ENOMEM);
1446
1447 tc->ntb = ntb;
1448 init_waitqueue_head(&tc->link_wq);
1449 init_waitqueue_head(&tc->db_wq);
1450 init_waitqueue_head(&tc->msg_wq);
1451
943 if (ntb_db_is_unsafe(ntb)) 1452 if (ntb_db_is_unsafe(ntb))
944 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 1453 dev_dbg(&ntb->dev, "doorbell is unsafe\n");
945 1454
946 if (ntb_spad_is_unsafe(ntb)) 1455 if (ntb_spad_is_unsafe(ntb))
947 dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 1456 dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
948 1457
949 if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT) 1458 return tc;
950 dev_warn(&ntb->dev, "multi-port NTB is unsupported\n"); 1459}
1460
1461static void tool_clear_data(struct tool_ctx *tc)
1462{
1463 wake_up(&tc->link_wq);
1464 wake_up(&tc->db_wq);
1465 wake_up(&tc->msg_wq);
1466}
1467
1468static int tool_init_ntb(struct tool_ctx *tc)
1469{
1470 return ntb_set_ctx(tc->ntb, tc, &tool_ops);
1471}
951 1472
952 tc = kzalloc(sizeof(*tc), GFP_KERNEL); 1473static void tool_clear_ntb(struct tool_ctx *tc)
953 if (!tc) { 1474{
954 rc = -ENOMEM; 1475 ntb_clear_ctx(tc->ntb);
955 goto err_tc; 1476 ntb_link_disable(tc->ntb);
1477}
1478
1479static void tool_setup_dbgfs(struct tool_ctx *tc)
1480{
1481 int pidx, widx, sidx, midx;
1482 char buf[TOOL_BUF_LEN];
1483
1484 /* This modules is useless without dbgfs... */
1485 if (!tool_dbgfs_topdir) {
1486 tc->dbgfs_dir = NULL;
1487 return;
956 } 1488 }
957 1489
958 tc->ntb = ntb; 1490 tc->dbgfs_dir = debugfs_create_dir(dev_name(&tc->ntb->dev),
959 init_waitqueue_head(&tc->link_wq); 1491 tool_dbgfs_topdir);
1492 if (!tc->dbgfs_dir)
1493 return;
1494
1495 debugfs_create_file("port", 0600, tc->dbgfs_dir,
1496 tc, &tool_port_fops);
1497
1498 debugfs_create_file("link", 0600, tc->dbgfs_dir,
1499 tc, &tool_link_fops);
1500
1501 debugfs_create_file("db", 0600, tc->dbgfs_dir,
1502 tc, &tool_db_fops);
1503
1504 debugfs_create_file("db_valid_mask", 0600, tc->dbgfs_dir,
1505 tc, &tool_db_valid_mask_fops);
1506
1507 debugfs_create_file("db_mask", 0600, tc->dbgfs_dir,
1508 tc, &tool_db_mask_fops);
960 1509
961 tc->mw_count = min(ntb_peer_mw_count(tc->ntb), MAX_MWS); 1510 debugfs_create_file("db_event", 0600, tc->dbgfs_dir,
962 for (i = 0; i < tc->mw_count; i++) { 1511 tc, &tool_db_event_fops);
963 rc = tool_init_mw(tc, i); 1512
964 if (rc) 1513 debugfs_create_file("peer_db", 0600, tc->dbgfs_dir,
965 goto err_ctx; 1514 tc, &tool_peer_db_fops);
1515
1516 debugfs_create_file("peer_db_mask", 0600, tc->dbgfs_dir,
1517 tc, &tool_peer_db_mask_fops);
1518
1519 if (tc->inspad_cnt != 0) {
1520 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) {
1521 snprintf(buf, sizeof(buf), "spad%d", sidx);
1522
1523 debugfs_create_file(buf, 0600, tc->dbgfs_dir,
1524 &tc->inspads[sidx], &tool_spad_fops);
1525 }
966 } 1526 }
967 1527
968 tool_setup_dbgfs(tc); 1528 if (tc->inmsg_cnt != 0) {
1529 for (midx = 0; midx < tc->inmsg_cnt; midx++) {
1530 snprintf(buf, sizeof(buf), "msg%d", midx);
1531 debugfs_create_file(buf, 0600, tc->dbgfs_dir,
1532 &tc->inmsgs[midx], &tool_inmsg_fops);
1533 }
1534
1535 debugfs_create_file("msg_sts", 0600, tc->dbgfs_dir,
1536 tc, &tool_msg_sts_fops);
1537
1538 debugfs_create_file("msg_inbits", 0600, tc->dbgfs_dir,
1539 tc, &tool_msg_inbits_fops);
969 1540
970 rc = ntb_set_ctx(ntb, tc, &tool_ops); 1541 debugfs_create_file("msg_outbits", 0600, tc->dbgfs_dir,
971 if (rc) 1542 tc, &tool_msg_outbits_fops);
972 goto err_ctx;
973 1543
974 ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 1544 debugfs_create_file("msg_mask", 0600, tc->dbgfs_dir,
975 ntb_link_event(ntb); 1545 tc, &tool_msg_mask_fops);
1546
1547 debugfs_create_file("msg_event", 0600, tc->dbgfs_dir,
1548 tc, &tool_msg_event_fops);
1549 }
1550
1551 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
1552 snprintf(buf, sizeof(buf), "peer%d", pidx);
1553 tc->peers[pidx].dbgfs_dir =
1554 debugfs_create_dir(buf, tc->dbgfs_dir);
1555
1556 debugfs_create_file("port", 0600,
1557 tc->peers[pidx].dbgfs_dir,
1558 &tc->peers[pidx], &tool_peer_port_fops);
1559
1560 debugfs_create_file("link", 0200,
1561 tc->peers[pidx].dbgfs_dir,
1562 &tc->peers[pidx], &tool_peer_link_fops);
1563
1564 debugfs_create_file("link_event", 0200,
1565 tc->peers[pidx].dbgfs_dir,
1566 &tc->peers[pidx], &tool_peer_link_event_fops);
1567
1568 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) {
1569 snprintf(buf, sizeof(buf), "mw_trans%d", widx);
1570 debugfs_create_file(buf, 0600,
1571 tc->peers[pidx].dbgfs_dir,
1572 &tc->peers[pidx].inmws[widx],
1573 &tool_mw_trans_fops);
1574 }
1575
1576 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) {
1577 snprintf(buf, sizeof(buf), "peer_mw_trans%d", widx);
1578 debugfs_create_file(buf, 0600,
1579 tc->peers[pidx].dbgfs_dir,
1580 &tc->peers[pidx].outmws[widx],
1581 &tool_peer_mw_trans_fops);
1582 }
1583
1584 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) {
1585 snprintf(buf, sizeof(buf), "spad%d", sidx);
1586
1587 debugfs_create_file(buf, 0600,
1588 tc->peers[pidx].dbgfs_dir,
1589 &tc->peers[pidx].outspads[sidx],
1590 &tool_peer_spad_fops);
1591 }
1592
1593 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) {
1594 snprintf(buf, sizeof(buf), "msg%d", midx);
1595 debugfs_create_file(buf, 0600,
1596 tc->peers[pidx].dbgfs_dir,
1597 &tc->peers[pidx].outmsgs[midx],
1598 &tool_outmsg_fops);
1599 }
1600 }
1601}
1602
1603static void tool_clear_dbgfs(struct tool_ctx *tc)
1604{
1605 debugfs_remove_recursive(tc->dbgfs_dir);
1606}
1607
1608static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
1609{
1610 struct tool_ctx *tc;
1611 int ret;
1612
1613 tc = tool_create_data(ntb);
1614 if (IS_ERR(tc))
1615 return PTR_ERR(tc);
1616
1617 ret = tool_init_peers(tc);
1618 if (ret != 0)
1619 goto err_clear_data;
1620
1621 ret = tool_init_mws(tc);
1622 if (ret != 0)
1623 goto err_clear_data;
1624
1625 ret = tool_init_spads(tc);
1626 if (ret != 0)
1627 goto err_clear_mws;
1628
1629 ret = tool_init_msgs(tc);
1630 if (ret != 0)
1631 goto err_clear_mws;
1632
1633 ret = tool_init_ntb(tc);
1634 if (ret != 0)
1635 goto err_clear_mws;
1636
1637 tool_setup_dbgfs(tc);
976 1638
977 return 0; 1639 return 0;
978 1640
979err_ctx: 1641err_clear_mws:
980 tool_free_mws(tc); 1642 tool_clear_mws(tc);
981 debugfs_remove_recursive(tc->dbgfs); 1643
982 kfree(tc); 1644err_clear_data:
983err_tc: 1645 tool_clear_data(tc);
984 return rc; 1646
1647 return ret;
985} 1648}
986 1649
987static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb) 1650static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb)
988{ 1651{
989 struct tool_ctx *tc = ntb->ctx; 1652 struct tool_ctx *tc = ntb->ctx;
990 1653
991 tool_free_mws(tc); 1654 tool_clear_dbgfs(tc);
992 1655
993 ntb_clear_ctx(ntb); 1656 tool_clear_ntb(tc);
994 ntb_link_disable(ntb);
995 1657
996 debugfs_remove_recursive(tc->dbgfs); 1658 tool_clear_mws(tc);
997 kfree(tc); 1659
1660 tool_clear_data(tc);
998} 1661}
999 1662
1000static struct ntb_client tool_client = { 1663static struct ntb_client tool_client = {
1001 .ops = { 1664 .ops = {
1002 .probe = tool_probe, 1665 .probe = tool_probe,
1003 .remove = tool_remove, 1666 .remove = tool_remove,
1004 }, 1667 }
1005}; 1668};
1006 1669
1007static int __init tool_init(void) 1670static int __init tool_init(void)
1008{ 1671{
1009 int rc; 1672 int ret;
1010 1673
1011 if (debugfs_initialized()) 1674 if (debugfs_initialized())
1012 tool_dbgfs = debugfs_create_dir(KBUILD_MODNAME, NULL); 1675 tool_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
1013 1676
1014 rc = ntb_register_client(&tool_client); 1677 ret = ntb_register_client(&tool_client);
1015 if (rc) 1678 if (ret)
1016 goto err_client; 1679 debugfs_remove_recursive(tool_dbgfs_topdir);
1017 1680
1018 return 0; 1681 return ret;
1019
1020err_client:
1021 debugfs_remove_recursive(tool_dbgfs);
1022 return rc;
1023} 1682}
1024module_init(tool_init); 1683module_init(tool_init);
1025 1684
1026static void __exit tool_exit(void) 1685static void __exit tool_exit(void)
1027{ 1686{
1028 ntb_unregister_client(&tool_client); 1687 ntb_unregister_client(&tool_client);
1029 debugfs_remove_recursive(tool_dbgfs); 1688 debugfs_remove_recursive(tool_dbgfs_topdir);
1030} 1689}
1031module_exit(tool_exit); 1690module_exit(tool_exit);
1691