Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.10-rc5 251 lines 6.5 kB view raw
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 Linux driver 49 * 50 * Contact Information: 51 * Allen Hubbe <Allen.Hubbe@emc.com> 52 */ 53 54#include <linux/device.h> 55#include <linux/kernel.h> 56#include <linux/module.h> 57 58#include <linux/ntb.h> 59#include <linux/pci.h> 60 61#define DRIVER_NAME "ntb" 62#define DRIVER_DESCRIPTION "PCIe NTB Driver Framework" 63 64#define DRIVER_LICENSE "Dual BSD/GPL" 65#define DRIVER_VERSION "1.0" 66#define DRIVER_RELDATE "24 March 2015" 67#define DRIVER_AUTHOR "Allen Hubbe <Allen.Hubbe@emc.com>" 68 69MODULE_LICENSE(DRIVER_LICENSE); 70MODULE_VERSION(DRIVER_VERSION); 71MODULE_AUTHOR(DRIVER_AUTHOR); 72MODULE_DESCRIPTION(DRIVER_DESCRIPTION); 73 74static struct bus_type ntb_bus; 75static void ntb_dev_release(struct device *dev); 76 77int __ntb_register_client(struct ntb_client *client, struct module *mod, 78 const char *mod_name) 79{ 80 if (!client) 81 return -EINVAL; 82 if (!ntb_client_ops_is_valid(&client->ops)) 83 return -EINVAL; 84 85 memset(&client->drv, 0, sizeof(client->drv)); 86 client->drv.bus = &ntb_bus; 87 client->drv.name = mod_name; 88 client->drv.owner = mod; 89 90 return driver_register(&client->drv); 91} 92EXPORT_SYMBOL(__ntb_register_client); 93 94void ntb_unregister_client(struct ntb_client *client) 95{ 96 driver_unregister(&client->drv); 97} 98EXPORT_SYMBOL(ntb_unregister_client); 99 100int ntb_register_device(struct ntb_dev *ntb) 101{ 102 if (!ntb) 103 return -EINVAL; 104 if (!ntb->pdev) 105 return -EINVAL; 106 if (!ntb->ops) 107 return -EINVAL; 108 if (!ntb_dev_ops_is_valid(ntb->ops)) 109 return -EINVAL; 110 111 init_completion(&ntb->released); 112 113 memset(&ntb->dev, 0, sizeof(ntb->dev)); 114 ntb->dev.bus = &ntb_bus; 115 ntb->dev.parent = &ntb->pdev->dev; 116 ntb->dev.release = ntb_dev_release; 117 dev_set_name(&ntb->dev, "%s", pci_name(ntb->pdev)); 118 119 ntb->ctx = NULL; 120 ntb->ctx_ops = NULL; 121 spin_lock_init(&ntb->ctx_lock); 122 123 return device_register(&ntb->dev); 124} 125EXPORT_SYMBOL(ntb_register_device); 126 127void ntb_unregister_device(struct ntb_dev *ntb) 128{ 129 device_unregister(&ntb->dev); 130 wait_for_completion(&ntb->released); 131} 132EXPORT_SYMBOL(ntb_unregister_device); 133 134int ntb_set_ctx(struct ntb_dev *ntb, void *ctx, 135 const struct ntb_ctx_ops *ctx_ops) 136{ 137 unsigned long irqflags; 138 139 if (!ntb_ctx_ops_is_valid(ctx_ops)) 140 return -EINVAL; 141 if (ntb->ctx_ops) 142 return -EINVAL; 143 144 spin_lock_irqsave(&ntb->ctx_lock, irqflags); 145 { 146 ntb->ctx = ctx; 147 ntb->ctx_ops = ctx_ops; 148 } 149 spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); 150 151 return 0; 152} 153EXPORT_SYMBOL(ntb_set_ctx); 154 155void ntb_clear_ctx(struct ntb_dev *ntb) 156{ 157 unsigned long irqflags; 158 159 spin_lock_irqsave(&ntb->ctx_lock, irqflags); 160 { 161 ntb->ctx_ops = NULL; 162 ntb->ctx = NULL; 163 } 164 spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); 165} 166EXPORT_SYMBOL(ntb_clear_ctx); 167 168void ntb_link_event(struct ntb_dev *ntb) 169{ 170 unsigned long irqflags; 171 172 spin_lock_irqsave(&ntb->ctx_lock, irqflags); 173 { 174 if (ntb->ctx_ops && ntb->ctx_ops->link_event) 175 ntb->ctx_ops->link_event(ntb->ctx); 176 } 177 spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); 178} 179EXPORT_SYMBOL(ntb_link_event); 180 181void ntb_db_event(struct ntb_dev *ntb, int vector) 182{ 183 unsigned long irqflags; 184 185 spin_lock_irqsave(&ntb->ctx_lock, irqflags); 186 { 187 if (ntb->ctx_ops && ntb->ctx_ops->db_event) 188 ntb->ctx_ops->db_event(ntb->ctx, vector); 189 } 190 spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); 191} 192EXPORT_SYMBOL(ntb_db_event); 193 194static int ntb_probe(struct device *dev) 195{ 196 struct ntb_dev *ntb; 197 struct ntb_client *client; 198 int rc; 199 200 get_device(dev); 201 ntb = dev_ntb(dev); 202 client = drv_ntb_client(dev->driver); 203 204 rc = client->ops.probe(client, ntb); 205 if (rc) 206 put_device(dev); 207 208 return rc; 209} 210 211static int ntb_remove(struct device *dev) 212{ 213 struct ntb_dev *ntb; 214 struct ntb_client *client; 215 216 if (dev->driver) { 217 ntb = dev_ntb(dev); 218 client = drv_ntb_client(dev->driver); 219 220 client->ops.remove(client, ntb); 221 put_device(dev); 222 } 223 224 return 0; 225} 226 227static void ntb_dev_release(struct device *dev) 228{ 229 struct ntb_dev *ntb = dev_ntb(dev); 230 231 complete(&ntb->released); 232} 233 234static struct bus_type ntb_bus = { 235 .name = "ntb", 236 .probe = ntb_probe, 237 .remove = ntb_remove, 238}; 239 240static int __init ntb_driver_init(void) 241{ 242 return bus_register(&ntb_bus); 243} 244module_init(ntb_driver_init); 245 246static void __exit ntb_driver_exit(void) 247{ 248 bus_unregister(&ntb_bus); 249} 250module_exit(ntb_driver_exit); 251