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 struct pp_ctx { 94 struct ntb_dev *ntb; 95 u64 db_bits; 96 /* synchronize access to db_bits by ping and pong */ 97 spinlock_t db_lock; 98 struct timer_list db_timer; 99 unsigned long db_delay; 100 struct dentry *debugfs_node_dir; 101 struct dentry *debugfs_count; 102 atomic_t count; 103 }; 104 105 static struct dentry *pp_debugfs_dir; 106 107 static void pp_ping(unsigned long ctx) 108 { 109 struct pp_ctx *pp = (void *)ctx; 110 unsigned long irqflags; 111 u64 db_bits, db_mask; 112 u32 spad_rd, spad_wr; 113 114 spin_lock_irqsave(&pp->db_lock, irqflags); 115 { 116 db_mask = ntb_db_valid_mask(pp->ntb); 117 db_bits = ntb_db_read(pp->ntb); 118 119 if (db_bits) { 120 dev_dbg(&pp->ntb->dev, 121 "Masked pongs %#llx\n", 122 db_bits); 123 ntb_db_clear(pp->ntb, db_bits); 124 } 125 126 db_bits = ((pp->db_bits | db_bits) << 1) & db_mask; 127 128 if (!db_bits) 129 db_bits = db_init; 130 131 spad_rd = ntb_spad_read(pp->ntb, 0); 132 spad_wr = spad_rd + 1; 133 134 dev_dbg(&pp->ntb->dev, 135 "Ping bits %#llx read %#x write %#x\n", 136 db_bits, spad_rd, spad_wr); 137 138 ntb_peer_spad_write(pp->ntb, 0, spad_wr); 139 ntb_peer_db_set(pp->ntb, db_bits); 140 ntb_db_clear_mask(pp->ntb, db_mask); 141 142 pp->db_bits = 0; 143 } 144 spin_unlock_irqrestore(&pp->db_lock, irqflags); 145 } 146 147 static void pp_link_event(void *ctx) 148 { 149 struct pp_ctx *pp = ctx; 150 151 if (ntb_link_is_up(pp->ntb, NULL, NULL) == 1) { 152 dev_dbg(&pp->ntb->dev, "link is up\n"); 153 pp_ping((unsigned long)pp); 154 } else { 155 dev_dbg(&pp->ntb->dev, "link is down\n"); 156 del_timer(&pp->db_timer); 157 } 158 } 159 160 static void pp_db_event(void *ctx, int vec) 161 { 162 struct pp_ctx *pp = ctx; 163 u64 db_bits, db_mask; 164 unsigned long irqflags; 165 166 spin_lock_irqsave(&pp->db_lock, irqflags); 167 { 168 db_mask = ntb_db_vector_mask(pp->ntb, vec); 169 db_bits = db_mask & ntb_db_read(pp->ntb); 170 ntb_db_set_mask(pp->ntb, db_mask); 171 ntb_db_clear(pp->ntb, db_bits); 172 173 pp->db_bits |= db_bits; 174 175 mod_timer(&pp->db_timer, jiffies + pp->db_delay); 176 177 dev_dbg(&pp->ntb->dev, 178 "Pong vec %d bits %#llx\n", 179 vec, db_bits); 180 atomic_inc(&pp->count); 181 } 182 spin_unlock_irqrestore(&pp->db_lock, irqflags); 183 } 184 185 static int pp_debugfs_setup(struct pp_ctx *pp) 186 { 187 struct pci_dev *pdev = pp->ntb->pdev; 188 189 if (!pp_debugfs_dir) 190 return -ENODEV; 191 192 pp->debugfs_node_dir = debugfs_create_dir(pci_name(pdev), 193 pp_debugfs_dir); 194 if (!pp->debugfs_node_dir) 195 return -ENODEV; 196 197 pp->debugfs_count = debugfs_create_atomic_t("count", S_IRUSR | S_IWUSR, 198 pp->debugfs_node_dir, 199 &pp->count); 200 if (!pp->debugfs_count) 201 return -ENODEV; 202 203 return 0; 204 } 205 206 static const struct ntb_ctx_ops pp_ops = { 207 .link_event = pp_link_event, 208 .db_event = pp_db_event, 209 }; 210 211 static int pp_probe(struct ntb_client *client, 212 struct ntb_dev *ntb) 213 { 214 struct pp_ctx *pp; 215 int rc; 216 217 if (ntb_db_is_unsafe(ntb)) { 218 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 219 if (!unsafe) { 220 rc = -EINVAL; 221 goto err_pp; 222 } 223 } 224 225 if (ntb_spad_is_unsafe(ntb)) { 226 dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 227 if (!unsafe) { 228 rc = -EINVAL; 229 goto err_pp; 230 } 231 } 232 233 pp = kmalloc(sizeof(*pp), GFP_KERNEL); 234 if (!pp) { 235 rc = -ENOMEM; 236 goto err_pp; 237 } 238 239 pp->ntb = ntb; 240 pp->db_bits = 0; 241 atomic_set(&pp->count, 0); 242 spin_lock_init(&pp->db_lock); 243 setup_timer(&pp->db_timer, pp_ping, (unsigned long)pp); 244 pp->db_delay = msecs_to_jiffies(delay_ms); 245 246 rc = ntb_set_ctx(ntb, pp, &pp_ops); 247 if (rc) 248 goto err_ctx; 249 250 rc = pp_debugfs_setup(pp); 251 if (rc) 252 goto err_ctx; 253 254 ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 255 ntb_link_event(ntb); 256 257 return 0; 258 259 err_ctx: 260 kfree(pp); 261 err_pp: 262 return rc; 263 } 264 265 static void pp_remove(struct ntb_client *client, 266 struct ntb_dev *ntb) 267 { 268 struct pp_ctx *pp = ntb->ctx; 269 270 debugfs_remove_recursive(pp->debugfs_node_dir); 271 272 ntb_clear_ctx(ntb); 273 del_timer_sync(&pp->db_timer); 274 ntb_link_disable(ntb); 275 276 kfree(pp); 277 } 278 279 static struct ntb_client pp_client = { 280 .ops = { 281 .probe = pp_probe, 282 .remove = pp_remove, 283 }, 284 }; 285 286 static int __init pp_init(void) 287 { 288 int rc; 289 290 if (debugfs_initialized()) 291 pp_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); 292 293 rc = ntb_register_client(&pp_client); 294 if (rc) 295 goto err_client; 296 297 return 0; 298 299 err_client: 300 debugfs_remove_recursive(pp_debugfs_dir); 301 return rc; 302 } 303 module_init(pp_init); 304 305 static void __exit pp_exit(void) 306 { 307 ntb_unregister_client(&pp_client); 308 debugfs_remove_recursive(pp_debugfs_dir); 309 } 310 module_exit(pp_exit); 311