cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ntb_tool.c (43490B)


      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, 2);
    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->pdev->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->pdev->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->pdev->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%pap\n",
    682			 &inmw->size);
    683
    684	off += scnprintf(buf + off, buf_size - off,
    685			 "Alignment      \t%pap\n",
    686			 &addr_align);
    687
    688	off += scnprintf(buf + off, buf_size - off,
    689			 "Size Alignment \t%pap\n",
    690			 &size_align);
    691
    692	off += scnprintf(buf + off, buf_size - off,
    693			 "Size Max       \t%pap\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%pap\n", &map_base);
    911
    912	off += scnprintf(buf + off, buf_size - off,
    913			 "Mapping Size        \t%pap\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%pap\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);