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_VERSION "1.0" 72 #define DRIVER_RELDATE "24 March 2015" 73 #define DRIVER_AUTHOR "Allen Hubbe <Allen.Hubbe@emc.com>" 74 75 MODULE_LICENSE("Dual BSD/GPL"); 76 MODULE_VERSION(DRIVER_VERSION); 77 MODULE_AUTHOR(DRIVER_AUTHOR); 78 MODULE_DESCRIPTION(DRIVER_DESCRIPTION); 79 80 static unsigned int unsafe; 81 module_param(unsafe, uint, 0644); 82 MODULE_PARM_DESC(unsafe, "Run even though ntb operations may be unsafe"); 83 84 static unsigned int delay_ms = 1000; 85 module_param(delay_ms, uint, 0644); 86 MODULE_PARM_DESC(delay_ms, "Milliseconds to delay the response to peer"); 87 88 static unsigned long db_init = 0x7; 89 module_param(db_init, ulong, 0644); 90 MODULE_PARM_DESC(db_init, "Initial doorbell bits to ring on the peer"); 91 92 /* Only two-ports NTB devices are supported */ 93 #define PIDX NTB_DEF_PEER_IDX 94 95 struct pp_ctx { 96 struct ntb_dev *ntb; 97 u64 db_bits; 98 /* synchronize access to db_bits by ping and pong */ 99 spinlock_t db_lock; 100 struct timer_list db_timer; 101 unsigned long db_delay; 102 struct dentry *debugfs_node_dir; 103 struct dentry *debugfs_count; 104 atomic_t count; 105 }; 106 107 static struct dentry *pp_debugfs_dir; 108 109 static void pp_ping(struct timer_list *t) 110 { 111 struct pp_ctx *pp = from_timer(pp, t, db_timer); 112 unsigned long irqflags; 113 u64 db_bits, db_mask; 114 u32 spad_rd, spad_wr; 115 116 spin_lock_irqsave(&pp->db_lock, irqflags); 117 { 118 db_mask = ntb_db_valid_mask(pp->ntb); 119 db_bits = ntb_db_read(pp->ntb); 120 121 if (db_bits) { 122 dev_dbg(&pp->ntb->dev, 123 "Masked pongs %#llx\n", 124 db_bits); 125 ntb_db_clear(pp->ntb, db_bits); 126 } 127 128 db_bits = ((pp->db_bits | db_bits) << 1) & db_mask; 129 130 if (!db_bits) 131 db_bits = db_init; 132 133 spad_rd = ntb_spad_read(pp->ntb, 0); 134 spad_wr = spad_rd + 1; 135 136 dev_dbg(&pp->ntb->dev, 137 "Ping bits %#llx read %#x write %#x\n", 138 db_bits, spad_rd, spad_wr); 139 140 ntb_peer_spad_write(pp->ntb, PIDX, 0, spad_wr); 141 ntb_peer_db_set(pp->ntb, db_bits); 142 ntb_db_clear_mask(pp->ntb, db_mask); 143 144 pp->db_bits = 0; 145 } 146 spin_unlock_irqrestore(&pp->db_lock, irqflags); 147 } 148 149 static void pp_link_event(void *ctx) 150 { 151 struct pp_ctx *pp = ctx; 152 153 if (ntb_link_is_up(pp->ntb, NULL, NULL) == 1) { 154 dev_dbg(&pp->ntb->dev, "link is up\n"); 155 pp_ping(&pp->db_timer); 156 } else { 157 dev_dbg(&pp->ntb->dev, "link is down\n"); 158 del_timer(&pp->db_timer); 159 } 160 } 161 162 static void pp_db_event(void *ctx, int vec) 163 { 164 struct pp_ctx *pp = ctx; 165 u64 db_bits, db_mask; 166 unsigned long irqflags; 167 168 spin_lock_irqsave(&pp->db_lock, irqflags); 169 { 170 db_mask = ntb_db_vector_mask(pp->ntb, vec); 171 db_bits = db_mask & ntb_db_read(pp->ntb); 172 ntb_db_set_mask(pp->ntb, db_mask); 173 ntb_db_clear(pp->ntb, db_bits); 174 175 pp->db_bits |= db_bits; 176 177 mod_timer(&pp->db_timer, jiffies + pp->db_delay); 178 179 dev_dbg(&pp->ntb->dev, 180 "Pong vec %d bits %#llx\n", 181 vec, db_bits); 182 atomic_inc(&pp->count); 183 } 184 spin_unlock_irqrestore(&pp->db_lock, irqflags); 185 } 186 187 static int pp_debugfs_setup(struct pp_ctx *pp) 188 { 189 struct pci_dev *pdev = pp->ntb->pdev; 190 191 if (!pp_debugfs_dir) 192 return -ENODEV; 193 194 pp->debugfs_node_dir = debugfs_create_dir(pci_name(pdev), 195 pp_debugfs_dir); 196 if (!pp->debugfs_node_dir) 197 return -ENODEV; 198 199 pp->debugfs_count = debugfs_create_atomic_t("count", S_IRUSR | S_IWUSR, 200 pp->debugfs_node_dir, 201 &pp->count); 202 if (!pp->debugfs_count) 203 return -ENODEV; 204 205 return 0; 206 } 207 208 static const struct ntb_ctx_ops pp_ops = { 209 .link_event = pp_link_event, 210 .db_event = pp_db_event, 211 }; 212 213 static int pp_probe(struct ntb_client *client, 214 struct ntb_dev *ntb) 215 { 216 struct pp_ctx *pp; 217 int rc; 218 219 if (ntb_db_is_unsafe(ntb)) { 220 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 221 if (!unsafe) { 222 rc = -EINVAL; 223 goto err_pp; 224 } 225 } 226 227 if (ntb_spad_count(ntb) < 1) { 228 dev_dbg(&ntb->dev, "no enough scratchpads\n"); 229 rc = -EINVAL; 230 goto err_pp; 231 } 232 233 if (ntb_spad_is_unsafe(ntb)) { 234 dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 235 if (!unsafe) { 236 rc = -EINVAL; 237 goto err_pp; 238 } 239 } 240 241 if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT) 242 dev_warn(&ntb->dev, "multi-port NTB is unsupported\n"); 243 244 pp = kmalloc(sizeof(*pp), GFP_KERNEL); 245 if (!pp) { 246 rc = -ENOMEM; 247 goto err_pp; 248 } 249 250 pp->ntb = ntb; 251 pp->db_bits = 0; 252 atomic_set(&pp->count, 0); 253 spin_lock_init(&pp->db_lock); 254 timer_setup(&pp->db_timer, pp_ping, 0); 255 pp->db_delay = msecs_to_jiffies(delay_ms); 256 257 rc = ntb_set_ctx(ntb, pp, &pp_ops); 258 if (rc) 259 goto err_ctx; 260 261 rc = pp_debugfs_setup(pp); 262 if (rc) 263 goto err_ctx; 264 265 ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 266 ntb_link_event(ntb); 267 268 return 0; 269 270 err_ctx: 271 kfree(pp); 272 err_pp: 273 return rc; 274 } 275 276 static void pp_remove(struct ntb_client *client, 277 struct ntb_dev *ntb) 278 { 279 struct pp_ctx *pp = ntb->ctx; 280 281 debugfs_remove_recursive(pp->debugfs_node_dir); 282 283 ntb_clear_ctx(ntb); 284 del_timer_sync(&pp->db_timer); 285 ntb_link_disable(ntb); 286 287 kfree(pp); 288 } 289 290 static struct ntb_client pp_client = { 291 .ops = { 292 .probe = pp_probe, 293 .remove = pp_remove, 294 }, 295 }; 296 297 static int __init pp_init(void) 298 { 299 int rc; 300 301 if (debugfs_initialized()) 302 pp_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); 303 304 rc = ntb_register_client(&pp_client); 305 if (rc) 306 goto err_client; 307 308 return 0; 309 310 err_client: 311 debugfs_remove_recursive(pp_debugfs_dir); 312 return rc; 313 } 314 module_init(pp_init); 315 316 static void __exit pp_exit(void) 317 { 318 ntb_unregister_client(&pp_client); 319 debugfs_remove_recursive(pp_debugfs_dir); 320 } 321 module_exit(pp_exit); 322