aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ntb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ntb')
-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