Linux Audio

Check our new training course

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