1 /* 2 * This file is provided under a dual BSD/GPLv2 license. When using or 3 * redistributing this file, you may do so under either license. 4 * 5 * GPL LICENSE SUMMARY 6 * 7 * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of version 2 of the GNU General Public License as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * BSD LICENSE 19 * 20 * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 26 * * Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * * Redistributions in binary form must reproduce the above copy 29 * notice, this list of conditions and the following disclaimer in 30 * the documentation and/or other materials provided with the 31 * distribution. 32 * * Neither the name of Intel Corporation nor the names of its 33 * contributors may be used to endorse or promote products derived 34 * from this software without specific prior written permission. 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 37 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 38 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 39 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 40 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 43 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 44 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 45 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 46 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 47 * 48 * PCIe NTB Pingpong Linux driver 49 * 50 * Contact Information: 51 * Allen Hubbe <Allen.Hubbe@emc.com> 52 */ 53 54 /* Note: load this module with option 'dyndbg=+p' */ 55 56 #include <linux/init.h> 57 #include <linux/kernel.h> 58 #include <linux/module.h> 59 60 #include <linux/dma-mapping.h> 61 #include <linux/pci.h> 62 #include <linux/slab.h> 63 #include <linux/spinlock.h> 64 #include <linux/debugfs.h> 65 66 #include <linux/ntb.h> 67 68 #define DRIVER_NAME "ntb_pingpong" 69 #define DRIVER_DESCRIPTION "PCIe NTB Simple Pingpong Client" 70 71 #define DRIVER_LICENSE "Dual BSD/GPL" 72 #define DRIVER_VERSION "1.0" 73 #define DRIVER_RELDATE "24 March 2015" 74 #define DRIVER_AUTHOR "Allen Hubbe <Allen.Hubbe@emc.com>" 75 76 MODULE_LICENSE(DRIVER_LICENSE); 77 MODULE_VERSION(DRIVER_VERSION); 78 MODULE_AUTHOR(DRIVER_AUTHOR); 79 MODULE_DESCRIPTION(DRIVER_DESCRIPTION); 80 81 static unsigned int unsafe; 82 module_param(unsafe, uint, 0644); 83 MODULE_PARM_DESC(unsafe, "Run even though ntb operations may be unsafe"); 84 85 static unsigned int delay_ms = 1000; 86 module_param(delay_ms, uint, 0644); 87 MODULE_PARM_DESC(delay_ms, "Milliseconds to delay the response to peer"); 88 89 static unsigned long db_init = 0x7; 90 module_param(db_init, ulong, 0644); 91 MODULE_PARM_DESC(db_init, "Initial doorbell bits to ring on the peer"); 92 93 /* Only two-ports NTB devices are supported */ 94 #define PIDX NTB_DEF_PEER_IDX 95 96 struct pp_ctx { 97 struct ntb_dev *ntb; 98 u64 db_bits; 99 /* synchronize access to db_bits by ping and pong */ 100 spinlock_t db_lock; 101 struct timer_list db_timer; 102 unsigned long db_delay; 103 struct dentry *debugfs_node_dir; 104 struct dentry *debugfs_count; 105 atomic_t count; 106 }; 107 108 static struct dentry *pp_debugfs_dir; 109 110 static void pp_ping(unsigned long ctx) 111 { 112 struct pp_ctx *pp = (void *)ctx; 113 unsigned long irqflags; 114 u64 db_bits, db_mask; 115 u32 spad_rd, spad_wr; 116 117 spin_lock_irqsave(&pp->db_lock, irqflags); 118 { 119 db_mask = ntb_db_valid_mask(pp->ntb); 120 db_bits = ntb_db_read(pp->ntb); 121 122 if (db_bits) { 123 dev_dbg(&pp->ntb->dev, 124 "Masked pongs %#llx\n", 125 db_bits); 126 ntb_db_clear(pp->ntb, db_bits); 127 } 128 129 db_bits = ((pp->db_bits | db_bits) << 1) & db_mask; 130 131 if (!db_bits) 132 db_bits = db_init; 133 134 spad_rd = ntb_spad_read(pp->ntb, 0); 135 spad_wr = spad_rd + 1; 136 137 dev_dbg(&pp->ntb->dev, 138 "Ping bits %#llx read %#x write %#x\n", 139 db_bits, spad_rd, spad_wr); 140 141 ntb_peer_spad_write(pp->ntb, PIDX, 0, spad_wr); 142 ntb_peer_db_set(pp->ntb, db_bits); 143 ntb_db_clear_mask(pp->ntb, db_mask); 144 145 pp->db_bits = 0; 146 } 147 spin_unlock_irqrestore(&pp->db_lock, irqflags); 148 } 149 150 static void pp_link_event(void *ctx) 151 { 152 struct pp_ctx *pp = ctx; 153 154 if (ntb_link_is_up(pp->ntb, NULL, NULL) == 1) { 155 dev_dbg(&pp->ntb->dev, "link is up\n"); 156 pp_ping((unsigned long)pp); 157 } else { 158 dev_dbg(&pp->ntb->dev, "link is down\n"); 159 del_timer(&pp->db_timer); 160 } 161 } 162 163 static void pp_db_event(void *ctx, int vec) 164 { 165 struct pp_ctx *pp = ctx; 166 u64 db_bits, db_mask; 167 unsigned long irqflags; 168 169 spin_lock_irqsave(&pp->db_lock, irqflags); 170 { 171 db_mask = ntb_db_vector_mask(pp->ntb, vec); 172 db_bits = db_mask & ntb_db_read(pp->ntb); 173 ntb_db_set_mask(pp->ntb, db_mask); 174 ntb_db_clear(pp->ntb, db_bits); 175 176 pp->db_bits |= db_bits; 177 178 mod_timer(&pp->db_timer, jiffies + pp->db_delay); 179 180 dev_dbg(&pp->ntb->dev, 181 "Pong vec %d bits %#llx\n", 182 vec, db_bits); 183 atomic_inc(&pp->count); 184 } 185 spin_unlock_irqrestore(&pp->db_lock, irqflags); 186 } 187 188 static int pp_debugfs_setup(struct pp_ctx *pp) 189 { 190 struct pci_dev *pdev = pp->ntb->pdev; 191 192 if (!pp_debugfs_dir) 193 return -ENODEV; 194 195 pp->debugfs_node_dir = debugfs_create_dir(pci_name(pdev), 196 pp_debugfs_dir); 197 if (!pp->debugfs_node_dir) 198 return -ENODEV; 199 200 pp->debugfs_count = debugfs_create_atomic_t("count", S_IRUSR | S_IWUSR, 201 pp->debugfs_node_dir, 202 &pp->count); 203 if (!pp->debugfs_count) 204 return -ENODEV; 205 206 return 0; 207 } 208 209 static const struct ntb_ctx_ops pp_ops = { 210 .link_event = pp_link_event, 211 .db_event = pp_db_event, 212 }; 213 214 static int pp_probe(struct ntb_client *client, 215 struct ntb_dev *ntb) 216 { 217 struct pp_ctx *pp; 218 int rc; 219 220 if (ntb_db_is_unsafe(ntb)) { 221 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 222 if (!unsafe) { 223 rc = -EINVAL; 224 goto err_pp; 225 } 226 } 227 228 if (ntb_spad_count(ntb) < 1) { 229 dev_dbg(&ntb->dev, "no enough scratchpads\n"); 230 rc = -EINVAL; 231 goto err_pp; 232 } 233 234 if (ntb_spad_is_unsafe(ntb)) { 235 dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 236 if (!unsafe) { 237 rc = -EINVAL; 238 goto err_pp; 239 } 240 } 241 242 if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT) 243 dev_warn(&ntb->dev, "multi-port NTB is unsupported\n"); 244 245 pp = kmalloc(sizeof(*pp), GFP_KERNEL); 246 if (!pp) { 247 rc = -ENOMEM; 248 goto err_pp; 249 } 250 251 pp->ntb = ntb; 252 pp->db_bits = 0; 253 atomic_set(&pp->count, 0); 254 spin_lock_init(&pp->db_lock); 255 setup_timer(&pp->db_timer, pp_ping, (unsigned long)pp); 256 pp->db_delay = msecs_to_jiffies(delay_ms); 257 258 rc = ntb_set_ctx(ntb, pp, &pp_ops); 259 if (rc) 260 goto err_ctx; 261 262 rc = pp_debugfs_setup(pp); 263 if (rc) 264 goto err_ctx; 265 266 ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 267 ntb_link_event(ntb); 268 269 return 0; 270 271 err_ctx: 272 kfree(pp); 273 err_pp: 274 return rc; 275 } 276 277 static void pp_remove(struct ntb_client *client, 278 struct ntb_dev *ntb) 279 { 280 struct pp_ctx *pp = ntb->ctx; 281 282 debugfs_remove_recursive(pp->debugfs_node_dir); 283 284 ntb_clear_ctx(ntb); 285 del_timer_sync(&pp->db_timer); 286 ntb_link_disable(ntb); 287 288 kfree(pp); 289 } 290 291 static struct ntb_client pp_client = { 292 .ops = { 293 .probe = pp_probe, 294 .remove = pp_remove, 295 }, 296 }; 297 298 static int __init pp_init(void) 299 { 300 int rc; 301 302 if (debugfs_initialized()) 303 pp_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); 304 305 rc = ntb_register_client(&pp_client); 306 if (rc) 307 goto err_client; 308 309 return 0; 310 311 err_client: 312 debugfs_remove_recursive(pp_debugfs_dir); 313 return rc; 314 } 315 module_init(pp_init); 316 317 static void __exit pp_exit(void) 318 { 319 ntb_unregister_client(&pp_client); 320 debugfs_remove_recursive(pp_debugfs_dir); 321 } 322 module_exit(pp_exit); 323