18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 38c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 88c2ecf20Sopenharmony_ci * Copyright (C) 2017 T-Platforms All Rights Reserved. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 118c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 128c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 158c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 168c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 178c2ecf20Sopenharmony_ci * General Public License for more details. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * BSD LICENSE 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 228c2ecf20Sopenharmony_ci * Copyright (C) 2017 T-Platforms All Rights Reserved. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 258c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 268c2ecf20Sopenharmony_ci * are met: 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 298c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 308c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copy 318c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 328c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 338c2ecf20Sopenharmony_ci * distribution. 348c2ecf20Sopenharmony_ci * * Neither the name of Intel Corporation nor the names of its 358c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 368c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 398c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 408c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 418c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 428c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 438c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 448c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 458c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 468c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 478c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 488c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * PCIe NTB Debugging Tool Linux driver 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * How to use this tool, by example. 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * Assuming $DBG_DIR is something like: 578c2ecf20Sopenharmony_ci * '/sys/kernel/debug/ntb_tool/0000:00:03.0' 588c2ecf20Sopenharmony_ci * Suppose aside from local device there is at least one remote device 598c2ecf20Sopenharmony_ci * connected to NTB with index 0. 608c2ecf20Sopenharmony_ci *----------------------------------------------------------------------------- 618c2ecf20Sopenharmony_ci * Eg: check local/peer device information. 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * # Get local device port number 648c2ecf20Sopenharmony_ci * root@self# cat $DBG_DIR/port 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * # Check local device functionality 678c2ecf20Sopenharmony_ci * root@self# ls $DBG_DIR 688c2ecf20Sopenharmony_ci * db msg1 msg_sts peer4/ port 698c2ecf20Sopenharmony_ci * db_event msg2 peer0/ peer5/ spad0 708c2ecf20Sopenharmony_ci * db_mask msg3 peer1/ peer_db spad1 718c2ecf20Sopenharmony_ci * link msg_event peer2/ peer_db_mask spad2 728c2ecf20Sopenharmony_ci * msg0 msg_mask peer3/ peer_spad spad3 738c2ecf20Sopenharmony_ci * # As one can see it supports: 748c2ecf20Sopenharmony_ci * # 1) four inbound message registers 758c2ecf20Sopenharmony_ci * # 2) four inbound scratchpads 768c2ecf20Sopenharmony_ci * # 3) up to six peer devices 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * # Check peer device port number 798c2ecf20Sopenharmony_ci * root@self# cat $DBG_DIR/peer0/port 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * # Check peer device(s) functionality to be used 828c2ecf20Sopenharmony_ci * root@self# ls $DBG_DIR/peer0 838c2ecf20Sopenharmony_ci * link mw_trans0 mw_trans6 port 848c2ecf20Sopenharmony_ci * link_event mw_trans1 mw_trans7 spad0 858c2ecf20Sopenharmony_ci * msg0 mw_trans2 peer_mw_trans0 spad1 868c2ecf20Sopenharmony_ci * msg1 mw_trans3 peer_mw_trans1 spad2 878c2ecf20Sopenharmony_ci * msg2 mw_trans4 peer_mw_trans2 spad3 888c2ecf20Sopenharmony_ci * msg3 mw_trans5 peer_mw_trans3 898c2ecf20Sopenharmony_ci * # As one can see we got: 908c2ecf20Sopenharmony_ci * # 1) four outbound message registers 918c2ecf20Sopenharmony_ci * # 2) four outbound scratchpads 928c2ecf20Sopenharmony_ci * # 3) eight inbound memory windows 938c2ecf20Sopenharmony_ci * # 4) four outbound memory windows 948c2ecf20Sopenharmony_ci *----------------------------------------------------------------------------- 958c2ecf20Sopenharmony_ci * Eg: NTB link tests 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci * # Set local link up/down 988c2ecf20Sopenharmony_ci * root@self# echo Y > $DBG_DIR/link 998c2ecf20Sopenharmony_ci * root@self# echo N > $DBG_DIR/link 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * # Check if link with peer device is up/down: 1028c2ecf20Sopenharmony_ci * root@self# cat $DBG_DIR/peer0/link 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * # Block until the link is up/down 1058c2ecf20Sopenharmony_ci * root@self# echo Y > $DBG_DIR/peer0/link_event 1068c2ecf20Sopenharmony_ci * root@self# echo N > $DBG_DIR/peer0/link_event 1078c2ecf20Sopenharmony_ci *----------------------------------------------------------------------------- 1088c2ecf20Sopenharmony_ci * Eg: Doorbell registers tests (some functionality might be absent) 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * # Set/clear/get local doorbell 1118c2ecf20Sopenharmony_ci * root@self# echo 's 1' > $DBG_DIR/db 1128c2ecf20Sopenharmony_ci * root@self# echo 'c 1' > $DBG_DIR/db 1138c2ecf20Sopenharmony_ci * root@self# cat $DBG_DIR/db 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * # Set/clear/get local doorbell mask 1168c2ecf20Sopenharmony_ci * root@self# echo 's 1' > $DBG_DIR/db_mask 1178c2ecf20Sopenharmony_ci * root@self# echo 'c 1' > $DBG_DIR/db_mask 1188c2ecf20Sopenharmony_ci * root@self# cat $DBG_DIR/db_mask 1198c2ecf20Sopenharmony_ci * 1208c2ecf20Sopenharmony_ci * # Ring/clear/get peer doorbell 1218c2ecf20Sopenharmony_ci * root@peer# echo 's 1' > $DBG_DIR/peer_db 1228c2ecf20Sopenharmony_ci * root@peer# echo 'c 1' > $DBG_DIR/peer_db 1238c2ecf20Sopenharmony_ci * root@peer# cat $DBG_DIR/peer_db 1248c2ecf20Sopenharmony_ci * 1258c2ecf20Sopenharmony_ci * # Set/clear/get peer doorbell mask 1268c2ecf20Sopenharmony_ci * root@self# echo 's 1' > $DBG_DIR/peer_db_mask 1278c2ecf20Sopenharmony_ci * root@self# echo 'c 1' > $DBG_DIR/peer_db_mask 1288c2ecf20Sopenharmony_ci * root@self# cat $DBG_DIR/peer_db_mask 1298c2ecf20Sopenharmony_ci * 1308c2ecf20Sopenharmony_ci * # Block until local doorbell is set with specified value 1318c2ecf20Sopenharmony_ci * root@self# echo 1 > $DBG_DIR/db_event 1328c2ecf20Sopenharmony_ci *----------------------------------------------------------------------------- 1338c2ecf20Sopenharmony_ci * Eg: Message registers tests (functionality might be absent) 1348c2ecf20Sopenharmony_ci * 1358c2ecf20Sopenharmony_ci * # Set/clear/get in/out message registers status 1368c2ecf20Sopenharmony_ci * root@self# echo 's 1' > $DBG_DIR/msg_sts 1378c2ecf20Sopenharmony_ci * root@self# echo 'c 1' > $DBG_DIR/msg_sts 1388c2ecf20Sopenharmony_ci * root@self# cat $DBG_DIR/msg_sts 1398c2ecf20Sopenharmony_ci * 1408c2ecf20Sopenharmony_ci * # Set/clear in/out message registers mask 1418c2ecf20Sopenharmony_ci * root@self# echo 's 1' > $DBG_DIR/msg_mask 1428c2ecf20Sopenharmony_ci * root@self# echo 'c 1' > $DBG_DIR/msg_mask 1438c2ecf20Sopenharmony_ci * 1448c2ecf20Sopenharmony_ci * # Get inbound message register #0 value and source of port index 1458c2ecf20Sopenharmony_ci * root@self# cat $DBG_DIR/msg0 1468c2ecf20Sopenharmony_ci * 1478c2ecf20Sopenharmony_ci * # Send some data to peer over outbound message register #0 1488c2ecf20Sopenharmony_ci * root@self# echo 0x01020304 > $DBG_DIR/peer0/msg0 1498c2ecf20Sopenharmony_ci *----------------------------------------------------------------------------- 1508c2ecf20Sopenharmony_ci * Eg: Scratchpad registers tests (functionality might be absent) 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * # Write/read to/from local scratchpad register #0 1538c2ecf20Sopenharmony_ci * root@peer# echo 0x01020304 > $DBG_DIR/spad0 1548c2ecf20Sopenharmony_ci * root@peer# cat $DBG_DIR/spad0 1558c2ecf20Sopenharmony_ci * 1568c2ecf20Sopenharmony_ci * # Write/read to/from peer scratchpad register #0 1578c2ecf20Sopenharmony_ci * root@peer# echo 0x01020304 > $DBG_DIR/peer0/spad0 1588c2ecf20Sopenharmony_ci * root@peer# cat $DBG_DIR/peer0/spad0 1598c2ecf20Sopenharmony_ci *----------------------------------------------------------------------------- 1608c2ecf20Sopenharmony_ci * Eg: Memory windows tests 1618c2ecf20Sopenharmony_ci * 1628c2ecf20Sopenharmony_ci * # Create inbound memory window buffer of specified size/get its base address 1638c2ecf20Sopenharmony_ci * root@peer# echo 16384 > $DBG_DIR/peer0/mw_trans0 1648c2ecf20Sopenharmony_ci * root@peer# cat $DBG_DIR/peer0/mw_trans0 1658c2ecf20Sopenharmony_ci * 1668c2ecf20Sopenharmony_ci * # Write/read data to/from inbound memory window 1678c2ecf20Sopenharmony_ci * root@peer# echo Hello > $DBG_DIR/peer0/mw0 1688c2ecf20Sopenharmony_ci * root@peer# head -c 7 $DBG_DIR/peer0/mw0 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * # Map outbound memory window/check it settings (on peer device) 1718c2ecf20Sopenharmony_ci * root@peer# echo 0xADD0BA5E:16384 > $DBG_DIR/peer0/peer_mw_trans0 1728c2ecf20Sopenharmony_ci * root@peer# cat $DBG_DIR/peer0/peer_mw_trans0 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * # Write/read data to/from outbound memory window (on peer device) 1758c2ecf20Sopenharmony_ci * root@peer# echo olleH > $DBG_DIR/peer0/peer_mw0 1768c2ecf20Sopenharmony_ci * root@peer# head -c 7 $DBG_DIR/peer0/peer_mw0 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci#include <linux/init.h> 1808c2ecf20Sopenharmony_ci#include <linux/kernel.h> 1818c2ecf20Sopenharmony_ci#include <linux/module.h> 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 1848c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 1858c2ecf20Sopenharmony_ci#include <linux/pci.h> 1868c2ecf20Sopenharmony_ci#include <linux/slab.h> 1878c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci#include <linux/ntb.h> 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci#define DRIVER_NAME "ntb_tool" 1928c2ecf20Sopenharmony_ci#define DRIVER_VERSION "2.0" 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 1958c2ecf20Sopenharmony_ciMODULE_VERSION(DRIVER_VERSION); 1968c2ecf20Sopenharmony_ciMODULE_AUTHOR("Allen Hubbe <Allen.Hubbe@emc.com>"); 1978c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCIe NTB Debugging Tool"); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* 2008c2ecf20Sopenharmony_ci * Inbound and outbound memory windows descriptor. Union members selection 2018c2ecf20Sopenharmony_ci * depends on the MW type the structure describes. mm_base/dma_base are the 2028c2ecf20Sopenharmony_ci * virtual and DMA address of an inbound MW. io_base/tr_base are the MMIO 2038c2ecf20Sopenharmony_ci * mapped virtual and xlat addresses of an outbound MW respectively. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_cistruct tool_mw { 2068c2ecf20Sopenharmony_ci int widx; 2078c2ecf20Sopenharmony_ci int pidx; 2088c2ecf20Sopenharmony_ci struct tool_ctx *tc; 2098c2ecf20Sopenharmony_ci union { 2108c2ecf20Sopenharmony_ci u8 *mm_base; 2118c2ecf20Sopenharmony_ci u8 __iomem *io_base; 2128c2ecf20Sopenharmony_ci }; 2138c2ecf20Sopenharmony_ci union { 2148c2ecf20Sopenharmony_ci dma_addr_t dma_base; 2158c2ecf20Sopenharmony_ci u64 tr_base; 2168c2ecf20Sopenharmony_ci }; 2178c2ecf20Sopenharmony_ci resource_size_t size; 2188c2ecf20Sopenharmony_ci struct dentry *dbgfs_file; 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/* 2228c2ecf20Sopenharmony_ci * Wrapper structure is used to distinguish the outbound MW peers reference 2238c2ecf20Sopenharmony_ci * within the corresponding DebugFS directory IO operation. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_cistruct tool_mw_wrap { 2268c2ecf20Sopenharmony_ci int pidx; 2278c2ecf20Sopenharmony_ci struct tool_mw *mw; 2288c2ecf20Sopenharmony_ci}; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistruct tool_msg { 2318c2ecf20Sopenharmony_ci int midx; 2328c2ecf20Sopenharmony_ci int pidx; 2338c2ecf20Sopenharmony_ci struct tool_ctx *tc; 2348c2ecf20Sopenharmony_ci}; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistruct tool_spad { 2378c2ecf20Sopenharmony_ci int sidx; 2388c2ecf20Sopenharmony_ci int pidx; 2398c2ecf20Sopenharmony_ci struct tool_ctx *tc; 2408c2ecf20Sopenharmony_ci}; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistruct tool_peer { 2438c2ecf20Sopenharmony_ci int pidx; 2448c2ecf20Sopenharmony_ci struct tool_ctx *tc; 2458c2ecf20Sopenharmony_ci int inmw_cnt; 2468c2ecf20Sopenharmony_ci struct tool_mw *inmws; 2478c2ecf20Sopenharmony_ci int outmw_cnt; 2488c2ecf20Sopenharmony_ci struct tool_mw_wrap *outmws; 2498c2ecf20Sopenharmony_ci int outmsg_cnt; 2508c2ecf20Sopenharmony_ci struct tool_msg *outmsgs; 2518c2ecf20Sopenharmony_ci int outspad_cnt; 2528c2ecf20Sopenharmony_ci struct tool_spad *outspads; 2538c2ecf20Sopenharmony_ci struct dentry *dbgfs_dir; 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistruct tool_ctx { 2578c2ecf20Sopenharmony_ci struct ntb_dev *ntb; 2588c2ecf20Sopenharmony_ci wait_queue_head_t link_wq; 2598c2ecf20Sopenharmony_ci wait_queue_head_t db_wq; 2608c2ecf20Sopenharmony_ci wait_queue_head_t msg_wq; 2618c2ecf20Sopenharmony_ci int outmw_cnt; 2628c2ecf20Sopenharmony_ci struct tool_mw *outmws; 2638c2ecf20Sopenharmony_ci int peer_cnt; 2648c2ecf20Sopenharmony_ci struct tool_peer *peers; 2658c2ecf20Sopenharmony_ci int inmsg_cnt; 2668c2ecf20Sopenharmony_ci struct tool_msg *inmsgs; 2678c2ecf20Sopenharmony_ci int inspad_cnt; 2688c2ecf20Sopenharmony_ci struct tool_spad *inspads; 2698c2ecf20Sopenharmony_ci struct dentry *dbgfs_dir; 2708c2ecf20Sopenharmony_ci}; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci#define TOOL_FOPS_RDWR(__name, __read, __write) \ 2738c2ecf20Sopenharmony_ci const struct file_operations __name = { \ 2748c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 2758c2ecf20Sopenharmony_ci .open = simple_open, \ 2768c2ecf20Sopenharmony_ci .read = __read, \ 2778c2ecf20Sopenharmony_ci .write = __write, \ 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci#define TOOL_BUF_LEN 32 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic struct dentry *tool_dbgfs_topdir; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/*============================================================================== 2858c2ecf20Sopenharmony_ci * NTB events handlers 2868c2ecf20Sopenharmony_ci *============================================================================== 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void tool_link_event(void *ctx) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct tool_ctx *tc = ctx; 2928c2ecf20Sopenharmony_ci enum ntb_speed speed; 2938c2ecf20Sopenharmony_ci enum ntb_width width; 2948c2ecf20Sopenharmony_ci int up; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci up = ntb_link_is_up(tc->ntb, &speed, &width); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n", 2998c2ecf20Sopenharmony_ci up ? "up" : "down", speed, width); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci wake_up(&tc->link_wq); 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic void tool_db_event(void *ctx, int vec) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct tool_ctx *tc = ctx; 3078c2ecf20Sopenharmony_ci u64 db_bits, db_mask; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci db_mask = ntb_db_vector_mask(tc->ntb, vec); 3108c2ecf20Sopenharmony_ci db_bits = ntb_db_read(tc->ntb); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n", 3138c2ecf20Sopenharmony_ci vec, db_mask, db_bits); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci wake_up(&tc->db_wq); 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic void tool_msg_event(void *ctx) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct tool_ctx *tc = ctx; 3218c2ecf20Sopenharmony_ci u64 msg_sts; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci msg_sts = ntb_msg_read_sts(tc->ntb); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci dev_dbg(&tc->ntb->dev, "message bits %#llx\n", msg_sts); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci wake_up(&tc->msg_wq); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic const struct ntb_ctx_ops tool_ops = { 3318c2ecf20Sopenharmony_ci .link_event = tool_link_event, 3328c2ecf20Sopenharmony_ci .db_event = tool_db_event, 3338c2ecf20Sopenharmony_ci .msg_event = tool_msg_event 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci/*============================================================================== 3378c2ecf20Sopenharmony_ci * Common read/write methods 3388c2ecf20Sopenharmony_ci *============================================================================== 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic ssize_t tool_fn_read(struct tool_ctx *tc, char __user *ubuf, 3428c2ecf20Sopenharmony_ci size_t size, loff_t *offp, 3438c2ecf20Sopenharmony_ci u64 (*fn_read)(struct ntb_dev *)) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci size_t buf_size; 3468c2ecf20Sopenharmony_ci char buf[TOOL_BUF_LEN]; 3478c2ecf20Sopenharmony_ci ssize_t pos; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (!fn_read) 3508c2ecf20Sopenharmony_ci return -EINVAL; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci buf_size = min(size, sizeof(buf)); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci pos = scnprintf(buf, buf_size, "%#llx\n", fn_read(tc->ntb)); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, size, offp, buf, pos); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic ssize_t tool_fn_write(struct tool_ctx *tc, 3608c2ecf20Sopenharmony_ci const char __user *ubuf, 3618c2ecf20Sopenharmony_ci size_t size, loff_t *offp, 3628c2ecf20Sopenharmony_ci int (*fn_set)(struct ntb_dev *, u64), 3638c2ecf20Sopenharmony_ci int (*fn_clear)(struct ntb_dev *, u64)) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci char *buf, cmd; 3668c2ecf20Sopenharmony_ci ssize_t ret; 3678c2ecf20Sopenharmony_ci u64 bits; 3688c2ecf20Sopenharmony_ci int n; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (*offp) 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci buf = kmalloc(size + 1, GFP_KERNEL); 3748c2ecf20Sopenharmony_ci if (!buf) 3758c2ecf20Sopenharmony_ci return -ENOMEM; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (copy_from_user(buf, ubuf, size)) { 3788c2ecf20Sopenharmony_ci kfree(buf); 3798c2ecf20Sopenharmony_ci return -EFAULT; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci buf[size] = 0; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci n = sscanf(buf, "%c %lli", &cmd, &bits); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci kfree(buf); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (n != 2) { 3898c2ecf20Sopenharmony_ci ret = -EINVAL; 3908c2ecf20Sopenharmony_ci } else if (cmd == 's') { 3918c2ecf20Sopenharmony_ci if (!fn_set) 3928c2ecf20Sopenharmony_ci ret = -EINVAL; 3938c2ecf20Sopenharmony_ci else 3948c2ecf20Sopenharmony_ci ret = fn_set(tc->ntb, bits); 3958c2ecf20Sopenharmony_ci } else if (cmd == 'c') { 3968c2ecf20Sopenharmony_ci if (!fn_clear) 3978c2ecf20Sopenharmony_ci ret = -EINVAL; 3988c2ecf20Sopenharmony_ci else 3998c2ecf20Sopenharmony_ci ret = fn_clear(tc->ntb, bits); 4008c2ecf20Sopenharmony_ci } else { 4018c2ecf20Sopenharmony_ci ret = -EINVAL; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return ret ? : size; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci/*============================================================================== 4088c2ecf20Sopenharmony_ci * Port read/write methods 4098c2ecf20Sopenharmony_ci *============================================================================== 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic ssize_t tool_port_read(struct file *filep, char __user *ubuf, 4138c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 4168c2ecf20Sopenharmony_ci char buf[TOOL_BUF_LEN]; 4178c2ecf20Sopenharmony_ci int pos; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci pos = scnprintf(buf, sizeof(buf), "%d\n", ntb_port_number(tc->ntb)); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, size, offp, buf, pos); 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_port_fops, 4258c2ecf20Sopenharmony_ci tool_port_read, 4268c2ecf20Sopenharmony_ci NULL); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic ssize_t tool_peer_port_read(struct file *filep, char __user *ubuf, 4298c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct tool_peer *peer = filep->private_data; 4328c2ecf20Sopenharmony_ci struct tool_ctx *tc = peer->tc; 4338c2ecf20Sopenharmony_ci char buf[TOOL_BUF_LEN]; 4348c2ecf20Sopenharmony_ci int pos; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci pos = scnprintf(buf, sizeof(buf), "%d\n", 4378c2ecf20Sopenharmony_ci ntb_peer_port_number(tc->ntb, peer->pidx)); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, size, offp, buf, pos); 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_peer_port_fops, 4438c2ecf20Sopenharmony_ci tool_peer_port_read, 4448c2ecf20Sopenharmony_ci NULL); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int tool_init_peers(struct tool_ctx *tc) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci int pidx; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci tc->peer_cnt = ntb_peer_port_count(tc->ntb); 4518c2ecf20Sopenharmony_ci tc->peers = devm_kcalloc(&tc->ntb->dev, tc->peer_cnt, 4528c2ecf20Sopenharmony_ci sizeof(*tc->peers), GFP_KERNEL); 4538c2ecf20Sopenharmony_ci if (tc->peers == NULL) 4548c2ecf20Sopenharmony_ci return -ENOMEM; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 4578c2ecf20Sopenharmony_ci tc->peers[pidx].pidx = pidx; 4588c2ecf20Sopenharmony_ci tc->peers[pidx].tc = tc; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return 0; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci/*============================================================================== 4658c2ecf20Sopenharmony_ci * Link state read/write methods 4668c2ecf20Sopenharmony_ci *============================================================================== 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic ssize_t tool_link_write(struct file *filep, const char __user *ubuf, 4708c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 4738c2ecf20Sopenharmony_ci bool val; 4748c2ecf20Sopenharmony_ci int ret; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci ret = kstrtobool_from_user(ubuf, size, &val); 4778c2ecf20Sopenharmony_ci if (ret) 4788c2ecf20Sopenharmony_ci return ret; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (val) 4818c2ecf20Sopenharmony_ci ret = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 4828c2ecf20Sopenharmony_ci else 4838c2ecf20Sopenharmony_ci ret = ntb_link_disable(tc->ntb); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (ret) 4868c2ecf20Sopenharmony_ci return ret; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci return size; 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_link_fops, 4928c2ecf20Sopenharmony_ci NULL, 4938c2ecf20Sopenharmony_ci tool_link_write); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic ssize_t tool_peer_link_read(struct file *filep, char __user *ubuf, 4968c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct tool_peer *peer = filep->private_data; 4998c2ecf20Sopenharmony_ci struct tool_ctx *tc = peer->tc; 5008c2ecf20Sopenharmony_ci char buf[3]; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (ntb_link_is_up(tc->ntb, NULL, NULL) & BIT(peer->pidx)) 5038c2ecf20Sopenharmony_ci buf[0] = 'Y'; 5048c2ecf20Sopenharmony_ci else 5058c2ecf20Sopenharmony_ci buf[0] = 'N'; 5068c2ecf20Sopenharmony_ci buf[1] = '\n'; 5078c2ecf20Sopenharmony_ci buf[2] = '\0'; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, size, offp, buf, 2); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_peer_link_fops, 5138c2ecf20Sopenharmony_ci tool_peer_link_read, 5148c2ecf20Sopenharmony_ci NULL); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic ssize_t tool_peer_link_event_write(struct file *filep, 5178c2ecf20Sopenharmony_ci const char __user *ubuf, 5188c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct tool_peer *peer = filep->private_data; 5218c2ecf20Sopenharmony_ci struct tool_ctx *tc = peer->tc; 5228c2ecf20Sopenharmony_ci u64 link_msk; 5238c2ecf20Sopenharmony_ci bool val; 5248c2ecf20Sopenharmony_ci int ret; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci ret = kstrtobool_from_user(ubuf, size, &val); 5278c2ecf20Sopenharmony_ci if (ret) 5288c2ecf20Sopenharmony_ci return ret; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci link_msk = BIT_ULL_MASK(peer->pidx); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (wait_event_interruptible(tc->link_wq, 5338c2ecf20Sopenharmony_ci !!(ntb_link_is_up(tc->ntb, NULL, NULL) & link_msk) == val)) 5348c2ecf20Sopenharmony_ci return -ERESTART; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return size; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_peer_link_event_fops, 5408c2ecf20Sopenharmony_ci NULL, 5418c2ecf20Sopenharmony_ci tool_peer_link_event_write); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci/*============================================================================== 5448c2ecf20Sopenharmony_ci * Memory windows read/write/setting methods 5458c2ecf20Sopenharmony_ci *============================================================================== 5468c2ecf20Sopenharmony_ci */ 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic ssize_t tool_mw_read(struct file *filep, char __user *ubuf, 5498c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct tool_mw *inmw = filep->private_data; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (inmw->mm_base == NULL) 5548c2ecf20Sopenharmony_ci return -ENXIO; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, size, offp, 5578c2ecf20Sopenharmony_ci inmw->mm_base, inmw->size); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic ssize_t tool_mw_write(struct file *filep, const char __user *ubuf, 5618c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct tool_mw *inmw = filep->private_data; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (inmw->mm_base == NULL) 5668c2ecf20Sopenharmony_ci return -ENXIO; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci return simple_write_to_buffer(inmw->mm_base, inmw->size, offp, 5698c2ecf20Sopenharmony_ci ubuf, size); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_mw_fops, 5738c2ecf20Sopenharmony_ci tool_mw_read, 5748c2ecf20Sopenharmony_ci tool_mw_write); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic int tool_setup_mw(struct tool_ctx *tc, int pidx, int widx, 5778c2ecf20Sopenharmony_ci size_t req_size) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci resource_size_t size, addr_align, size_align; 5808c2ecf20Sopenharmony_ci struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; 5818c2ecf20Sopenharmony_ci char buf[TOOL_BUF_LEN]; 5828c2ecf20Sopenharmony_ci int ret; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (inmw->mm_base != NULL) 5858c2ecf20Sopenharmony_ci return 0; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci ret = ntb_mw_get_align(tc->ntb, pidx, widx, &addr_align, 5888c2ecf20Sopenharmony_ci &size_align, &size); 5898c2ecf20Sopenharmony_ci if (ret) 5908c2ecf20Sopenharmony_ci return ret; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci inmw->size = min_t(resource_size_t, req_size, size); 5938c2ecf20Sopenharmony_ci inmw->size = round_up(inmw->size, addr_align); 5948c2ecf20Sopenharmony_ci inmw->size = round_up(inmw->size, size_align); 5958c2ecf20Sopenharmony_ci inmw->mm_base = dma_alloc_coherent(&tc->ntb->pdev->dev, inmw->size, 5968c2ecf20Sopenharmony_ci &inmw->dma_base, GFP_KERNEL); 5978c2ecf20Sopenharmony_ci if (!inmw->mm_base) 5988c2ecf20Sopenharmony_ci return -ENOMEM; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (!IS_ALIGNED(inmw->dma_base, addr_align)) { 6018c2ecf20Sopenharmony_ci ret = -ENOMEM; 6028c2ecf20Sopenharmony_ci goto err_free_dma; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci ret = ntb_mw_set_trans(tc->ntb, pidx, widx, inmw->dma_base, inmw->size); 6068c2ecf20Sopenharmony_ci if (ret) 6078c2ecf20Sopenharmony_ci goto err_free_dma; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "mw%d", widx); 6108c2ecf20Sopenharmony_ci inmw->dbgfs_file = debugfs_create_file(buf, 0600, 6118c2ecf20Sopenharmony_ci tc->peers[pidx].dbgfs_dir, inmw, 6128c2ecf20Sopenharmony_ci &tool_mw_fops); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return 0; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cierr_free_dma: 6178c2ecf20Sopenharmony_ci dma_free_coherent(&tc->ntb->pdev->dev, inmw->size, inmw->mm_base, 6188c2ecf20Sopenharmony_ci inmw->dma_base); 6198c2ecf20Sopenharmony_ci inmw->mm_base = NULL; 6208c2ecf20Sopenharmony_ci inmw->dma_base = 0; 6218c2ecf20Sopenharmony_ci inmw->size = 0; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci return ret; 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic void tool_free_mw(struct tool_ctx *tc, int pidx, int widx) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci debugfs_remove(inmw->dbgfs_file); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (inmw->mm_base != NULL) { 6338c2ecf20Sopenharmony_ci ntb_mw_clear_trans(tc->ntb, pidx, widx); 6348c2ecf20Sopenharmony_ci dma_free_coherent(&tc->ntb->pdev->dev, inmw->size, 6358c2ecf20Sopenharmony_ci inmw->mm_base, inmw->dma_base); 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci inmw->mm_base = NULL; 6398c2ecf20Sopenharmony_ci inmw->dma_base = 0; 6408c2ecf20Sopenharmony_ci inmw->size = 0; 6418c2ecf20Sopenharmony_ci inmw->dbgfs_file = NULL; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic ssize_t tool_mw_trans_read(struct file *filep, char __user *ubuf, 6458c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci struct tool_mw *inmw = filep->private_data; 6488c2ecf20Sopenharmony_ci resource_size_t addr_align; 6498c2ecf20Sopenharmony_ci resource_size_t size_align; 6508c2ecf20Sopenharmony_ci resource_size_t size_max; 6518c2ecf20Sopenharmony_ci ssize_t ret, off = 0; 6528c2ecf20Sopenharmony_ci size_t buf_size; 6538c2ecf20Sopenharmony_ci char *buf; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci buf_size = min_t(size_t, size, 512); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci buf = kmalloc(buf_size, GFP_KERNEL); 6588c2ecf20Sopenharmony_ci if (!buf) 6598c2ecf20Sopenharmony_ci return -ENOMEM; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci ret = ntb_mw_get_align(inmw->tc->ntb, inmw->pidx, inmw->widx, 6628c2ecf20Sopenharmony_ci &addr_align, &size_align, &size_max); 6638c2ecf20Sopenharmony_ci if (ret) 6648c2ecf20Sopenharmony_ci goto err; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6678c2ecf20Sopenharmony_ci "Inbound MW \t%d\n", 6688c2ecf20Sopenharmony_ci inmw->widx); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6718c2ecf20Sopenharmony_ci "Port \t%d (%d)\n", 6728c2ecf20Sopenharmony_ci ntb_peer_port_number(inmw->tc->ntb, inmw->pidx), 6738c2ecf20Sopenharmony_ci inmw->pidx); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6768c2ecf20Sopenharmony_ci "Window Address \t0x%pK\n", inmw->mm_base); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6798c2ecf20Sopenharmony_ci "DMA Address \t%pad\n", 6808c2ecf20Sopenharmony_ci &inmw->dma_base); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6838c2ecf20Sopenharmony_ci "Window Size \t%pap\n", 6848c2ecf20Sopenharmony_ci &inmw->size); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6878c2ecf20Sopenharmony_ci "Alignment \t%pap\n", 6888c2ecf20Sopenharmony_ci &addr_align); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6918c2ecf20Sopenharmony_ci "Size Alignment \t%pap\n", 6928c2ecf20Sopenharmony_ci &size_align); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6958c2ecf20Sopenharmony_ci "Size Max \t%pap\n", 6968c2ecf20Sopenharmony_ci &size_max); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(ubuf, size, offp, buf, off); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cierr: 7018c2ecf20Sopenharmony_ci kfree(buf); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci return ret; 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic ssize_t tool_mw_trans_write(struct file *filep, const char __user *ubuf, 7078c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci struct tool_mw *inmw = filep->private_data; 7108c2ecf20Sopenharmony_ci unsigned int val; 7118c2ecf20Sopenharmony_ci int ret; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci ret = kstrtouint_from_user(ubuf, size, 0, &val); 7148c2ecf20Sopenharmony_ci if (ret) 7158c2ecf20Sopenharmony_ci return ret; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci tool_free_mw(inmw->tc, inmw->pidx, inmw->widx); 7188c2ecf20Sopenharmony_ci if (val) { 7198c2ecf20Sopenharmony_ci ret = tool_setup_mw(inmw->tc, inmw->pidx, inmw->widx, val); 7208c2ecf20Sopenharmony_ci if (ret) 7218c2ecf20Sopenharmony_ci return ret; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci return size; 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_mw_trans_fops, 7288c2ecf20Sopenharmony_ci tool_mw_trans_read, 7298c2ecf20Sopenharmony_ci tool_mw_trans_write); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf, 7328c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci struct tool_mw *outmw = filep->private_data; 7358c2ecf20Sopenharmony_ci loff_t pos = *offp; 7368c2ecf20Sopenharmony_ci ssize_t ret; 7378c2ecf20Sopenharmony_ci void *buf; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (outmw->io_base == NULL) 7408c2ecf20Sopenharmony_ci return -EIO; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (pos >= outmw->size || !size) 7438c2ecf20Sopenharmony_ci return 0; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if (size > outmw->size - pos) 7468c2ecf20Sopenharmony_ci size = outmw->size - pos; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci buf = kmalloc(size, GFP_KERNEL); 7498c2ecf20Sopenharmony_ci if (!buf) 7508c2ecf20Sopenharmony_ci return -ENOMEM; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci memcpy_fromio(buf, outmw->io_base + pos, size); 7538c2ecf20Sopenharmony_ci ret = copy_to_user(ubuf, buf, size); 7548c2ecf20Sopenharmony_ci if (ret == size) { 7558c2ecf20Sopenharmony_ci ret = -EFAULT; 7568c2ecf20Sopenharmony_ci goto err_free; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci size -= ret; 7608c2ecf20Sopenharmony_ci *offp = pos + size; 7618c2ecf20Sopenharmony_ci ret = size; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cierr_free: 7648c2ecf20Sopenharmony_ci kfree(buf); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci return ret; 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf, 7708c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci struct tool_mw *outmw = filep->private_data; 7738c2ecf20Sopenharmony_ci ssize_t ret; 7748c2ecf20Sopenharmony_ci loff_t pos = *offp; 7758c2ecf20Sopenharmony_ci void *buf; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (outmw->io_base == NULL) 7788c2ecf20Sopenharmony_ci return -EIO; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (pos >= outmw->size || !size) 7818c2ecf20Sopenharmony_ci return 0; 7828c2ecf20Sopenharmony_ci if (size > outmw->size - pos) 7838c2ecf20Sopenharmony_ci size = outmw->size - pos; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci buf = kmalloc(size, GFP_KERNEL); 7868c2ecf20Sopenharmony_ci if (!buf) 7878c2ecf20Sopenharmony_ci return -ENOMEM; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci ret = copy_from_user(buf, ubuf, size); 7908c2ecf20Sopenharmony_ci if (ret == size) { 7918c2ecf20Sopenharmony_ci ret = -EFAULT; 7928c2ecf20Sopenharmony_ci goto err_free; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci size -= ret; 7968c2ecf20Sopenharmony_ci *offp = pos + size; 7978c2ecf20Sopenharmony_ci ret = size; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci memcpy_toio(outmw->io_base + pos, buf, size); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cierr_free: 8028c2ecf20Sopenharmony_ci kfree(buf); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci return ret; 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_peer_mw_fops, 8088c2ecf20Sopenharmony_ci tool_peer_mw_read, 8098c2ecf20Sopenharmony_ci tool_peer_mw_write); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic int tool_setup_peer_mw(struct tool_ctx *tc, int pidx, int widx, 8128c2ecf20Sopenharmony_ci u64 req_addr, size_t req_size) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci struct tool_mw *outmw = &tc->outmws[widx]; 8158c2ecf20Sopenharmony_ci resource_size_t map_size; 8168c2ecf20Sopenharmony_ci phys_addr_t map_base; 8178c2ecf20Sopenharmony_ci char buf[TOOL_BUF_LEN]; 8188c2ecf20Sopenharmony_ci int ret; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (outmw->io_base != NULL) 8218c2ecf20Sopenharmony_ci return 0; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci ret = ntb_peer_mw_get_addr(tc->ntb, widx, &map_base, &map_size); 8248c2ecf20Sopenharmony_ci if (ret) 8258c2ecf20Sopenharmony_ci return ret; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci ret = ntb_peer_mw_set_trans(tc->ntb, pidx, widx, req_addr, req_size); 8288c2ecf20Sopenharmony_ci if (ret) 8298c2ecf20Sopenharmony_ci return ret; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci outmw->io_base = ioremap_wc(map_base, map_size); 8328c2ecf20Sopenharmony_ci if (outmw->io_base == NULL) { 8338c2ecf20Sopenharmony_ci ret = -EFAULT; 8348c2ecf20Sopenharmony_ci goto err_clear_trans; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci outmw->tr_base = req_addr; 8388c2ecf20Sopenharmony_ci outmw->size = req_size; 8398c2ecf20Sopenharmony_ci outmw->pidx = pidx; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "peer_mw%d", widx); 8428c2ecf20Sopenharmony_ci outmw->dbgfs_file = debugfs_create_file(buf, 0600, 8438c2ecf20Sopenharmony_ci tc->peers[pidx].dbgfs_dir, outmw, 8448c2ecf20Sopenharmony_ci &tool_peer_mw_fops); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci return 0; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_cierr_clear_trans: 8498c2ecf20Sopenharmony_ci ntb_peer_mw_clear_trans(tc->ntb, pidx, widx); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci return ret; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_cistatic void tool_free_peer_mw(struct tool_ctx *tc, int widx) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci struct tool_mw *outmw = &tc->outmws[widx]; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci debugfs_remove(outmw->dbgfs_file); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (outmw->io_base != NULL) { 8618c2ecf20Sopenharmony_ci iounmap(tc->outmws[widx].io_base); 8628c2ecf20Sopenharmony_ci ntb_peer_mw_clear_trans(tc->ntb, outmw->pidx, widx); 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci outmw->io_base = NULL; 8668c2ecf20Sopenharmony_ci outmw->tr_base = 0; 8678c2ecf20Sopenharmony_ci outmw->size = 0; 8688c2ecf20Sopenharmony_ci outmw->pidx = -1; 8698c2ecf20Sopenharmony_ci outmw->dbgfs_file = NULL; 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic ssize_t tool_peer_mw_trans_read(struct file *filep, char __user *ubuf, 8738c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci struct tool_mw_wrap *outmw_wrap = filep->private_data; 8768c2ecf20Sopenharmony_ci struct tool_mw *outmw = outmw_wrap->mw; 8778c2ecf20Sopenharmony_ci resource_size_t map_size; 8788c2ecf20Sopenharmony_ci phys_addr_t map_base; 8798c2ecf20Sopenharmony_ci ssize_t off = 0; 8808c2ecf20Sopenharmony_ci size_t buf_size; 8818c2ecf20Sopenharmony_ci char *buf; 8828c2ecf20Sopenharmony_ci int ret; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci ret = ntb_peer_mw_get_addr(outmw->tc->ntb, outmw->widx, 8858c2ecf20Sopenharmony_ci &map_base, &map_size); 8868c2ecf20Sopenharmony_ci if (ret) 8878c2ecf20Sopenharmony_ci return ret; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci buf_size = min_t(size_t, size, 512); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci buf = kmalloc(buf_size, GFP_KERNEL); 8928c2ecf20Sopenharmony_ci if (!buf) 8938c2ecf20Sopenharmony_ci return -ENOMEM; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 8968c2ecf20Sopenharmony_ci "Outbound MW: \t%d\n", outmw->widx); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (outmw->io_base != NULL) { 8998c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 9008c2ecf20Sopenharmony_ci "Port attached \t%d (%d)\n", 9018c2ecf20Sopenharmony_ci ntb_peer_port_number(outmw->tc->ntb, outmw->pidx), 9028c2ecf20Sopenharmony_ci outmw->pidx); 9038c2ecf20Sopenharmony_ci } else { 9048c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 9058c2ecf20Sopenharmony_ci "Port attached \t-1 (-1)\n"); 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 9098c2ecf20Sopenharmony_ci "Virtual address \t0x%pK\n", outmw->io_base); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 9128c2ecf20Sopenharmony_ci "Phys Address \t%pap\n", &map_base); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 9158c2ecf20Sopenharmony_ci "Mapping Size \t%pap\n", &map_size); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 9188c2ecf20Sopenharmony_ci "Translation Address \t0x%016llx\n", outmw->tr_base); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 9218c2ecf20Sopenharmony_ci "Window Size \t%pap\n", &outmw->size); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(ubuf, size, offp, buf, off); 9248c2ecf20Sopenharmony_ci kfree(buf); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci return ret; 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic ssize_t tool_peer_mw_trans_write(struct file *filep, 9308c2ecf20Sopenharmony_ci const char __user *ubuf, 9318c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci struct tool_mw_wrap *outmw_wrap = filep->private_data; 9348c2ecf20Sopenharmony_ci struct tool_mw *outmw = outmw_wrap->mw; 9358c2ecf20Sopenharmony_ci size_t buf_size, wsize; 9368c2ecf20Sopenharmony_ci char buf[TOOL_BUF_LEN]; 9378c2ecf20Sopenharmony_ci int ret, n; 9388c2ecf20Sopenharmony_ci u64 addr; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci buf_size = min(size, (sizeof(buf) - 1)); 9418c2ecf20Sopenharmony_ci if (copy_from_user(buf, ubuf, buf_size)) 9428c2ecf20Sopenharmony_ci return -EFAULT; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci buf[buf_size] = '\0'; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci n = sscanf(buf, "%lli:%zi", &addr, &wsize); 9478c2ecf20Sopenharmony_ci if (n != 2) 9488c2ecf20Sopenharmony_ci return -EINVAL; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci tool_free_peer_mw(outmw->tc, outmw->widx); 9518c2ecf20Sopenharmony_ci if (wsize) { 9528c2ecf20Sopenharmony_ci ret = tool_setup_peer_mw(outmw->tc, outmw_wrap->pidx, 9538c2ecf20Sopenharmony_ci outmw->widx, addr, wsize); 9548c2ecf20Sopenharmony_ci if (ret) 9558c2ecf20Sopenharmony_ci return ret; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci return size; 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_peer_mw_trans_fops, 9628c2ecf20Sopenharmony_ci tool_peer_mw_trans_read, 9638c2ecf20Sopenharmony_ci tool_peer_mw_trans_write); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cistatic int tool_init_mws(struct tool_ctx *tc) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci int widx, pidx; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci /* Initialize outbound memory windows */ 9708c2ecf20Sopenharmony_ci tc->outmw_cnt = ntb_peer_mw_count(tc->ntb); 9718c2ecf20Sopenharmony_ci tc->outmws = devm_kcalloc(&tc->ntb->dev, tc->outmw_cnt, 9728c2ecf20Sopenharmony_ci sizeof(*tc->outmws), GFP_KERNEL); 9738c2ecf20Sopenharmony_ci if (tc->outmws == NULL) 9748c2ecf20Sopenharmony_ci return -ENOMEM; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci for (widx = 0; widx < tc->outmw_cnt; widx++) { 9778c2ecf20Sopenharmony_ci tc->outmws[widx].widx = widx; 9788c2ecf20Sopenharmony_ci tc->outmws[widx].pidx = -1; 9798c2ecf20Sopenharmony_ci tc->outmws[widx].tc = tc; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* Initialize inbound memory windows and outbound MWs wrapper */ 9838c2ecf20Sopenharmony_ci for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 9848c2ecf20Sopenharmony_ci tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->ntb, pidx); 9858c2ecf20Sopenharmony_ci tc->peers[pidx].inmws = 9868c2ecf20Sopenharmony_ci devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].inmw_cnt, 9878c2ecf20Sopenharmony_ci sizeof(*tc->peers[pidx].inmws), GFP_KERNEL); 9888c2ecf20Sopenharmony_ci if (tc->peers[pidx].inmws == NULL) 9898c2ecf20Sopenharmony_ci return -ENOMEM; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 9928c2ecf20Sopenharmony_ci tc->peers[pidx].inmws[widx].widx = widx; 9938c2ecf20Sopenharmony_ci tc->peers[pidx].inmws[widx].pidx = pidx; 9948c2ecf20Sopenharmony_ci tc->peers[pidx].inmws[widx].tc = tc; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci tc->peers[pidx].outmw_cnt = ntb_peer_mw_count(tc->ntb); 9988c2ecf20Sopenharmony_ci tc->peers[pidx].outmws = 9998c2ecf20Sopenharmony_ci devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmw_cnt, 10008c2ecf20Sopenharmony_ci sizeof(*tc->peers[pidx].outmws), GFP_KERNEL); 10018c2ecf20Sopenharmony_ci if (tc->peers[pidx].outmws == NULL) 10028c2ecf20Sopenharmony_ci return -ENOMEM; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) { 10058c2ecf20Sopenharmony_ci tc->peers[pidx].outmws[widx].pidx = pidx; 10068c2ecf20Sopenharmony_ci tc->peers[pidx].outmws[widx].mw = &tc->outmws[widx]; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci return 0; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cistatic void tool_clear_mws(struct tool_ctx *tc) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci int widx, pidx; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci /* Free outbound memory windows */ 10188c2ecf20Sopenharmony_ci for (widx = 0; widx < tc->outmw_cnt; widx++) 10198c2ecf20Sopenharmony_ci tool_free_peer_mw(tc, widx); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci /* Free outbound memory windows */ 10228c2ecf20Sopenharmony_ci for (pidx = 0; pidx < tc->peer_cnt; pidx++) 10238c2ecf20Sopenharmony_ci for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) 10248c2ecf20Sopenharmony_ci tool_free_mw(tc, pidx, widx); 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci/*============================================================================== 10288c2ecf20Sopenharmony_ci * Doorbell read/write methods 10298c2ecf20Sopenharmony_ci *============================================================================== 10308c2ecf20Sopenharmony_ci */ 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cistatic ssize_t tool_db_read(struct file *filep, char __user *ubuf, 10338c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read); 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic ssize_t tool_db_write(struct file *filep, const char __user *ubuf, 10418c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set, 10468c2ecf20Sopenharmony_ci tc->ntb->ops->db_clear); 10478c2ecf20Sopenharmony_ci} 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_db_fops, 10508c2ecf20Sopenharmony_ci tool_db_read, 10518c2ecf20Sopenharmony_ci tool_db_write); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic ssize_t tool_db_valid_mask_read(struct file *filep, char __user *ubuf, 10548c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 10558c2ecf20Sopenharmony_ci{ 10568c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_valid_mask); 10598c2ecf20Sopenharmony_ci} 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_db_valid_mask_fops, 10628c2ecf20Sopenharmony_ci tool_db_valid_mask_read, 10638c2ecf20Sopenharmony_ci NULL); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_cistatic ssize_t tool_db_mask_read(struct file *filep, char __user *ubuf, 10668c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 10678c2ecf20Sopenharmony_ci{ 10688c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read_mask); 10718c2ecf20Sopenharmony_ci} 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_cistatic ssize_t tool_db_mask_write(struct file *filep, const char __user *ubuf, 10748c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 10758c2ecf20Sopenharmony_ci{ 10768c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set_mask, 10798c2ecf20Sopenharmony_ci tc->ntb->ops->db_clear_mask); 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_db_mask_fops, 10838c2ecf20Sopenharmony_ci tool_db_mask_read, 10848c2ecf20Sopenharmony_ci tool_db_mask_write); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_cistatic ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf, 10878c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->peer_db_read); 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf, 10958c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->peer_db_set, 11008c2ecf20Sopenharmony_ci tc->ntb->ops->peer_db_clear); 11018c2ecf20Sopenharmony_ci} 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_peer_db_fops, 11048c2ecf20Sopenharmony_ci tool_peer_db_read, 11058c2ecf20Sopenharmony_ci tool_peer_db_write); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic ssize_t tool_peer_db_mask_read(struct file *filep, char __user *ubuf, 11088c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci return tool_fn_read(tc, ubuf, size, offp, 11138c2ecf20Sopenharmony_ci tc->ntb->ops->peer_db_read_mask); 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic ssize_t tool_peer_db_mask_write(struct file *filep, 11178c2ecf20Sopenharmony_ci const char __user *ubuf, 11188c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci return tool_fn_write(tc, ubuf, size, offp, 11238c2ecf20Sopenharmony_ci tc->ntb->ops->peer_db_set_mask, 11248c2ecf20Sopenharmony_ci tc->ntb->ops->peer_db_clear_mask); 11258c2ecf20Sopenharmony_ci} 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_peer_db_mask_fops, 11288c2ecf20Sopenharmony_ci tool_peer_db_mask_read, 11298c2ecf20Sopenharmony_ci tool_peer_db_mask_write); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic ssize_t tool_db_event_write(struct file *filep, 11328c2ecf20Sopenharmony_ci const char __user *ubuf, 11338c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 11368c2ecf20Sopenharmony_ci u64 val; 11378c2ecf20Sopenharmony_ci int ret; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci ret = kstrtou64_from_user(ubuf, size, 0, &val); 11408c2ecf20Sopenharmony_ci if (ret) 11418c2ecf20Sopenharmony_ci return ret; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (wait_event_interruptible(tc->db_wq, ntb_db_read(tc->ntb) == val)) 11448c2ecf20Sopenharmony_ci return -ERESTART; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci return size; 11478c2ecf20Sopenharmony_ci} 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_db_event_fops, 11508c2ecf20Sopenharmony_ci NULL, 11518c2ecf20Sopenharmony_ci tool_db_event_write); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci/*============================================================================== 11548c2ecf20Sopenharmony_ci * Scratchpads read/write methods 11558c2ecf20Sopenharmony_ci *============================================================================== 11568c2ecf20Sopenharmony_ci */ 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic ssize_t tool_spad_read(struct file *filep, char __user *ubuf, 11598c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci struct tool_spad *spad = filep->private_data; 11628c2ecf20Sopenharmony_ci char buf[TOOL_BUF_LEN]; 11638c2ecf20Sopenharmony_ci ssize_t pos; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci if (!spad->tc->ntb->ops->spad_read) 11668c2ecf20Sopenharmony_ci return -EINVAL; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci pos = scnprintf(buf, sizeof(buf), "%#x\n", 11698c2ecf20Sopenharmony_ci ntb_spad_read(spad->tc->ntb, spad->sidx)); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, size, offp, buf, pos); 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_cistatic ssize_t tool_spad_write(struct file *filep, const char __user *ubuf, 11758c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 11768c2ecf20Sopenharmony_ci{ 11778c2ecf20Sopenharmony_ci struct tool_spad *spad = filep->private_data; 11788c2ecf20Sopenharmony_ci u32 val; 11798c2ecf20Sopenharmony_ci int ret; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci if (!spad->tc->ntb->ops->spad_write) { 11828c2ecf20Sopenharmony_ci dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n"); 11838c2ecf20Sopenharmony_ci return -EINVAL; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci ret = kstrtou32_from_user(ubuf, size, 0, &val); 11878c2ecf20Sopenharmony_ci if (ret) 11888c2ecf20Sopenharmony_ci return ret; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci ret = ntb_spad_write(spad->tc->ntb, spad->sidx, val); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci return ret ?: size; 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_spad_fops, 11968c2ecf20Sopenharmony_ci tool_spad_read, 11978c2ecf20Sopenharmony_ci tool_spad_write); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf, 12008c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 12018c2ecf20Sopenharmony_ci{ 12028c2ecf20Sopenharmony_ci struct tool_spad *spad = filep->private_data; 12038c2ecf20Sopenharmony_ci char buf[TOOL_BUF_LEN]; 12048c2ecf20Sopenharmony_ci ssize_t pos; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (!spad->tc->ntb->ops->peer_spad_read) 12078c2ecf20Sopenharmony_ci return -EINVAL; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci pos = scnprintf(buf, sizeof(buf), "%#x\n", 12108c2ecf20Sopenharmony_ci ntb_peer_spad_read(spad->tc->ntb, spad->pidx, spad->sidx)); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, size, offp, buf, pos); 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf, 12168c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci struct tool_spad *spad = filep->private_data; 12198c2ecf20Sopenharmony_ci u32 val; 12208c2ecf20Sopenharmony_ci int ret; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (!spad->tc->ntb->ops->peer_spad_write) { 12238c2ecf20Sopenharmony_ci dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n"); 12248c2ecf20Sopenharmony_ci return -EINVAL; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci ret = kstrtou32_from_user(ubuf, size, 0, &val); 12288c2ecf20Sopenharmony_ci if (ret) 12298c2ecf20Sopenharmony_ci return ret; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci ret = ntb_peer_spad_write(spad->tc->ntb, spad->pidx, spad->sidx, val); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci return ret ?: size; 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_peer_spad_fops, 12378c2ecf20Sopenharmony_ci tool_peer_spad_read, 12388c2ecf20Sopenharmony_ci tool_peer_spad_write); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_cistatic int tool_init_spads(struct tool_ctx *tc) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci int sidx, pidx; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci /* Initialize inbound scratchpad structures */ 12458c2ecf20Sopenharmony_ci tc->inspad_cnt = ntb_spad_count(tc->ntb); 12468c2ecf20Sopenharmony_ci tc->inspads = devm_kcalloc(&tc->ntb->dev, tc->inspad_cnt, 12478c2ecf20Sopenharmony_ci sizeof(*tc->inspads), GFP_KERNEL); 12488c2ecf20Sopenharmony_ci if (tc->inspads == NULL) 12498c2ecf20Sopenharmony_ci return -ENOMEM; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 12528c2ecf20Sopenharmony_ci tc->inspads[sidx].sidx = sidx; 12538c2ecf20Sopenharmony_ci tc->inspads[sidx].pidx = -1; 12548c2ecf20Sopenharmony_ci tc->inspads[sidx].tc = tc; 12558c2ecf20Sopenharmony_ci } 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci /* Initialize outbound scratchpad structures */ 12588c2ecf20Sopenharmony_ci for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 12598c2ecf20Sopenharmony_ci tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->ntb); 12608c2ecf20Sopenharmony_ci tc->peers[pidx].outspads = 12618c2ecf20Sopenharmony_ci devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outspad_cnt, 12628c2ecf20Sopenharmony_ci sizeof(*tc->peers[pidx].outspads), GFP_KERNEL); 12638c2ecf20Sopenharmony_ci if (tc->peers[pidx].outspads == NULL) 12648c2ecf20Sopenharmony_ci return -ENOMEM; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 12678c2ecf20Sopenharmony_ci tc->peers[pidx].outspads[sidx].sidx = sidx; 12688c2ecf20Sopenharmony_ci tc->peers[pidx].outspads[sidx].pidx = pidx; 12698c2ecf20Sopenharmony_ci tc->peers[pidx].outspads[sidx].tc = tc; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci return 0; 12748c2ecf20Sopenharmony_ci} 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci/*============================================================================== 12778c2ecf20Sopenharmony_ci * Messages read/write methods 12788c2ecf20Sopenharmony_ci *============================================================================== 12798c2ecf20Sopenharmony_ci */ 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_cistatic ssize_t tool_inmsg_read(struct file *filep, char __user *ubuf, 12828c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci struct tool_msg *msg = filep->private_data; 12858c2ecf20Sopenharmony_ci char buf[TOOL_BUF_LEN]; 12868c2ecf20Sopenharmony_ci ssize_t pos; 12878c2ecf20Sopenharmony_ci u32 data; 12888c2ecf20Sopenharmony_ci int pidx; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci data = ntb_msg_read(msg->tc->ntb, &pidx, msg->midx); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci pos = scnprintf(buf, sizeof(buf), "0x%08x<-%d\n", data, pidx); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, size, offp, buf, pos); 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_inmsg_fops, 12988c2ecf20Sopenharmony_ci tool_inmsg_read, 12998c2ecf20Sopenharmony_ci NULL); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_cistatic ssize_t tool_outmsg_write(struct file *filep, 13028c2ecf20Sopenharmony_ci const char __user *ubuf, 13038c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 13048c2ecf20Sopenharmony_ci{ 13058c2ecf20Sopenharmony_ci struct tool_msg *msg = filep->private_data; 13068c2ecf20Sopenharmony_ci u32 val; 13078c2ecf20Sopenharmony_ci int ret; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci ret = kstrtou32_from_user(ubuf, size, 0, &val); 13108c2ecf20Sopenharmony_ci if (ret) 13118c2ecf20Sopenharmony_ci return ret; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci ret = ntb_peer_msg_write(msg->tc->ntb, msg->pidx, msg->midx, val); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci return ret ? : size; 13168c2ecf20Sopenharmony_ci} 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_outmsg_fops, 13198c2ecf20Sopenharmony_ci NULL, 13208c2ecf20Sopenharmony_ci tool_outmsg_write); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_cistatic ssize_t tool_msg_sts_read(struct file *filep, char __user *ubuf, 13238c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 13248c2ecf20Sopenharmony_ci{ 13258c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_read_sts); 13288c2ecf20Sopenharmony_ci} 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_cistatic ssize_t tool_msg_sts_write(struct file *filep, const char __user *ubuf, 13318c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci return tool_fn_write(tc, ubuf, size, offp, NULL, 13368c2ecf20Sopenharmony_ci tc->ntb->ops->msg_clear_sts); 13378c2ecf20Sopenharmony_ci} 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_msg_sts_fops, 13408c2ecf20Sopenharmony_ci tool_msg_sts_read, 13418c2ecf20Sopenharmony_ci tool_msg_sts_write); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_cistatic ssize_t tool_msg_inbits_read(struct file *filep, char __user *ubuf, 13448c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 13458c2ecf20Sopenharmony_ci{ 13468c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_inbits); 13498c2ecf20Sopenharmony_ci} 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_msg_inbits_fops, 13528c2ecf20Sopenharmony_ci tool_msg_inbits_read, 13538c2ecf20Sopenharmony_ci NULL); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_cistatic ssize_t tool_msg_outbits_read(struct file *filep, char __user *ubuf, 13568c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 13578c2ecf20Sopenharmony_ci{ 13588c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_outbits); 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_msg_outbits_fops, 13648c2ecf20Sopenharmony_ci tool_msg_outbits_read, 13658c2ecf20Sopenharmony_ci NULL); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_cistatic ssize_t tool_msg_mask_write(struct file *filep, const char __user *ubuf, 13688c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 13698c2ecf20Sopenharmony_ci{ 13708c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci return tool_fn_write(tc, ubuf, size, offp, 13738c2ecf20Sopenharmony_ci tc->ntb->ops->msg_set_mask, 13748c2ecf20Sopenharmony_ci tc->ntb->ops->msg_clear_mask); 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_msg_mask_fops, 13788c2ecf20Sopenharmony_ci NULL, 13798c2ecf20Sopenharmony_ci tool_msg_mask_write); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_cistatic ssize_t tool_msg_event_write(struct file *filep, 13828c2ecf20Sopenharmony_ci const char __user *ubuf, 13838c2ecf20Sopenharmony_ci size_t size, loff_t *offp) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci struct tool_ctx *tc = filep->private_data; 13868c2ecf20Sopenharmony_ci u64 val; 13878c2ecf20Sopenharmony_ci int ret; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci ret = kstrtou64_from_user(ubuf, size, 0, &val); 13908c2ecf20Sopenharmony_ci if (ret) 13918c2ecf20Sopenharmony_ci return ret; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci if (wait_event_interruptible(tc->msg_wq, 13948c2ecf20Sopenharmony_ci ntb_msg_read_sts(tc->ntb) == val)) 13958c2ecf20Sopenharmony_ci return -ERESTART; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci return size; 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cistatic TOOL_FOPS_RDWR(tool_msg_event_fops, 14018c2ecf20Sopenharmony_ci NULL, 14028c2ecf20Sopenharmony_ci tool_msg_event_write); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_cistatic int tool_init_msgs(struct tool_ctx *tc) 14058c2ecf20Sopenharmony_ci{ 14068c2ecf20Sopenharmony_ci int midx, pidx; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci /* Initialize inbound message structures */ 14098c2ecf20Sopenharmony_ci tc->inmsg_cnt = ntb_msg_count(tc->ntb); 14108c2ecf20Sopenharmony_ci tc->inmsgs = devm_kcalloc(&tc->ntb->dev, tc->inmsg_cnt, 14118c2ecf20Sopenharmony_ci sizeof(*tc->inmsgs), GFP_KERNEL); 14128c2ecf20Sopenharmony_ci if (tc->inmsgs == NULL) 14138c2ecf20Sopenharmony_ci return -ENOMEM; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci for (midx = 0; midx < tc->inmsg_cnt; midx++) { 14168c2ecf20Sopenharmony_ci tc->inmsgs[midx].midx = midx; 14178c2ecf20Sopenharmony_ci tc->inmsgs[midx].pidx = -1; 14188c2ecf20Sopenharmony_ci tc->inmsgs[midx].tc = tc; 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci /* Initialize outbound message structures */ 14228c2ecf20Sopenharmony_ci for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 14238c2ecf20Sopenharmony_ci tc->peers[pidx].outmsg_cnt = ntb_msg_count(tc->ntb); 14248c2ecf20Sopenharmony_ci tc->peers[pidx].outmsgs = 14258c2ecf20Sopenharmony_ci devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmsg_cnt, 14268c2ecf20Sopenharmony_ci sizeof(*tc->peers[pidx].outmsgs), GFP_KERNEL); 14278c2ecf20Sopenharmony_ci if (tc->peers[pidx].outmsgs == NULL) 14288c2ecf20Sopenharmony_ci return -ENOMEM; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) { 14318c2ecf20Sopenharmony_ci tc->peers[pidx].outmsgs[midx].midx = midx; 14328c2ecf20Sopenharmony_ci tc->peers[pidx].outmsgs[midx].pidx = pidx; 14338c2ecf20Sopenharmony_ci tc->peers[pidx].outmsgs[midx].tc = tc; 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci return 0; 14388c2ecf20Sopenharmony_ci} 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci/*============================================================================== 14418c2ecf20Sopenharmony_ci * Initialization methods 14428c2ecf20Sopenharmony_ci *============================================================================== 14438c2ecf20Sopenharmony_ci */ 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_cistatic struct tool_ctx *tool_create_data(struct ntb_dev *ntb) 14468c2ecf20Sopenharmony_ci{ 14478c2ecf20Sopenharmony_ci struct tool_ctx *tc; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci tc = devm_kzalloc(&ntb->dev, sizeof(*tc), GFP_KERNEL); 14508c2ecf20Sopenharmony_ci if (tc == NULL) 14518c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci tc->ntb = ntb; 14548c2ecf20Sopenharmony_ci init_waitqueue_head(&tc->link_wq); 14558c2ecf20Sopenharmony_ci init_waitqueue_head(&tc->db_wq); 14568c2ecf20Sopenharmony_ci init_waitqueue_head(&tc->msg_wq); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci if (ntb_db_is_unsafe(ntb)) 14598c2ecf20Sopenharmony_ci dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci if (ntb_spad_is_unsafe(ntb)) 14628c2ecf20Sopenharmony_ci dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci return tc; 14658c2ecf20Sopenharmony_ci} 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_cistatic void tool_clear_data(struct tool_ctx *tc) 14688c2ecf20Sopenharmony_ci{ 14698c2ecf20Sopenharmony_ci wake_up(&tc->link_wq); 14708c2ecf20Sopenharmony_ci wake_up(&tc->db_wq); 14718c2ecf20Sopenharmony_ci wake_up(&tc->msg_wq); 14728c2ecf20Sopenharmony_ci} 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_cistatic int tool_init_ntb(struct tool_ctx *tc) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci return ntb_set_ctx(tc->ntb, tc, &tool_ops); 14778c2ecf20Sopenharmony_ci} 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_cistatic void tool_clear_ntb(struct tool_ctx *tc) 14808c2ecf20Sopenharmony_ci{ 14818c2ecf20Sopenharmony_ci ntb_clear_ctx(tc->ntb); 14828c2ecf20Sopenharmony_ci ntb_link_disable(tc->ntb); 14838c2ecf20Sopenharmony_ci} 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_cistatic void tool_setup_dbgfs(struct tool_ctx *tc) 14868c2ecf20Sopenharmony_ci{ 14878c2ecf20Sopenharmony_ci int pidx, widx, sidx, midx; 14888c2ecf20Sopenharmony_ci char buf[TOOL_BUF_LEN]; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci /* This modules is useless without dbgfs... */ 14918c2ecf20Sopenharmony_ci if (!tool_dbgfs_topdir) { 14928c2ecf20Sopenharmony_ci tc->dbgfs_dir = NULL; 14938c2ecf20Sopenharmony_ci return; 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci tc->dbgfs_dir = debugfs_create_dir(dev_name(&tc->ntb->dev), 14978c2ecf20Sopenharmony_ci tool_dbgfs_topdir); 14988c2ecf20Sopenharmony_ci if (!tc->dbgfs_dir) 14998c2ecf20Sopenharmony_ci return; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci debugfs_create_file("port", 0600, tc->dbgfs_dir, 15028c2ecf20Sopenharmony_ci tc, &tool_port_fops); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci debugfs_create_file("link", 0600, tc->dbgfs_dir, 15058c2ecf20Sopenharmony_ci tc, &tool_link_fops); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci debugfs_create_file("db", 0600, tc->dbgfs_dir, 15088c2ecf20Sopenharmony_ci tc, &tool_db_fops); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci debugfs_create_file("db_valid_mask", 0600, tc->dbgfs_dir, 15118c2ecf20Sopenharmony_ci tc, &tool_db_valid_mask_fops); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci debugfs_create_file("db_mask", 0600, tc->dbgfs_dir, 15148c2ecf20Sopenharmony_ci tc, &tool_db_mask_fops); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci debugfs_create_file("db_event", 0600, tc->dbgfs_dir, 15178c2ecf20Sopenharmony_ci tc, &tool_db_event_fops); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci debugfs_create_file("peer_db", 0600, tc->dbgfs_dir, 15208c2ecf20Sopenharmony_ci tc, &tool_peer_db_fops); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci debugfs_create_file("peer_db_mask", 0600, tc->dbgfs_dir, 15238c2ecf20Sopenharmony_ci tc, &tool_peer_db_mask_fops); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (tc->inspad_cnt != 0) { 15268c2ecf20Sopenharmony_ci for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { 15278c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "spad%d", sidx); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci debugfs_create_file(buf, 0600, tc->dbgfs_dir, 15308c2ecf20Sopenharmony_ci &tc->inspads[sidx], &tool_spad_fops); 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci if (tc->inmsg_cnt != 0) { 15358c2ecf20Sopenharmony_ci for (midx = 0; midx < tc->inmsg_cnt; midx++) { 15368c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "msg%d", midx); 15378c2ecf20Sopenharmony_ci debugfs_create_file(buf, 0600, tc->dbgfs_dir, 15388c2ecf20Sopenharmony_ci &tc->inmsgs[midx], &tool_inmsg_fops); 15398c2ecf20Sopenharmony_ci } 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci debugfs_create_file("msg_sts", 0600, tc->dbgfs_dir, 15428c2ecf20Sopenharmony_ci tc, &tool_msg_sts_fops); 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci debugfs_create_file("msg_inbits", 0600, tc->dbgfs_dir, 15458c2ecf20Sopenharmony_ci tc, &tool_msg_inbits_fops); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci debugfs_create_file("msg_outbits", 0600, tc->dbgfs_dir, 15488c2ecf20Sopenharmony_ci tc, &tool_msg_outbits_fops); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci debugfs_create_file("msg_mask", 0600, tc->dbgfs_dir, 15518c2ecf20Sopenharmony_ci tc, &tool_msg_mask_fops); 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci debugfs_create_file("msg_event", 0600, tc->dbgfs_dir, 15548c2ecf20Sopenharmony_ci tc, &tool_msg_event_fops); 15558c2ecf20Sopenharmony_ci } 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci for (pidx = 0; pidx < tc->peer_cnt; pidx++) { 15588c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "peer%d", pidx); 15598c2ecf20Sopenharmony_ci tc->peers[pidx].dbgfs_dir = 15608c2ecf20Sopenharmony_ci debugfs_create_dir(buf, tc->dbgfs_dir); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci debugfs_create_file("port", 0600, 15638c2ecf20Sopenharmony_ci tc->peers[pidx].dbgfs_dir, 15648c2ecf20Sopenharmony_ci &tc->peers[pidx], &tool_peer_port_fops); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci debugfs_create_file("link", 0200, 15678c2ecf20Sopenharmony_ci tc->peers[pidx].dbgfs_dir, 15688c2ecf20Sopenharmony_ci &tc->peers[pidx], &tool_peer_link_fops); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci debugfs_create_file("link_event", 0200, 15718c2ecf20Sopenharmony_ci tc->peers[pidx].dbgfs_dir, 15728c2ecf20Sopenharmony_ci &tc->peers[pidx], &tool_peer_link_event_fops); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { 15758c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "mw_trans%d", widx); 15768c2ecf20Sopenharmony_ci debugfs_create_file(buf, 0600, 15778c2ecf20Sopenharmony_ci tc->peers[pidx].dbgfs_dir, 15788c2ecf20Sopenharmony_ci &tc->peers[pidx].inmws[widx], 15798c2ecf20Sopenharmony_ci &tool_mw_trans_fops); 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) { 15838c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "peer_mw_trans%d", widx); 15848c2ecf20Sopenharmony_ci debugfs_create_file(buf, 0600, 15858c2ecf20Sopenharmony_ci tc->peers[pidx].dbgfs_dir, 15868c2ecf20Sopenharmony_ci &tc->peers[pidx].outmws[widx], 15878c2ecf20Sopenharmony_ci &tool_peer_mw_trans_fops); 15888c2ecf20Sopenharmony_ci } 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { 15918c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "spad%d", sidx); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci debugfs_create_file(buf, 0600, 15948c2ecf20Sopenharmony_ci tc->peers[pidx].dbgfs_dir, 15958c2ecf20Sopenharmony_ci &tc->peers[pidx].outspads[sidx], 15968c2ecf20Sopenharmony_ci &tool_peer_spad_fops); 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) { 16008c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "msg%d", midx); 16018c2ecf20Sopenharmony_ci debugfs_create_file(buf, 0600, 16028c2ecf20Sopenharmony_ci tc->peers[pidx].dbgfs_dir, 16038c2ecf20Sopenharmony_ci &tc->peers[pidx].outmsgs[midx], 16048c2ecf20Sopenharmony_ci &tool_outmsg_fops); 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci} 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_cistatic void tool_clear_dbgfs(struct tool_ctx *tc) 16108c2ecf20Sopenharmony_ci{ 16118c2ecf20Sopenharmony_ci debugfs_remove_recursive(tc->dbgfs_dir); 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci struct tool_ctx *tc; 16178c2ecf20Sopenharmony_ci int ret; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci tc = tool_create_data(ntb); 16208c2ecf20Sopenharmony_ci if (IS_ERR(tc)) 16218c2ecf20Sopenharmony_ci return PTR_ERR(tc); 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci ret = tool_init_peers(tc); 16248c2ecf20Sopenharmony_ci if (ret != 0) 16258c2ecf20Sopenharmony_ci goto err_clear_data; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci ret = tool_init_mws(tc); 16288c2ecf20Sopenharmony_ci if (ret != 0) 16298c2ecf20Sopenharmony_ci goto err_clear_data; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci ret = tool_init_spads(tc); 16328c2ecf20Sopenharmony_ci if (ret != 0) 16338c2ecf20Sopenharmony_ci goto err_clear_mws; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci ret = tool_init_msgs(tc); 16368c2ecf20Sopenharmony_ci if (ret != 0) 16378c2ecf20Sopenharmony_ci goto err_clear_mws; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci ret = tool_init_ntb(tc); 16408c2ecf20Sopenharmony_ci if (ret != 0) 16418c2ecf20Sopenharmony_ci goto err_clear_mws; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci tool_setup_dbgfs(tc); 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci return 0; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_cierr_clear_mws: 16488c2ecf20Sopenharmony_ci tool_clear_mws(tc); 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_cierr_clear_data: 16518c2ecf20Sopenharmony_ci tool_clear_data(tc); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci return ret; 16548c2ecf20Sopenharmony_ci} 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_cistatic void tool_remove(struct ntb_client *self, struct ntb_dev *ntb) 16578c2ecf20Sopenharmony_ci{ 16588c2ecf20Sopenharmony_ci struct tool_ctx *tc = ntb->ctx; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci tool_clear_dbgfs(tc); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci tool_clear_ntb(tc); 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci tool_clear_mws(tc); 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci tool_clear_data(tc); 16678c2ecf20Sopenharmony_ci} 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_cistatic struct ntb_client tool_client = { 16708c2ecf20Sopenharmony_ci .ops = { 16718c2ecf20Sopenharmony_ci .probe = tool_probe, 16728c2ecf20Sopenharmony_ci .remove = tool_remove, 16738c2ecf20Sopenharmony_ci } 16748c2ecf20Sopenharmony_ci}; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_cistatic int __init tool_init(void) 16778c2ecf20Sopenharmony_ci{ 16788c2ecf20Sopenharmony_ci int ret; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci if (debugfs_initialized()) 16818c2ecf20Sopenharmony_ci tool_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci ret = ntb_register_client(&tool_client); 16848c2ecf20Sopenharmony_ci if (ret) 16858c2ecf20Sopenharmony_ci debugfs_remove_recursive(tool_dbgfs_topdir); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci return ret; 16888c2ecf20Sopenharmony_ci} 16898c2ecf20Sopenharmony_cimodule_init(tool_init); 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_cistatic void __exit tool_exit(void) 16928c2ecf20Sopenharmony_ci{ 16938c2ecf20Sopenharmony_ci ntb_unregister_client(&tool_client); 16948c2ecf20Sopenharmony_ci debugfs_remove_recursive(tool_dbgfs_topdir); 16958c2ecf20Sopenharmony_ci} 16968c2ecf20Sopenharmony_cimodule_exit(tool_exit); 1697