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 65 #include <linux/ntb.h> 66 67 #define DRIVER_NAME "ntb_pingpong" 68 #define DRIVER_DESCRIPTION "PCIe NTB Simple Pingpong Client" 69 70 #define DRIVER_LICENSE "Dual BSD/GPL" 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(DRIVER_LICENSE); 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(delay_ms, "Initial doorbell bits to ring on the peer"); 91 92 struct pp_ctx { 93 struct ntb_dev *ntb; 94 u64 db_bits; 95 /* synchronize access to db_bits by ping and pong */ 96 spinlock_t db_lock; 97 struct timer_list db_timer; 98 unsigned long db_delay; 99 }; 100 101 static void pp_ping(unsigned long ctx) 102 { 103 struct pp_ctx *pp = (void *)ctx; 104 unsigned long irqflags; 105 u64 db_bits, db_mask; 106 u32 spad_rd, spad_wr; 107 108 spin_lock_irqsave(&pp->db_lock, irqflags); 109 { 110 db_mask = ntb_db_valid_mask(pp->ntb); 111 db_bits = ntb_db_read(pp->ntb); 112 113 if (db_bits) { 114 dev_dbg(&pp->ntb->dev, 115 "Masked pongs %#llx\n", 116 db_bits); 117 ntb_db_clear(pp->ntb, db_bits); 118 } 119 120 db_bits = ((pp->db_bits | db_bits) << 1) & db_mask; 121 122 if (!db_bits) 123 db_bits = db_init; 124 125 spad_rd = ntb_spad_read(pp->ntb, 0); 126 spad_wr = spad_rd + 1; 127 128 dev_dbg(&pp->ntb->dev, 129 "Ping bits %#llx read %#x write %#x\n", 130 db_bits, spad_rd, spad_wr); 131 132 ntb_peer_spad_write(pp->ntb, 0, spad_wr); 133 ntb_peer_db_set(pp->ntb, db_bits); 134 ntb_db_clear_mask(pp->ntb, db_mask); 135 136 pp->db_bits = 0; 137 } 138 spin_unlock_irqrestore(&pp->db_lock, irqflags); 139 } 140 141 static void pp_link_event(void *ctx) 142 { 143 struct pp_ctx *pp = ctx; 144 145 if (ntb_link_is_up(pp->ntb, NULL, NULL) == 1) { 146 dev_dbg(&pp->ntb->dev, "link is up\n"); 147 pp_ping((unsigned long)pp); 148 } else { 149 dev_dbg(&pp->ntb->dev, "link is down\n"); 150 del_timer(&pp->db_timer); 151 } 152 } 153 154 static void pp_db_event(void *ctx, int vec) 155 { 156 struct pp_ctx *pp = ctx; 157 u64 db_bits, db_mask; 158 unsigned long irqflags; 159 160 spin_lock_irqsave(&pp->db_lock, irqflags); 161 { 162 db_mask = ntb_db_vector_mask(pp->ntb, vec); 163 db_bits = db_mask & ntb_db_read(pp->ntb); 164 ntb_db_set_mask(pp->ntb, db_mask); 165 ntb_db_clear(pp->ntb, db_bits); 166 167 pp->db_bits |= db_bits; 168 169 mod_timer(&pp->db_timer, jiffies + pp->db_delay); 170 171 dev_dbg(&pp->ntb->dev, 172 "Pong vec %d bits %#llx\n", 173 vec, db_bits); 174 } 175 spin_unlock_irqrestore(&pp->db_lock, irqflags); 176 } 177 178 static const struct ntb_ctx_ops pp_ops = { 179 .link_event = pp_link_event, 180 .db_event = pp_db_event, 181 }; 182 183 static int pp_probe(struct ntb_client *client, 184 struct ntb_dev *ntb) 185 { 186 struct pp_ctx *pp; 187 int rc; 188 189 if (ntb_db_is_unsafe(ntb)) { 190 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 191 if (!unsafe) { 192 rc = -EINVAL; 193 goto err_pp; 194 } 195 } 196 197 if (ntb_spad_is_unsafe(ntb)) { 198 dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 199 if (!unsafe) { 200 rc = -EINVAL; 201 goto err_pp; 202 } 203 } 204 205 pp = kmalloc(sizeof(*pp), GFP_KERNEL); 206 if (!pp) { 207 rc = -ENOMEM; 208 goto err_pp; 209 } 210 211 pp->ntb = ntb; 212 pp->db_bits = 0; 213 spin_lock_init(&pp->db_lock); 214 setup_timer(&pp->db_timer, pp_ping, (unsigned long)pp); 215 pp->db_delay = msecs_to_jiffies(delay_ms); 216 217 rc = ntb_set_ctx(ntb, pp, &pp_ops); 218 if (rc) 219 goto err_ctx; 220 221 ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 222 ntb_link_event(ntb); 223 224 return 0; 225 226 err_ctx: 227 kfree(pp); 228 err_pp: 229 return rc; 230 } 231 232 static void pp_remove(struct ntb_client *client, 233 struct ntb_dev *ntb) 234 { 235 struct pp_ctx *pp = ntb->ctx; 236 237 ntb_clear_ctx(ntb); 238 del_timer_sync(&pp->db_timer); 239 ntb_link_disable(ntb); 240 241 kfree(pp); 242 } 243 244 static struct ntb_client pp_client = { 245 .ops = { 246 .probe = pp_probe, 247 .remove = pp_remove, 248 }, 249 }; 250 module_ntb_client(pp_client); 251