Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This file is provided under a dual BSD/GPLv2 license.  When using or
0003  *   redistributing this file, you may do so under either license.
0004  *
0005  *   GPL LICENSE SUMMARY
0006  *
0007  *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
0008  *   Copyright (C) 2017 T-Platforms All Rights Reserved.
0009  *
0010  *   This program is free software; you can redistribute it and/or modify
0011  *   it under the terms of version 2 of the GNU General Public License as
0012  *   published by the Free Software Foundation.
0013  *
0014  *   This program is distributed in the hope that it will be useful, but
0015  *   WITHOUT ANY WARRANTY; without even the implied warranty of
0016  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017  *   General Public License for more details.
0018  *
0019  *   BSD LICENSE
0020  *
0021  *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
0022  *   Copyright (C) 2017 T-Platforms All Rights Reserved.
0023  *
0024  *   Redistribution and use in source and binary forms, with or without
0025  *   modification, are permitted provided that the following conditions
0026  *   are met:
0027  *
0028  *     * Redistributions of source code must retain the above copyright
0029  *       notice, this list of conditions and the following disclaimer.
0030  *     * Redistributions in binary form must reproduce the above copy
0031  *       notice, this list of conditions and the following disclaimer in
0032  *       the documentation and/or other materials provided with the
0033  *       distribution.
0034  *     * Neither the name of Intel Corporation nor the names of its
0035  *       contributors may be used to endorse or promote products derived
0036  *       from this software without specific prior written permission.
0037  *
0038  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0039  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0040  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0041  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0042  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0043  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0044  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0045  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0046  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0047  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0048  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0049  *
0050  * PCIe NTB Debugging Tool Linux driver
0051  */
0052 
0053 /*
0054  * How to use this tool, by example.
0055  *
0056  * Assuming $DBG_DIR is something like:
0057  * '/sys/kernel/debug/ntb_tool/0000:00:03.0'
0058  * Suppose aside from local device there is at least one remote device
0059  * connected to NTB with index 0.
0060  *-----------------------------------------------------------------------------
0061  * Eg: check local/peer device information.
0062  *
0063  * # Get local device port number
0064  * root@self# cat $DBG_DIR/port
0065  *
0066  * # Check local device functionality
0067  * root@self# ls $DBG_DIR
0068  * db            msg1          msg_sts     peer4/        port
0069  * db_event      msg2          peer0/      peer5/        spad0
0070  * db_mask       msg3          peer1/      peer_db       spad1
0071  * link          msg_event     peer2/      peer_db_mask  spad2
0072  * msg0          msg_mask      peer3/      peer_spad     spad3
0073  * # As one can see it supports:
0074  * # 1) four inbound message registers
0075  * # 2) four inbound scratchpads
0076  * # 3) up to six peer devices
0077  *
0078  * # Check peer device port number
0079  * root@self# cat $DBG_DIR/peer0/port
0080  *
0081  * # Check peer device(s) functionality to be used
0082  * root@self# ls $DBG_DIR/peer0
0083  * link             mw_trans0       mw_trans6        port
0084  * link_event       mw_trans1       mw_trans7        spad0
0085  * msg0             mw_trans2       peer_mw_trans0   spad1
0086  * msg1             mw_trans3       peer_mw_trans1   spad2
0087  * msg2             mw_trans4       peer_mw_trans2   spad3
0088  * msg3             mw_trans5       peer_mw_trans3
0089  * # As one can see we got:
0090  * # 1) four outbound message registers
0091  * # 2) four outbound scratchpads
0092  * # 3) eight inbound memory windows
0093  * # 4) four outbound memory windows
0094  *-----------------------------------------------------------------------------
0095  * Eg: NTB link tests
0096  *
0097  * # Set local link up/down
0098  * root@self# echo Y > $DBG_DIR/link
0099  * root@self# echo N > $DBG_DIR/link
0100  *
0101  * # Check if link with peer device is up/down:
0102  * root@self# cat $DBG_DIR/peer0/link
0103  *
0104  * # Block until the link is up/down
0105  * root@self# echo Y > $DBG_DIR/peer0/link_event
0106  * root@self# echo N > $DBG_DIR/peer0/link_event
0107  *-----------------------------------------------------------------------------
0108  * Eg: Doorbell registers tests (some functionality might be absent)
0109  *
0110  * # Set/clear/get local doorbell
0111  * root@self# echo 's 1' > $DBG_DIR/db
0112  * root@self# echo 'c 1' > $DBG_DIR/db
0113  * root@self# cat  $DBG_DIR/db
0114  *
0115  * # Set/clear/get local doorbell mask
0116  * root@self# echo 's 1' > $DBG_DIR/db_mask
0117  * root@self# echo 'c 1' > $DBG_DIR/db_mask
0118  * root@self# cat $DBG_DIR/db_mask
0119  *
0120  * # Ring/clear/get peer doorbell
0121  * root@peer# echo 's 1' > $DBG_DIR/peer_db
0122  * root@peer# echo 'c 1' > $DBG_DIR/peer_db
0123  * root@peer# cat $DBG_DIR/peer_db
0124  *
0125  * # Set/clear/get peer doorbell mask
0126  * root@self# echo 's 1' > $DBG_DIR/peer_db_mask
0127  * root@self# echo 'c 1' > $DBG_DIR/peer_db_mask
0128  * root@self# cat $DBG_DIR/peer_db_mask
0129  *
0130  * # Block until local doorbell is set with specified value
0131  * root@self# echo 1 > $DBG_DIR/db_event
0132  *-----------------------------------------------------------------------------
0133  * Eg: Message registers tests (functionality might be absent)
0134  *
0135  * # Set/clear/get in/out message registers status
0136  * root@self# echo 's 1' > $DBG_DIR/msg_sts
0137  * root@self# echo 'c 1' > $DBG_DIR/msg_sts
0138  * root@self# cat $DBG_DIR/msg_sts
0139  *
0140  * # Set/clear in/out message registers mask
0141  * root@self# echo 's 1' > $DBG_DIR/msg_mask
0142  * root@self# echo 'c 1' > $DBG_DIR/msg_mask
0143  *
0144  * # Get inbound message register #0 value and source of port index
0145  * root@self# cat  $DBG_DIR/msg0
0146  *
0147  * # Send some data to peer over outbound message register #0
0148  * root@self# echo 0x01020304 > $DBG_DIR/peer0/msg0
0149  *-----------------------------------------------------------------------------
0150  * Eg: Scratchpad registers tests (functionality might be absent)
0151  *
0152  * # Write/read to/from local scratchpad register #0
0153  * root@peer# echo 0x01020304 > $DBG_DIR/spad0
0154  * root@peer# cat $DBG_DIR/spad0
0155  *
0156  * # Write/read to/from peer scratchpad register #0
0157  * root@peer# echo 0x01020304 > $DBG_DIR/peer0/spad0
0158  * root@peer# cat $DBG_DIR/peer0/spad0
0159  *-----------------------------------------------------------------------------
0160  * Eg: Memory windows tests
0161  *
0162  * # Create inbound memory window buffer of specified size/get its base address
0163  * root@peer# echo 16384 > $DBG_DIR/peer0/mw_trans0
0164  * root@peer# cat $DBG_DIR/peer0/mw_trans0
0165  *
0166  * # Write/read data to/from inbound memory window
0167  * root@peer# echo Hello > $DBG_DIR/peer0/mw0
0168  * root@peer# head -c 7 $DBG_DIR/peer0/mw0
0169  *
0170  * # Map outbound memory window/check it settings (on peer device)
0171  * root@peer# echo 0xADD0BA5E:16384 > $DBG_DIR/peer0/peer_mw_trans0
0172  * root@peer# cat $DBG_DIR/peer0/peer_mw_trans0
0173  *
0174  * # Write/read data to/from outbound memory window (on peer device)
0175  * root@peer# echo olleH > $DBG_DIR/peer0/peer_mw0
0176  * root@peer# head -c 7 $DBG_DIR/peer0/peer_mw0
0177  */
0178 
0179 #include <linux/init.h>
0180 #include <linux/kernel.h>
0181 #include <linux/module.h>
0182 
0183 #include <linux/debugfs.h>
0184 #include <linux/dma-mapping.h>
0185 #include <linux/pci.h>
0186 #include <linux/slab.h>
0187 #include <linux/uaccess.h>
0188 
0189 #include <linux/ntb.h>
0190 
0191 #define DRIVER_NAME     "ntb_tool"
0192 #define DRIVER_VERSION      "2.0"
0193 
0194 MODULE_LICENSE("Dual BSD/GPL");
0195 MODULE_VERSION(DRIVER_VERSION);
0196 MODULE_AUTHOR("Allen Hubbe <Allen.Hubbe@emc.com>");
0197 MODULE_DESCRIPTION("PCIe NTB Debugging Tool");
0198 
0199 /*
0200  * Inbound and outbound memory windows descriptor. Union members selection
0201  * depends on the MW type the structure describes. mm_base/dma_base are the
0202  * virtual and DMA address of an inbound MW. io_base/tr_base are the MMIO
0203  * mapped virtual and xlat addresses of an outbound MW respectively.
0204  */
0205 struct tool_mw {
0206     int widx;
0207     int pidx;
0208     struct tool_ctx *tc;
0209     union {
0210         u8 *mm_base;
0211         u8 __iomem *io_base;
0212     };
0213     union {
0214         dma_addr_t dma_base;
0215         u64 tr_base;
0216     };
0217     resource_size_t size;
0218     struct dentry *dbgfs_file;
0219 };
0220 
0221 /*
0222  * Wrapper structure is used to distinguish the outbound MW peers reference
0223  * within the corresponding DebugFS directory IO operation.
0224  */
0225 struct tool_mw_wrap {
0226     int pidx;
0227     struct tool_mw *mw;
0228 };
0229 
0230 struct tool_msg {
0231     int midx;
0232     int pidx;
0233     struct tool_ctx *tc;
0234 };
0235 
0236 struct tool_spad {
0237     int sidx;
0238     int pidx;
0239     struct tool_ctx *tc;
0240 };
0241 
0242 struct tool_peer {
0243     int pidx;
0244     struct tool_ctx *tc;
0245     int inmw_cnt;
0246     struct tool_mw *inmws;
0247     int outmw_cnt;
0248     struct tool_mw_wrap *outmws;
0249     int outmsg_cnt;
0250     struct tool_msg *outmsgs;
0251     int outspad_cnt;
0252     struct tool_spad *outspads;
0253     struct dentry *dbgfs_dir;
0254 };
0255 
0256 struct tool_ctx {
0257     struct ntb_dev *ntb;
0258     wait_queue_head_t link_wq;
0259     wait_queue_head_t db_wq;
0260     wait_queue_head_t msg_wq;
0261     int outmw_cnt;
0262     struct tool_mw *outmws;
0263     int peer_cnt;
0264     struct tool_peer *peers;
0265     int inmsg_cnt;
0266     struct tool_msg *inmsgs;
0267     int inspad_cnt;
0268     struct tool_spad *inspads;
0269     struct dentry *dbgfs_dir;
0270 };
0271 
0272 #define TOOL_FOPS_RDWR(__name, __read, __write) \
0273     const struct file_operations __name = { \
0274         .owner = THIS_MODULE,       \
0275         .open = simple_open,        \
0276         .read = __read,         \
0277         .write = __write,       \
0278     }
0279 
0280 #define TOOL_BUF_LEN 32
0281 
0282 static struct dentry *tool_dbgfs_topdir;
0283 
0284 /*==============================================================================
0285  *                               NTB events handlers
0286  *==============================================================================
0287  */
0288 
0289 static void tool_link_event(void *ctx)
0290 {
0291     struct tool_ctx *tc = ctx;
0292     enum ntb_speed speed;
0293     enum ntb_width width;
0294     int up;
0295 
0296     up = ntb_link_is_up(tc->ntb, &speed, &width);
0297 
0298     dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n",
0299         up ? "up" : "down", speed, width);
0300 
0301     wake_up(&tc->link_wq);
0302 }
0303 
0304 static void tool_db_event(void *ctx, int vec)
0305 {
0306     struct tool_ctx *tc = ctx;
0307     u64 db_bits, db_mask;
0308 
0309     db_mask = ntb_db_vector_mask(tc->ntb, vec);
0310     db_bits = ntb_db_read(tc->ntb);
0311 
0312     dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n",
0313         vec, db_mask, db_bits);
0314 
0315     wake_up(&tc->db_wq);
0316 }
0317 
0318 static void tool_msg_event(void *ctx)
0319 {
0320     struct tool_ctx *tc = ctx;
0321     u64 msg_sts;
0322 
0323     msg_sts = ntb_msg_read_sts(tc->ntb);
0324 
0325     dev_dbg(&tc->ntb->dev, "message bits %#llx\n", msg_sts);
0326 
0327     wake_up(&tc->msg_wq);
0328 }
0329 
0330 static const struct ntb_ctx_ops tool_ops = {
0331     .link_event = tool_link_event,
0332     .db_event = tool_db_event,
0333     .msg_event = tool_msg_event
0334 };
0335 
0336 /*==============================================================================
0337  *                        Common read/write methods
0338  *==============================================================================
0339  */
0340 
0341 static ssize_t tool_fn_read(struct tool_ctx *tc, char __user *ubuf,
0342                 size_t size, loff_t *offp,
0343                 u64 (*fn_read)(struct ntb_dev *))
0344 {
0345     size_t buf_size;
0346     char buf[TOOL_BUF_LEN];
0347     ssize_t pos;
0348 
0349     if (!fn_read)
0350         return -EINVAL;
0351 
0352     buf_size = min(size, sizeof(buf));
0353 
0354     pos = scnprintf(buf, buf_size, "%#llx\n", fn_read(tc->ntb));
0355 
0356     return simple_read_from_buffer(ubuf, size, offp, buf, pos);
0357 }
0358 
0359 static ssize_t tool_fn_write(struct tool_ctx *tc,
0360                  const char __user *ubuf,
0361                  size_t size, loff_t *offp,
0362                  int (*fn_set)(struct ntb_dev *, u64),
0363                  int (*fn_clear)(struct ntb_dev *, u64))
0364 {
0365     char *buf, cmd;
0366     ssize_t ret;
0367     u64 bits;
0368     int n;
0369 
0370     if (*offp)
0371         return 0;
0372 
0373     buf = kmalloc(size + 1, GFP_KERNEL);
0374     if (!buf)
0375         return -ENOMEM;
0376 
0377     if (copy_from_user(buf, ubuf, size)) {
0378         kfree(buf);
0379         return -EFAULT;
0380     }
0381 
0382     buf[size] = 0;
0383 
0384     n = sscanf(buf, "%c %lli", &cmd, &bits);
0385 
0386     kfree(buf);
0387 
0388     if (n != 2) {
0389         ret = -EINVAL;
0390     } else if (cmd == 's') {
0391         if (!fn_set)
0392             ret = -EINVAL;
0393         else
0394             ret = fn_set(tc->ntb, bits);
0395     } else if (cmd == 'c') {
0396         if (!fn_clear)
0397             ret = -EINVAL;
0398         else
0399             ret = fn_clear(tc->ntb, bits);
0400     } else {
0401         ret = -EINVAL;
0402     }
0403 
0404     return ret ? : size;
0405 }
0406 
0407 /*==============================================================================
0408  *                            Port read/write methods
0409  *==============================================================================
0410  */
0411 
0412 static ssize_t tool_port_read(struct file *filep, char __user *ubuf,
0413                   size_t size, loff_t *offp)
0414 {
0415     struct tool_ctx *tc = filep->private_data;
0416     char buf[TOOL_BUF_LEN];
0417     int pos;
0418 
0419     pos = scnprintf(buf, sizeof(buf), "%d\n", ntb_port_number(tc->ntb));
0420 
0421     return simple_read_from_buffer(ubuf, size, offp, buf, pos);
0422 }
0423 
0424 static TOOL_FOPS_RDWR(tool_port_fops,
0425               tool_port_read,
0426               NULL);
0427 
0428 static ssize_t tool_peer_port_read(struct file *filep, char __user *ubuf,
0429                    size_t size, loff_t *offp)
0430 {
0431     struct tool_peer *peer = filep->private_data;
0432     struct tool_ctx *tc = peer->tc;
0433     char buf[TOOL_BUF_LEN];
0434     int pos;
0435 
0436     pos = scnprintf(buf, sizeof(buf), "%d\n",
0437         ntb_peer_port_number(tc->ntb, peer->pidx));
0438 
0439     return simple_read_from_buffer(ubuf, size, offp, buf, pos);
0440 }
0441 
0442 static TOOL_FOPS_RDWR(tool_peer_port_fops,
0443               tool_peer_port_read,
0444               NULL);
0445 
0446 static int tool_init_peers(struct tool_ctx *tc)
0447 {
0448     int pidx;
0449 
0450     tc->peer_cnt = ntb_peer_port_count(tc->ntb);
0451     tc->peers = devm_kcalloc(&tc->ntb->dev, tc->peer_cnt,
0452                  sizeof(*tc->peers), GFP_KERNEL);
0453     if (tc->peers == NULL)
0454         return -ENOMEM;
0455 
0456     for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
0457         tc->peers[pidx].pidx = pidx;
0458         tc->peers[pidx].tc = tc;
0459     }
0460 
0461     return 0;
0462 }
0463 
0464 /*==============================================================================
0465  *                       Link state read/write methods
0466  *==============================================================================
0467  */
0468 
0469 static ssize_t tool_link_write(struct file *filep, const char __user *ubuf,
0470                    size_t size, loff_t *offp)
0471 {
0472     struct tool_ctx *tc = filep->private_data;
0473     bool val;
0474     int ret;
0475 
0476     ret = kstrtobool_from_user(ubuf, size, &val);
0477     if (ret)
0478         return ret;
0479 
0480     if (val)
0481         ret = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
0482     else
0483         ret = ntb_link_disable(tc->ntb);
0484 
0485     if (ret)
0486         return ret;
0487 
0488     return size;
0489 }
0490 
0491 static TOOL_FOPS_RDWR(tool_link_fops,
0492               NULL,
0493               tool_link_write);
0494 
0495 static ssize_t tool_peer_link_read(struct file *filep, char __user *ubuf,
0496                    size_t size, loff_t *offp)
0497 {
0498     struct tool_peer *peer = filep->private_data;
0499     struct tool_ctx *tc = peer->tc;
0500     char buf[3];
0501 
0502     if (ntb_link_is_up(tc->ntb, NULL, NULL) & BIT(peer->pidx))
0503         buf[0] = 'Y';
0504     else
0505         buf[0] = 'N';
0506     buf[1] = '\n';
0507     buf[2] = '\0';
0508 
0509     return simple_read_from_buffer(ubuf, size, offp, buf, 2);
0510 }
0511 
0512 static TOOL_FOPS_RDWR(tool_peer_link_fops,
0513               tool_peer_link_read,
0514               NULL);
0515 
0516 static ssize_t tool_peer_link_event_write(struct file *filep,
0517                       const char __user *ubuf,
0518                       size_t size, loff_t *offp)
0519 {
0520     struct tool_peer *peer = filep->private_data;
0521     struct tool_ctx *tc = peer->tc;
0522     u64 link_msk;
0523     bool val;
0524     int ret;
0525 
0526     ret = kstrtobool_from_user(ubuf, size, &val);
0527     if (ret)
0528         return ret;
0529 
0530     link_msk = BIT_ULL_MASK(peer->pidx);
0531 
0532     if (wait_event_interruptible(tc->link_wq,
0533         !!(ntb_link_is_up(tc->ntb, NULL, NULL) & link_msk) == val))
0534         return -ERESTART;
0535 
0536     return size;
0537 }
0538 
0539 static TOOL_FOPS_RDWR(tool_peer_link_event_fops,
0540               NULL,
0541               tool_peer_link_event_write);
0542 
0543 /*==============================================================================
0544  *                  Memory windows read/write/setting methods
0545  *==============================================================================
0546  */
0547 
0548 static ssize_t tool_mw_read(struct file *filep, char __user *ubuf,
0549                 size_t size, loff_t *offp)
0550 {
0551     struct tool_mw *inmw = filep->private_data;
0552 
0553     if (inmw->mm_base == NULL)
0554         return -ENXIO;
0555 
0556     return simple_read_from_buffer(ubuf, size, offp,
0557                        inmw->mm_base, inmw->size);
0558 }
0559 
0560 static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf,
0561                  size_t size, loff_t *offp)
0562 {
0563     struct tool_mw *inmw = filep->private_data;
0564 
0565     if (inmw->mm_base == NULL)
0566         return -ENXIO;
0567 
0568     return simple_write_to_buffer(inmw->mm_base, inmw->size, offp,
0569                       ubuf, size);
0570 }
0571 
0572 static TOOL_FOPS_RDWR(tool_mw_fops,
0573               tool_mw_read,
0574               tool_mw_write);
0575 
0576 static int tool_setup_mw(struct tool_ctx *tc, int pidx, int widx,
0577              size_t req_size)
0578 {
0579     resource_size_t size, addr_align, size_align;
0580     struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
0581     char buf[TOOL_BUF_LEN];
0582     int ret;
0583 
0584     if (inmw->mm_base != NULL)
0585         return 0;
0586 
0587     ret = ntb_mw_get_align(tc->ntb, pidx, widx, &addr_align,
0588                 &size_align, &size);
0589     if (ret)
0590         return ret;
0591 
0592     inmw->size = min_t(resource_size_t, req_size, size);
0593     inmw->size = round_up(inmw->size, addr_align);
0594     inmw->size = round_up(inmw->size, size_align);
0595     inmw->mm_base = dma_alloc_coherent(&tc->ntb->pdev->dev, inmw->size,
0596                        &inmw->dma_base, GFP_KERNEL);
0597     if (!inmw->mm_base)
0598         return -ENOMEM;
0599 
0600     if (!IS_ALIGNED(inmw->dma_base, addr_align)) {
0601         ret = -ENOMEM;
0602         goto err_free_dma;
0603     }
0604 
0605     ret = ntb_mw_set_trans(tc->ntb, pidx, widx, inmw->dma_base, inmw->size);
0606     if (ret)
0607         goto err_free_dma;
0608 
0609     snprintf(buf, sizeof(buf), "mw%d", widx);
0610     inmw->dbgfs_file = debugfs_create_file(buf, 0600,
0611                            tc->peers[pidx].dbgfs_dir, inmw,
0612                            &tool_mw_fops);
0613 
0614     return 0;
0615 
0616 err_free_dma:
0617     dma_free_coherent(&tc->ntb->pdev->dev, inmw->size, inmw->mm_base,
0618               inmw->dma_base);
0619     inmw->mm_base = NULL;
0620     inmw->dma_base = 0;
0621     inmw->size = 0;
0622 
0623     return ret;
0624 }
0625 
0626 static void tool_free_mw(struct tool_ctx *tc, int pidx, int widx)
0627 {
0628     struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
0629 
0630     debugfs_remove(inmw->dbgfs_file);
0631 
0632     if (inmw->mm_base != NULL) {
0633         ntb_mw_clear_trans(tc->ntb, pidx, widx);
0634         dma_free_coherent(&tc->ntb->pdev->dev, inmw->size,
0635                   inmw->mm_base, inmw->dma_base);
0636     }
0637 
0638     inmw->mm_base = NULL;
0639     inmw->dma_base = 0;
0640     inmw->size = 0;
0641     inmw->dbgfs_file = NULL;
0642 }
0643 
0644 static ssize_t tool_mw_trans_read(struct file *filep, char __user *ubuf,
0645                   size_t size, loff_t *offp)
0646 {
0647     struct tool_mw *inmw = filep->private_data;
0648     resource_size_t addr_align;
0649     resource_size_t size_align;
0650     resource_size_t size_max;
0651     ssize_t ret, off = 0;
0652     size_t buf_size;
0653     char *buf;
0654 
0655     buf_size = min_t(size_t, size, 512);
0656 
0657     buf = kmalloc(buf_size, GFP_KERNEL);
0658     if (!buf)
0659         return -ENOMEM;
0660 
0661     ret = ntb_mw_get_align(inmw->tc->ntb, inmw->pidx, inmw->widx,
0662                    &addr_align, &size_align, &size_max);
0663     if (ret)
0664         goto err;
0665 
0666     off += scnprintf(buf + off, buf_size - off,
0667              "Inbound MW     \t%d\n",
0668              inmw->widx);
0669 
0670     off += scnprintf(buf + off, buf_size - off,
0671              "Port           \t%d (%d)\n",
0672              ntb_peer_port_number(inmw->tc->ntb, inmw->pidx),
0673              inmw->pidx);
0674 
0675     off += scnprintf(buf + off, buf_size - off,
0676              "Window Address \t0x%pK\n", inmw->mm_base);
0677 
0678     off += scnprintf(buf + off, buf_size - off,
0679              "DMA Address    \t%pad\n",
0680              &inmw->dma_base);
0681 
0682     off += scnprintf(buf + off, buf_size - off,
0683              "Window Size    \t%pap\n",
0684              &inmw->size);
0685 
0686     off += scnprintf(buf + off, buf_size - off,
0687              "Alignment      \t%pap\n",
0688              &addr_align);
0689 
0690     off += scnprintf(buf + off, buf_size - off,
0691              "Size Alignment \t%pap\n",
0692              &size_align);
0693 
0694     off += scnprintf(buf + off, buf_size - off,
0695              "Size Max       \t%pap\n",
0696              &size_max);
0697 
0698     ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
0699 
0700 err:
0701     kfree(buf);
0702 
0703     return ret;
0704 }
0705 
0706 static ssize_t tool_mw_trans_write(struct file *filep, const char __user *ubuf,
0707                    size_t size, loff_t *offp)
0708 {
0709     struct tool_mw *inmw = filep->private_data;
0710     unsigned int val;
0711     int ret;
0712 
0713     ret = kstrtouint_from_user(ubuf, size, 0, &val);
0714     if (ret)
0715         return ret;
0716 
0717     tool_free_mw(inmw->tc, inmw->pidx, inmw->widx);
0718     if (val) {
0719         ret = tool_setup_mw(inmw->tc, inmw->pidx, inmw->widx, val);
0720         if (ret)
0721             return ret;
0722     }
0723 
0724     return size;
0725 }
0726 
0727 static TOOL_FOPS_RDWR(tool_mw_trans_fops,
0728               tool_mw_trans_read,
0729               tool_mw_trans_write);
0730 
0731 static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf,
0732                  size_t size, loff_t *offp)
0733 {
0734     struct tool_mw *outmw = filep->private_data;
0735     loff_t pos = *offp;
0736     ssize_t ret;
0737     void *buf;
0738 
0739     if (outmw->io_base == NULL)
0740         return -EIO;
0741 
0742     if (pos >= outmw->size || !size)
0743         return 0;
0744 
0745     if (size > outmw->size - pos)
0746         size = outmw->size - pos;
0747 
0748     buf = kmalloc(size, GFP_KERNEL);
0749     if (!buf)
0750         return -ENOMEM;
0751 
0752     memcpy_fromio(buf, outmw->io_base + pos, size);
0753     ret = copy_to_user(ubuf, buf, size);
0754     if (ret == size) {
0755         ret = -EFAULT;
0756         goto err_free;
0757     }
0758 
0759     size -= ret;
0760     *offp = pos + size;
0761     ret = size;
0762 
0763 err_free:
0764     kfree(buf);
0765 
0766     return ret;
0767 }
0768 
0769 static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf,
0770                   size_t size, loff_t *offp)
0771 {
0772     struct tool_mw *outmw = filep->private_data;
0773     ssize_t ret;
0774     loff_t pos = *offp;
0775     void *buf;
0776 
0777     if (outmw->io_base == NULL)
0778         return -EIO;
0779 
0780     if (pos >= outmw->size || !size)
0781         return 0;
0782     if (size > outmw->size - pos)
0783         size = outmw->size - pos;
0784 
0785     buf = kmalloc(size, GFP_KERNEL);
0786     if (!buf)
0787         return -ENOMEM;
0788 
0789     ret = copy_from_user(buf, ubuf, size);
0790     if (ret == size) {
0791         ret = -EFAULT;
0792         goto err_free;
0793     }
0794 
0795     size -= ret;
0796     *offp = pos + size;
0797     ret = size;
0798 
0799     memcpy_toio(outmw->io_base + pos, buf, size);
0800 
0801 err_free:
0802     kfree(buf);
0803 
0804     return ret;
0805 }
0806 
0807 static TOOL_FOPS_RDWR(tool_peer_mw_fops,
0808               tool_peer_mw_read,
0809               tool_peer_mw_write);
0810 
0811 static int tool_setup_peer_mw(struct tool_ctx *tc, int pidx, int widx,
0812                   u64 req_addr, size_t req_size)
0813 {
0814     struct tool_mw *outmw = &tc->outmws[widx];
0815     resource_size_t map_size;
0816     phys_addr_t map_base;
0817     char buf[TOOL_BUF_LEN];
0818     int ret;
0819 
0820     if (outmw->io_base != NULL)
0821         return 0;
0822 
0823     ret = ntb_peer_mw_get_addr(tc->ntb, widx, &map_base, &map_size);
0824     if (ret)
0825         return ret;
0826 
0827     ret = ntb_peer_mw_set_trans(tc->ntb, pidx, widx, req_addr, req_size);
0828     if (ret)
0829         return ret;
0830 
0831     outmw->io_base = ioremap_wc(map_base, map_size);
0832     if (outmw->io_base == NULL) {
0833         ret = -EFAULT;
0834         goto err_clear_trans;
0835     }
0836 
0837     outmw->tr_base = req_addr;
0838     outmw->size = req_size;
0839     outmw->pidx = pidx;
0840 
0841     snprintf(buf, sizeof(buf), "peer_mw%d", widx);
0842     outmw->dbgfs_file = debugfs_create_file(buf, 0600,
0843                            tc->peers[pidx].dbgfs_dir, outmw,
0844                            &tool_peer_mw_fops);
0845 
0846     return 0;
0847 
0848 err_clear_trans:
0849     ntb_peer_mw_clear_trans(tc->ntb, pidx, widx);
0850 
0851     return ret;
0852 }
0853 
0854 static void tool_free_peer_mw(struct tool_ctx *tc, int widx)
0855 {
0856     struct tool_mw *outmw = &tc->outmws[widx];
0857 
0858     debugfs_remove(outmw->dbgfs_file);
0859 
0860     if (outmw->io_base != NULL) {
0861         iounmap(tc->outmws[widx].io_base);
0862         ntb_peer_mw_clear_trans(tc->ntb, outmw->pidx, widx);
0863     }
0864 
0865     outmw->io_base = NULL;
0866     outmw->tr_base = 0;
0867     outmw->size = 0;
0868     outmw->pidx = -1;
0869     outmw->dbgfs_file = NULL;
0870 }
0871 
0872 static ssize_t tool_peer_mw_trans_read(struct file *filep, char __user *ubuf,
0873                     size_t size, loff_t *offp)
0874 {
0875     struct tool_mw_wrap *outmw_wrap = filep->private_data;
0876     struct tool_mw *outmw = outmw_wrap->mw;
0877     resource_size_t map_size;
0878     phys_addr_t map_base;
0879     ssize_t off = 0;
0880     size_t buf_size;
0881     char *buf;
0882     int ret;
0883 
0884     ret = ntb_peer_mw_get_addr(outmw->tc->ntb, outmw->widx,
0885                   &map_base, &map_size);
0886     if (ret)
0887         return ret;
0888 
0889     buf_size = min_t(size_t, size, 512);
0890 
0891     buf = kmalloc(buf_size, GFP_KERNEL);
0892     if (!buf)
0893         return -ENOMEM;
0894 
0895     off += scnprintf(buf + off, buf_size - off,
0896              "Outbound MW:        \t%d\n", outmw->widx);
0897 
0898     if (outmw->io_base != NULL) {
0899         off += scnprintf(buf + off, buf_size - off,
0900             "Port attached       \t%d (%d)\n",
0901             ntb_peer_port_number(outmw->tc->ntb, outmw->pidx),
0902             outmw->pidx);
0903     } else {
0904         off += scnprintf(buf + off, buf_size - off,
0905                  "Port attached       \t-1 (-1)\n");
0906     }
0907 
0908     off += scnprintf(buf + off, buf_size - off,
0909              "Virtual address     \t0x%pK\n", outmw->io_base);
0910 
0911     off += scnprintf(buf + off, buf_size - off,
0912              "Phys Address        \t%pap\n", &map_base);
0913 
0914     off += scnprintf(buf + off, buf_size - off,
0915              "Mapping Size        \t%pap\n", &map_size);
0916 
0917     off += scnprintf(buf + off, buf_size - off,
0918              "Translation Address \t0x%016llx\n", outmw->tr_base);
0919 
0920     off += scnprintf(buf + off, buf_size - off,
0921              "Window Size         \t%pap\n", &outmw->size);
0922 
0923     ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
0924     kfree(buf);
0925 
0926     return ret;
0927 }
0928 
0929 static ssize_t tool_peer_mw_trans_write(struct file *filep,
0930                     const char __user *ubuf,
0931                     size_t size, loff_t *offp)
0932 {
0933     struct tool_mw_wrap *outmw_wrap = filep->private_data;
0934     struct tool_mw *outmw = outmw_wrap->mw;
0935     size_t buf_size, wsize;
0936     char buf[TOOL_BUF_LEN];
0937     int ret, n;
0938     u64 addr;
0939 
0940     buf_size = min(size, (sizeof(buf) - 1));
0941     if (copy_from_user(buf, ubuf, buf_size))
0942         return -EFAULT;
0943 
0944     buf[buf_size] = '\0';
0945 
0946     n = sscanf(buf, "%lli:%zi", &addr, &wsize);
0947     if (n != 2)
0948         return -EINVAL;
0949 
0950     tool_free_peer_mw(outmw->tc, outmw->widx);
0951     if (wsize) {
0952         ret = tool_setup_peer_mw(outmw->tc, outmw_wrap->pidx,
0953                      outmw->widx, addr, wsize);
0954         if (ret)
0955             return ret;
0956     }
0957 
0958     return size;
0959 }
0960 
0961 static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops,
0962               tool_peer_mw_trans_read,
0963               tool_peer_mw_trans_write);
0964 
0965 static int tool_init_mws(struct tool_ctx *tc)
0966 {
0967     int widx, pidx;
0968 
0969     /* Initialize outbound memory windows */
0970     tc->outmw_cnt = ntb_peer_mw_count(tc->ntb);
0971     tc->outmws = devm_kcalloc(&tc->ntb->dev, tc->outmw_cnt,
0972                   sizeof(*tc->outmws), GFP_KERNEL);
0973     if (tc->outmws == NULL)
0974         return -ENOMEM;
0975 
0976     for (widx = 0; widx < tc->outmw_cnt; widx++) {
0977         tc->outmws[widx].widx = widx;
0978         tc->outmws[widx].pidx = -1;
0979         tc->outmws[widx].tc = tc;
0980     }
0981 
0982     /* Initialize inbound memory windows and outbound MWs wrapper */
0983     for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
0984         tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->ntb, pidx);
0985         tc->peers[pidx].inmws =
0986             devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].inmw_cnt,
0987                     sizeof(*tc->peers[pidx].inmws), GFP_KERNEL);
0988         if (tc->peers[pidx].inmws == NULL)
0989             return -ENOMEM;
0990 
0991         for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) {
0992             tc->peers[pidx].inmws[widx].widx = widx;
0993             tc->peers[pidx].inmws[widx].pidx = pidx;
0994             tc->peers[pidx].inmws[widx].tc = tc;
0995         }
0996 
0997         tc->peers[pidx].outmw_cnt = ntb_peer_mw_count(tc->ntb);
0998         tc->peers[pidx].outmws =
0999             devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmw_cnt,
1000                    sizeof(*tc->peers[pidx].outmws), GFP_KERNEL);
1001 
1002         for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) {
1003             tc->peers[pidx].outmws[widx].pidx = pidx;
1004             tc->peers[pidx].outmws[widx].mw = &tc->outmws[widx];
1005         }
1006     }
1007 
1008     return 0;
1009 }
1010 
1011 static void tool_clear_mws(struct tool_ctx *tc)
1012 {
1013     int widx, pidx;
1014 
1015     /* Free outbound memory windows */
1016     for (widx = 0; widx < tc->outmw_cnt; widx++)
1017         tool_free_peer_mw(tc, widx);
1018 
1019     /* Free outbound memory windows */
1020     for (pidx = 0; pidx < tc->peer_cnt; pidx++)
1021         for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++)
1022             tool_free_mw(tc, pidx, widx);
1023 }
1024 
1025 /*==============================================================================
1026  *                       Doorbell read/write methods
1027  *==============================================================================
1028  */
1029 
1030 static ssize_t tool_db_read(struct file *filep, char __user *ubuf,
1031                 size_t size, loff_t *offp)
1032 {
1033     struct tool_ctx *tc = filep->private_data;
1034 
1035     return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read);
1036 }
1037 
1038 static ssize_t tool_db_write(struct file *filep, const char __user *ubuf,
1039                  size_t size, loff_t *offp)
1040 {
1041     struct tool_ctx *tc = filep->private_data;
1042 
1043     return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set,
1044                  tc->ntb->ops->db_clear);
1045 }
1046 
1047 static TOOL_FOPS_RDWR(tool_db_fops,
1048               tool_db_read,
1049               tool_db_write);
1050 
1051 static ssize_t tool_db_valid_mask_read(struct file *filep, char __user *ubuf,
1052                        size_t size, loff_t *offp)
1053 {
1054     struct tool_ctx *tc = filep->private_data;
1055 
1056     return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_valid_mask);
1057 }
1058 
1059 static TOOL_FOPS_RDWR(tool_db_valid_mask_fops,
1060               tool_db_valid_mask_read,
1061               NULL);
1062 
1063 static ssize_t tool_db_mask_read(struct file *filep, char __user *ubuf,
1064                  size_t size, loff_t *offp)
1065 {
1066     struct tool_ctx *tc = filep->private_data;
1067 
1068     return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read_mask);
1069 }
1070 
1071 static ssize_t tool_db_mask_write(struct file *filep, const char __user *ubuf,
1072                    size_t size, loff_t *offp)
1073 {
1074     struct tool_ctx *tc = filep->private_data;
1075 
1076     return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set_mask,
1077                  tc->ntb->ops->db_clear_mask);
1078 }
1079 
1080 static TOOL_FOPS_RDWR(tool_db_mask_fops,
1081               tool_db_mask_read,
1082               tool_db_mask_write);
1083 
1084 static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf,
1085                  size_t size, loff_t *offp)
1086 {
1087     struct tool_ctx *tc = filep->private_data;
1088 
1089     return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->peer_db_read);
1090 }
1091 
1092 static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf,
1093                   size_t size, loff_t *offp)
1094 {
1095     struct tool_ctx *tc = filep->private_data;
1096 
1097     return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->peer_db_set,
1098                  tc->ntb->ops->peer_db_clear);
1099 }
1100 
1101 static TOOL_FOPS_RDWR(tool_peer_db_fops,
1102               tool_peer_db_read,
1103               tool_peer_db_write);
1104 
1105 static ssize_t tool_peer_db_mask_read(struct file *filep, char __user *ubuf,
1106                    size_t size, loff_t *offp)
1107 {
1108     struct tool_ctx *tc = filep->private_data;
1109 
1110     return tool_fn_read(tc, ubuf, size, offp,
1111                 tc->ntb->ops->peer_db_read_mask);
1112 }
1113 
1114 static ssize_t tool_peer_db_mask_write(struct file *filep,
1115                        const char __user *ubuf,
1116                        size_t size, loff_t *offp)
1117 {
1118     struct tool_ctx *tc = filep->private_data;
1119 
1120     return tool_fn_write(tc, ubuf, size, offp,
1121                  tc->ntb->ops->peer_db_set_mask,
1122                  tc->ntb->ops->peer_db_clear_mask);
1123 }
1124 
1125 static TOOL_FOPS_RDWR(tool_peer_db_mask_fops,
1126               tool_peer_db_mask_read,
1127               tool_peer_db_mask_write);
1128 
1129 static ssize_t tool_db_event_write(struct file *filep,
1130                    const char __user *ubuf,
1131                    size_t size, loff_t *offp)
1132 {
1133     struct tool_ctx *tc = filep->private_data;
1134     u64 val;
1135     int ret;
1136 
1137     ret = kstrtou64_from_user(ubuf, size, 0, &val);
1138     if (ret)
1139         return ret;
1140 
1141     if (wait_event_interruptible(tc->db_wq, ntb_db_read(tc->ntb) == val))
1142         return -ERESTART;
1143 
1144     return size;
1145 }
1146 
1147 static TOOL_FOPS_RDWR(tool_db_event_fops,
1148               NULL,
1149               tool_db_event_write);
1150 
1151 /*==============================================================================
1152  *                       Scratchpads read/write methods
1153  *==============================================================================
1154  */
1155 
1156 static ssize_t tool_spad_read(struct file *filep, char __user *ubuf,
1157                   size_t size, loff_t *offp)
1158 {
1159     struct tool_spad *spad = filep->private_data;
1160     char buf[TOOL_BUF_LEN];
1161     ssize_t pos;
1162 
1163     if (!spad->tc->ntb->ops->spad_read)
1164         return -EINVAL;
1165 
1166     pos = scnprintf(buf, sizeof(buf), "%#x\n",
1167         ntb_spad_read(spad->tc->ntb, spad->sidx));
1168 
1169     return simple_read_from_buffer(ubuf, size, offp, buf, pos);
1170 }
1171 
1172 static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
1173                    size_t size, loff_t *offp)
1174 {
1175     struct tool_spad *spad = filep->private_data;
1176     u32 val;
1177     int ret;
1178 
1179     if (!spad->tc->ntb->ops->spad_write) {
1180         dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n");
1181         return -EINVAL;
1182     }
1183 
1184     ret = kstrtou32_from_user(ubuf, size, 0, &val);
1185     if (ret)
1186         return ret;
1187 
1188     ret = ntb_spad_write(spad->tc->ntb, spad->sidx, val);
1189 
1190     return ret ?: size;
1191 }
1192 
1193 static TOOL_FOPS_RDWR(tool_spad_fops,
1194               tool_spad_read,
1195               tool_spad_write);
1196 
1197 static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
1198                    size_t size, loff_t *offp)
1199 {
1200     struct tool_spad *spad = filep->private_data;
1201     char buf[TOOL_BUF_LEN];
1202     ssize_t pos;
1203 
1204     if (!spad->tc->ntb->ops->peer_spad_read)
1205         return -EINVAL;
1206 
1207     pos = scnprintf(buf, sizeof(buf), "%#x\n",
1208         ntb_peer_spad_read(spad->tc->ntb, spad->pidx, spad->sidx));
1209 
1210     return simple_read_from_buffer(ubuf, size, offp, buf, pos);
1211 }
1212 
1213 static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
1214                     size_t size, loff_t *offp)
1215 {
1216     struct tool_spad *spad = filep->private_data;
1217     u32 val;
1218     int ret;
1219 
1220     if (!spad->tc->ntb->ops->peer_spad_write) {
1221         dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n");
1222         return -EINVAL;
1223     }
1224 
1225     ret = kstrtou32_from_user(ubuf, size, 0, &val);
1226     if (ret)
1227         return ret;
1228 
1229     ret = ntb_peer_spad_write(spad->tc->ntb, spad->pidx, spad->sidx, val);
1230 
1231     return ret ?: size;
1232 }
1233 
1234 static TOOL_FOPS_RDWR(tool_peer_spad_fops,
1235               tool_peer_spad_read,
1236               tool_peer_spad_write);
1237 
1238 static int tool_init_spads(struct tool_ctx *tc)
1239 {
1240     int sidx, pidx;
1241 
1242     /* Initialize inbound scratchpad structures */
1243     tc->inspad_cnt = ntb_spad_count(tc->ntb);
1244     tc->inspads = devm_kcalloc(&tc->ntb->dev, tc->inspad_cnt,
1245                    sizeof(*tc->inspads), GFP_KERNEL);
1246     if (tc->inspads == NULL)
1247         return -ENOMEM;
1248 
1249     for (sidx = 0; sidx < tc->inspad_cnt; sidx++) {
1250         tc->inspads[sidx].sidx = sidx;
1251         tc->inspads[sidx].pidx = -1;
1252         tc->inspads[sidx].tc = tc;
1253     }
1254 
1255     /* Initialize outbound scratchpad structures */
1256     for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
1257         tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->ntb);
1258         tc->peers[pidx].outspads =
1259             devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outspad_cnt,
1260                 sizeof(*tc->peers[pidx].outspads), GFP_KERNEL);
1261         if (tc->peers[pidx].outspads == NULL)
1262             return -ENOMEM;
1263 
1264         for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) {
1265             tc->peers[pidx].outspads[sidx].sidx = sidx;
1266             tc->peers[pidx].outspads[sidx].pidx = pidx;
1267             tc->peers[pidx].outspads[sidx].tc = tc;
1268         }
1269     }
1270 
1271     return 0;
1272 }
1273 
1274 /*==============================================================================
1275  *                       Messages read/write methods
1276  *==============================================================================
1277  */
1278 
1279 static ssize_t tool_inmsg_read(struct file *filep, char __user *ubuf,
1280                    size_t size, loff_t *offp)
1281 {
1282     struct tool_msg *msg = filep->private_data;
1283     char buf[TOOL_BUF_LEN];
1284     ssize_t pos;
1285     u32 data;
1286     int pidx;
1287 
1288     data = ntb_msg_read(msg->tc->ntb, &pidx, msg->midx);
1289 
1290     pos = scnprintf(buf, sizeof(buf), "0x%08x<-%d\n", data, pidx);
1291 
1292     return simple_read_from_buffer(ubuf, size, offp, buf, pos);
1293 }
1294 
1295 static TOOL_FOPS_RDWR(tool_inmsg_fops,
1296               tool_inmsg_read,
1297               NULL);
1298 
1299 static ssize_t tool_outmsg_write(struct file *filep,
1300                  const char __user *ubuf,
1301                  size_t size, loff_t *offp)
1302 {
1303     struct tool_msg *msg = filep->private_data;
1304     u32 val;
1305     int ret;
1306 
1307     ret = kstrtou32_from_user(ubuf, size, 0, &val);
1308     if (ret)
1309         return ret;
1310 
1311     ret = ntb_peer_msg_write(msg->tc->ntb, msg->pidx, msg->midx, val);
1312 
1313     return ret ? : size;
1314 }
1315 
1316 static TOOL_FOPS_RDWR(tool_outmsg_fops,
1317               NULL,
1318               tool_outmsg_write);
1319 
1320 static ssize_t tool_msg_sts_read(struct file *filep, char __user *ubuf,
1321                  size_t size, loff_t *offp)
1322 {
1323     struct tool_ctx *tc = filep->private_data;
1324 
1325     return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_read_sts);
1326 }
1327 
1328 static ssize_t tool_msg_sts_write(struct file *filep, const char __user *ubuf,
1329                   size_t size, loff_t *offp)
1330 {
1331     struct tool_ctx *tc = filep->private_data;
1332 
1333     return tool_fn_write(tc, ubuf, size, offp, NULL,
1334                  tc->ntb->ops->msg_clear_sts);
1335 }
1336 
1337 static TOOL_FOPS_RDWR(tool_msg_sts_fops,
1338               tool_msg_sts_read,
1339               tool_msg_sts_write);
1340 
1341 static ssize_t tool_msg_inbits_read(struct file *filep, char __user *ubuf,
1342                     size_t size, loff_t *offp)
1343 {
1344     struct tool_ctx *tc = filep->private_data;
1345 
1346     return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_inbits);
1347 }
1348 
1349 static TOOL_FOPS_RDWR(tool_msg_inbits_fops,
1350               tool_msg_inbits_read,
1351               NULL);
1352 
1353 static ssize_t tool_msg_outbits_read(struct file *filep, char __user *ubuf,
1354                      size_t size, loff_t *offp)
1355 {
1356     struct tool_ctx *tc = filep->private_data;
1357 
1358     return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_outbits);
1359 }
1360 
1361 static TOOL_FOPS_RDWR(tool_msg_outbits_fops,
1362               tool_msg_outbits_read,
1363               NULL);
1364 
1365 static ssize_t tool_msg_mask_write(struct file *filep, const char __user *ubuf,
1366                    size_t size, loff_t *offp)
1367 {
1368     struct tool_ctx *tc = filep->private_data;
1369 
1370     return tool_fn_write(tc, ubuf, size, offp,
1371                  tc->ntb->ops->msg_set_mask,
1372                  tc->ntb->ops->msg_clear_mask);
1373 }
1374 
1375 static TOOL_FOPS_RDWR(tool_msg_mask_fops,
1376               NULL,
1377               tool_msg_mask_write);
1378 
1379 static ssize_t tool_msg_event_write(struct file *filep,
1380                     const char __user *ubuf,
1381                     size_t size, loff_t *offp)
1382 {
1383     struct tool_ctx *tc = filep->private_data;
1384     u64 val;
1385     int ret;
1386 
1387     ret = kstrtou64_from_user(ubuf, size, 0, &val);
1388     if (ret)
1389         return ret;
1390 
1391     if (wait_event_interruptible(tc->msg_wq,
1392         ntb_msg_read_sts(tc->ntb) == val))
1393         return -ERESTART;
1394 
1395     return size;
1396 }
1397 
1398 static TOOL_FOPS_RDWR(tool_msg_event_fops,
1399               NULL,
1400               tool_msg_event_write);
1401 
1402 static int tool_init_msgs(struct tool_ctx *tc)
1403 {
1404     int midx, pidx;
1405 
1406     /* Initialize inbound message structures */
1407     tc->inmsg_cnt = ntb_msg_count(tc->ntb);
1408     tc->inmsgs = devm_kcalloc(&tc->ntb->dev, tc->inmsg_cnt,
1409                    sizeof(*tc->inmsgs), GFP_KERNEL);
1410     if (tc->inmsgs == NULL)
1411         return -ENOMEM;
1412 
1413     for (midx = 0; midx < tc->inmsg_cnt; midx++) {
1414         tc->inmsgs[midx].midx = midx;
1415         tc->inmsgs[midx].pidx = -1;
1416         tc->inmsgs[midx].tc = tc;
1417     }
1418 
1419     /* Initialize outbound message structures */
1420     for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
1421         tc->peers[pidx].outmsg_cnt = ntb_msg_count(tc->ntb);
1422         tc->peers[pidx].outmsgs =
1423             devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmsg_cnt,
1424                 sizeof(*tc->peers[pidx].outmsgs), GFP_KERNEL);
1425         if (tc->peers[pidx].outmsgs == NULL)
1426             return -ENOMEM;
1427 
1428         for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) {
1429             tc->peers[pidx].outmsgs[midx].midx = midx;
1430             tc->peers[pidx].outmsgs[midx].pidx = pidx;
1431             tc->peers[pidx].outmsgs[midx].tc = tc;
1432         }
1433     }
1434 
1435     return 0;
1436 }
1437 
1438 /*==============================================================================
1439  *                          Initialization methods
1440  *==============================================================================
1441  */
1442 
1443 static struct tool_ctx *tool_create_data(struct ntb_dev *ntb)
1444 {
1445     struct tool_ctx *tc;
1446 
1447     tc = devm_kzalloc(&ntb->dev, sizeof(*tc), GFP_KERNEL);
1448     if (tc == NULL)
1449         return ERR_PTR(-ENOMEM);
1450 
1451     tc->ntb = ntb;
1452     init_waitqueue_head(&tc->link_wq);
1453     init_waitqueue_head(&tc->db_wq);
1454     init_waitqueue_head(&tc->msg_wq);
1455 
1456     if (ntb_db_is_unsafe(ntb))
1457         dev_dbg(&ntb->dev, "doorbell is unsafe\n");
1458 
1459     if (ntb_spad_is_unsafe(ntb))
1460         dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
1461 
1462     return tc;
1463 }
1464 
1465 static void tool_clear_data(struct tool_ctx *tc)
1466 {
1467     wake_up(&tc->link_wq);
1468     wake_up(&tc->db_wq);
1469     wake_up(&tc->msg_wq);
1470 }
1471 
1472 static int tool_init_ntb(struct tool_ctx *tc)
1473 {
1474     return ntb_set_ctx(tc->ntb, tc, &tool_ops);
1475 }
1476 
1477 static void tool_clear_ntb(struct tool_ctx *tc)
1478 {
1479     ntb_clear_ctx(tc->ntb);
1480     ntb_link_disable(tc->ntb);
1481 }
1482 
1483 static void tool_setup_dbgfs(struct tool_ctx *tc)
1484 {
1485     int pidx, widx, sidx, midx;
1486     char buf[TOOL_BUF_LEN];
1487 
1488     /* This modules is useless without dbgfs... */
1489     if (!tool_dbgfs_topdir) {
1490         tc->dbgfs_dir = NULL;
1491         return;
1492     }
1493 
1494     tc->dbgfs_dir = debugfs_create_dir(dev_name(&tc->ntb->dev),
1495                        tool_dbgfs_topdir);
1496     if (!tc->dbgfs_dir)
1497         return;
1498 
1499     debugfs_create_file("port", 0600, tc->dbgfs_dir,
1500                 tc, &tool_port_fops);
1501 
1502     debugfs_create_file("link", 0600, tc->dbgfs_dir,
1503                 tc, &tool_link_fops);
1504 
1505     debugfs_create_file("db", 0600, tc->dbgfs_dir,
1506                 tc, &tool_db_fops);
1507 
1508     debugfs_create_file("db_valid_mask", 0600, tc->dbgfs_dir,
1509                 tc, &tool_db_valid_mask_fops);
1510 
1511     debugfs_create_file("db_mask", 0600, tc->dbgfs_dir,
1512                 tc, &tool_db_mask_fops);
1513 
1514     debugfs_create_file("db_event", 0600, tc->dbgfs_dir,
1515                 tc, &tool_db_event_fops);
1516 
1517     debugfs_create_file("peer_db", 0600, tc->dbgfs_dir,
1518                 tc, &tool_peer_db_fops);
1519 
1520     debugfs_create_file("peer_db_mask", 0600, tc->dbgfs_dir,
1521                 tc, &tool_peer_db_mask_fops);
1522 
1523     if (tc->inspad_cnt != 0) {
1524         for (sidx = 0; sidx < tc->inspad_cnt; sidx++) {
1525             snprintf(buf, sizeof(buf), "spad%d", sidx);
1526 
1527             debugfs_create_file(buf, 0600, tc->dbgfs_dir,
1528                        &tc->inspads[sidx], &tool_spad_fops);
1529         }
1530     }
1531 
1532     if (tc->inmsg_cnt != 0) {
1533         for (midx = 0; midx < tc->inmsg_cnt; midx++) {
1534             snprintf(buf, sizeof(buf), "msg%d", midx);
1535             debugfs_create_file(buf, 0600, tc->dbgfs_dir,
1536                        &tc->inmsgs[midx], &tool_inmsg_fops);
1537         }
1538 
1539         debugfs_create_file("msg_sts", 0600, tc->dbgfs_dir,
1540                     tc, &tool_msg_sts_fops);
1541 
1542         debugfs_create_file("msg_inbits", 0600, tc->dbgfs_dir,
1543                     tc, &tool_msg_inbits_fops);
1544 
1545         debugfs_create_file("msg_outbits", 0600, tc->dbgfs_dir,
1546                     tc, &tool_msg_outbits_fops);
1547 
1548         debugfs_create_file("msg_mask", 0600, tc->dbgfs_dir,
1549                     tc, &tool_msg_mask_fops);
1550 
1551         debugfs_create_file("msg_event", 0600, tc->dbgfs_dir,
1552                     tc, &tool_msg_event_fops);
1553     }
1554 
1555     for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
1556         snprintf(buf, sizeof(buf), "peer%d", pidx);
1557         tc->peers[pidx].dbgfs_dir =
1558             debugfs_create_dir(buf, tc->dbgfs_dir);
1559 
1560         debugfs_create_file("port", 0600,
1561                     tc->peers[pidx].dbgfs_dir,
1562                     &tc->peers[pidx], &tool_peer_port_fops);
1563 
1564         debugfs_create_file("link", 0200,
1565                     tc->peers[pidx].dbgfs_dir,
1566                     &tc->peers[pidx], &tool_peer_link_fops);
1567 
1568         debugfs_create_file("link_event", 0200,
1569                   tc->peers[pidx].dbgfs_dir,
1570                   &tc->peers[pidx], &tool_peer_link_event_fops);
1571 
1572         for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) {
1573             snprintf(buf, sizeof(buf), "mw_trans%d", widx);
1574             debugfs_create_file(buf, 0600,
1575                         tc->peers[pidx].dbgfs_dir,
1576                         &tc->peers[pidx].inmws[widx],
1577                         &tool_mw_trans_fops);
1578         }
1579 
1580         for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) {
1581             snprintf(buf, sizeof(buf), "peer_mw_trans%d", widx);
1582             debugfs_create_file(buf, 0600,
1583                         tc->peers[pidx].dbgfs_dir,
1584                         &tc->peers[pidx].outmws[widx],
1585                         &tool_peer_mw_trans_fops);
1586         }
1587 
1588         for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) {
1589             snprintf(buf, sizeof(buf), "spad%d", sidx);
1590 
1591             debugfs_create_file(buf, 0600,
1592                         tc->peers[pidx].dbgfs_dir,
1593                         &tc->peers[pidx].outspads[sidx],
1594                         &tool_peer_spad_fops);
1595         }
1596 
1597         for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) {
1598             snprintf(buf, sizeof(buf), "msg%d", midx);
1599             debugfs_create_file(buf, 0600,
1600                         tc->peers[pidx].dbgfs_dir,
1601                         &tc->peers[pidx].outmsgs[midx],
1602                         &tool_outmsg_fops);
1603         }
1604     }
1605 }
1606 
1607 static void tool_clear_dbgfs(struct tool_ctx *tc)
1608 {
1609     debugfs_remove_recursive(tc->dbgfs_dir);
1610 }
1611 
1612 static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
1613 {
1614     struct tool_ctx *tc;
1615     int ret;
1616 
1617     tc = tool_create_data(ntb);
1618     if (IS_ERR(tc))
1619         return PTR_ERR(tc);
1620 
1621     ret = tool_init_peers(tc);
1622     if (ret != 0)
1623         goto err_clear_data;
1624 
1625     ret = tool_init_mws(tc);
1626     if (ret != 0)
1627         goto err_clear_data;
1628 
1629     ret = tool_init_spads(tc);
1630     if (ret != 0)
1631         goto err_clear_mws;
1632 
1633     ret = tool_init_msgs(tc);
1634     if (ret != 0)
1635         goto err_clear_mws;
1636 
1637     ret = tool_init_ntb(tc);
1638     if (ret != 0)
1639         goto err_clear_mws;
1640 
1641     tool_setup_dbgfs(tc);
1642 
1643     return 0;
1644 
1645 err_clear_mws:
1646     tool_clear_mws(tc);
1647 
1648 err_clear_data:
1649     tool_clear_data(tc);
1650 
1651     return ret;
1652 }
1653 
1654 static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb)
1655 {
1656     struct tool_ctx *tc = ntb->ctx;
1657 
1658     tool_clear_dbgfs(tc);
1659 
1660     tool_clear_ntb(tc);
1661 
1662     tool_clear_mws(tc);
1663 
1664     tool_clear_data(tc);
1665 }
1666 
1667 static struct ntb_client tool_client = {
1668     .ops = {
1669         .probe = tool_probe,
1670         .remove = tool_remove,
1671     }
1672 };
1673 
1674 static int __init tool_init(void)
1675 {
1676     int ret;
1677 
1678     if (debugfs_initialized())
1679         tool_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
1680 
1681     ret = ntb_register_client(&tool_client);
1682     if (ret)
1683         debugfs_remove_recursive(tool_dbgfs_topdir);
1684 
1685     return ret;
1686 }
1687 module_init(tool_init);
1688 
1689 static void __exit tool_exit(void)
1690 {
1691     ntb_unregister_client(&tool_client);
1692     debugfs_remove_recursive(tool_dbgfs_topdir);
1693 }
1694 module_exit(tool_exit);