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 | * Copyright (C) 2016 T-Platforms. All Rights Reserved. |
9 | * |
10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as |
12 | * published by the Free Software Foundation. |
13 | * |
14 | * This program is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * General Public License for more details. |
18 | * |
19 | * BSD LICENSE |
20 | * |
21 | * Copyright (C) 2015 EMC Corporation. All Rights Reserved. |
22 | * Copyright (C) 2016 T-Platforms. All Rights Reserved. |
23 | * |
24 | * Redistribution and use in source and binary forms, with or without |
25 | * modification, are permitted provided that the following conditions |
26 | * are met: |
27 | * |
28 | * * Redistributions of source code must retain the above copyright |
29 | * notice, this list of conditions and the following disclaimer. |
30 | * * Redistributions in binary form must reproduce the above copy |
31 | * notice, this list of conditions and the following disclaimer in |
32 | * the documentation and/or other materials provided with the |
33 | * distribution. |
34 | * * Neither the name of Intel Corporation nor the names of its |
35 | * contributors may be used to endorse or promote products derived |
36 | * from this software without specific prior written permission. |
37 | * |
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
39 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
40 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
41 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
42 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
43 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
44 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
45 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
46 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
47 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
48 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
49 | * |
50 | * PCIe NTB Linux driver |
51 | * |
52 | * Contact Information: |
53 | * Allen Hubbe <Allen.Hubbe@emc.com> |
54 | */ |
55 | |
56 | #include <linux/device.h> |
57 | #include <linux/kernel.h> |
58 | #include <linux/module.h> |
59 | |
60 | #include <linux/ntb.h> |
61 | #include <linux/pci.h> |
62 | |
63 | #define DRIVER_NAME "ntb" |
64 | #define DRIVER_DESCRIPTION "PCIe NTB Driver Framework" |
65 | |
66 | #define DRIVER_VERSION "1.0" |
67 | #define DRIVER_RELDATE "24 March 2015" |
68 | #define DRIVER_AUTHOR "Allen Hubbe <Allen.Hubbe@emc.com>" |
69 | |
70 | MODULE_LICENSE("Dual BSD/GPL" ); |
71 | MODULE_VERSION(DRIVER_VERSION); |
72 | MODULE_AUTHOR(DRIVER_AUTHOR); |
73 | MODULE_DESCRIPTION(DRIVER_DESCRIPTION); |
74 | |
75 | static struct bus_type ntb_bus; |
76 | static void ntb_dev_release(struct device *dev); |
77 | |
78 | int __ntb_register_client(struct ntb_client *client, struct module *mod, |
79 | const char *mod_name) |
80 | { |
81 | if (!client) |
82 | return -EINVAL; |
83 | if (!ntb_client_ops_is_valid(ops: &client->ops)) |
84 | return -EINVAL; |
85 | |
86 | memset(&client->drv, 0, sizeof(client->drv)); |
87 | client->drv.bus = &ntb_bus; |
88 | client->drv.name = mod_name; |
89 | client->drv.owner = mod; |
90 | |
91 | return driver_register(drv: &client->drv); |
92 | } |
93 | EXPORT_SYMBOL(__ntb_register_client); |
94 | |
95 | void ntb_unregister_client(struct ntb_client *client) |
96 | { |
97 | driver_unregister(drv: &client->drv); |
98 | } |
99 | EXPORT_SYMBOL(ntb_unregister_client); |
100 | |
101 | int ntb_register_device(struct ntb_dev *ntb) |
102 | { |
103 | int ret; |
104 | |
105 | if (!ntb) |
106 | return -EINVAL; |
107 | if (!ntb->pdev) |
108 | return -EINVAL; |
109 | if (!ntb->ops) |
110 | return -EINVAL; |
111 | if (!ntb_dev_ops_is_valid(ops: ntb->ops)) |
112 | return -EINVAL; |
113 | |
114 | init_completion(x: &ntb->released); |
115 | |
116 | ntb->dev.bus = &ntb_bus; |
117 | ntb->dev.parent = &ntb->pdev->dev; |
118 | ntb->dev.release = ntb_dev_release; |
119 | dev_set_name(dev: &ntb->dev, name: "%s" , pci_name(pdev: ntb->pdev)); |
120 | |
121 | ntb->ctx = NULL; |
122 | ntb->ctx_ops = NULL; |
123 | spin_lock_init(&ntb->ctx_lock); |
124 | |
125 | ret = device_register(dev: &ntb->dev); |
126 | if (ret) |
127 | put_device(dev: &ntb->dev); |
128 | |
129 | return ret; |
130 | } |
131 | EXPORT_SYMBOL(ntb_register_device); |
132 | |
133 | void ntb_unregister_device(struct ntb_dev *ntb) |
134 | { |
135 | device_unregister(dev: &ntb->dev); |
136 | wait_for_completion(&ntb->released); |
137 | } |
138 | EXPORT_SYMBOL(ntb_unregister_device); |
139 | |
140 | int ntb_set_ctx(struct ntb_dev *ntb, void *ctx, |
141 | const struct ntb_ctx_ops *ctx_ops) |
142 | { |
143 | unsigned long irqflags; |
144 | |
145 | if (!ntb_ctx_ops_is_valid(ops: ctx_ops)) |
146 | return -EINVAL; |
147 | if (ntb->ctx_ops) |
148 | return -EINVAL; |
149 | |
150 | spin_lock_irqsave(&ntb->ctx_lock, irqflags); |
151 | { |
152 | ntb->ctx = ctx; |
153 | ntb->ctx_ops = ctx_ops; |
154 | } |
155 | spin_unlock_irqrestore(lock: &ntb->ctx_lock, flags: irqflags); |
156 | |
157 | return 0; |
158 | } |
159 | EXPORT_SYMBOL(ntb_set_ctx); |
160 | |
161 | void ntb_clear_ctx(struct ntb_dev *ntb) |
162 | { |
163 | unsigned long irqflags; |
164 | |
165 | spin_lock_irqsave(&ntb->ctx_lock, irqflags); |
166 | { |
167 | ntb->ctx_ops = NULL; |
168 | ntb->ctx = NULL; |
169 | } |
170 | spin_unlock_irqrestore(lock: &ntb->ctx_lock, flags: irqflags); |
171 | } |
172 | EXPORT_SYMBOL(ntb_clear_ctx); |
173 | |
174 | void ntb_link_event(struct ntb_dev *ntb) |
175 | { |
176 | unsigned long irqflags; |
177 | |
178 | spin_lock_irqsave(&ntb->ctx_lock, irqflags); |
179 | { |
180 | if (ntb->ctx_ops && ntb->ctx_ops->link_event) |
181 | ntb->ctx_ops->link_event(ntb->ctx); |
182 | } |
183 | spin_unlock_irqrestore(lock: &ntb->ctx_lock, flags: irqflags); |
184 | } |
185 | EXPORT_SYMBOL(ntb_link_event); |
186 | |
187 | void ntb_db_event(struct ntb_dev *ntb, int vector) |
188 | { |
189 | unsigned long irqflags; |
190 | |
191 | spin_lock_irqsave(&ntb->ctx_lock, irqflags); |
192 | { |
193 | if (ntb->ctx_ops && ntb->ctx_ops->db_event) |
194 | ntb->ctx_ops->db_event(ntb->ctx, vector); |
195 | } |
196 | spin_unlock_irqrestore(lock: &ntb->ctx_lock, flags: irqflags); |
197 | } |
198 | EXPORT_SYMBOL(ntb_db_event); |
199 | |
200 | void ntb_msg_event(struct ntb_dev *ntb) |
201 | { |
202 | unsigned long irqflags; |
203 | |
204 | spin_lock_irqsave(&ntb->ctx_lock, irqflags); |
205 | { |
206 | if (ntb->ctx_ops && ntb->ctx_ops->msg_event) |
207 | ntb->ctx_ops->msg_event(ntb->ctx); |
208 | } |
209 | spin_unlock_irqrestore(lock: &ntb->ctx_lock, flags: irqflags); |
210 | } |
211 | EXPORT_SYMBOL(ntb_msg_event); |
212 | |
213 | int ntb_default_port_number(struct ntb_dev *ntb) |
214 | { |
215 | switch (ntb->topo) { |
216 | case NTB_TOPO_PRI: |
217 | case NTB_TOPO_B2B_USD: |
218 | return NTB_PORT_PRI_USD; |
219 | case NTB_TOPO_SEC: |
220 | case NTB_TOPO_B2B_DSD: |
221 | return NTB_PORT_SEC_DSD; |
222 | default: |
223 | return 0; |
224 | } |
225 | } |
226 | EXPORT_SYMBOL(ntb_default_port_number); |
227 | |
228 | int ntb_default_peer_port_count(struct ntb_dev *ntb) |
229 | { |
230 | return NTB_DEF_PEER_CNT; |
231 | } |
232 | EXPORT_SYMBOL(ntb_default_peer_port_count); |
233 | |
234 | int ntb_default_peer_port_number(struct ntb_dev *ntb, int pidx) |
235 | { |
236 | if (pidx != NTB_DEF_PEER_IDX) |
237 | return -EINVAL; |
238 | |
239 | switch (ntb->topo) { |
240 | case NTB_TOPO_PRI: |
241 | case NTB_TOPO_B2B_USD: |
242 | return NTB_PORT_SEC_DSD; |
243 | case NTB_TOPO_SEC: |
244 | case NTB_TOPO_B2B_DSD: |
245 | return NTB_PORT_PRI_USD; |
246 | default: |
247 | return 0; |
248 | } |
249 | } |
250 | EXPORT_SYMBOL(ntb_default_peer_port_number); |
251 | |
252 | int ntb_default_peer_port_idx(struct ntb_dev *ntb, int port) |
253 | { |
254 | int peer_port = ntb_default_peer_port_number(ntb, NTB_DEF_PEER_IDX); |
255 | |
256 | if (peer_port == -EINVAL || port != peer_port) |
257 | return -EINVAL; |
258 | |
259 | return 0; |
260 | } |
261 | EXPORT_SYMBOL(ntb_default_peer_port_idx); |
262 | |
263 | static int ntb_probe(struct device *dev) |
264 | { |
265 | struct ntb_dev *ntb; |
266 | struct ntb_client *client; |
267 | int rc; |
268 | |
269 | get_device(dev); |
270 | ntb = dev_ntb(dev); |
271 | client = drv_ntb_client(dev->driver); |
272 | |
273 | rc = client->ops.probe(client, ntb); |
274 | if (rc) |
275 | put_device(dev); |
276 | |
277 | return rc; |
278 | } |
279 | |
280 | static void ntb_remove(struct device *dev) |
281 | { |
282 | struct ntb_dev *ntb; |
283 | struct ntb_client *client; |
284 | |
285 | if (dev->driver) { |
286 | ntb = dev_ntb(dev); |
287 | client = drv_ntb_client(dev->driver); |
288 | |
289 | client->ops.remove(client, ntb); |
290 | put_device(dev); |
291 | } |
292 | } |
293 | |
294 | static void ntb_dev_release(struct device *dev) |
295 | { |
296 | struct ntb_dev *ntb = dev_ntb(dev); |
297 | |
298 | complete(&ntb->released); |
299 | } |
300 | |
301 | static struct bus_type ntb_bus = { |
302 | .name = "ntb" , |
303 | .probe = ntb_probe, |
304 | .remove = ntb_remove, |
305 | }; |
306 | |
307 | static int __init ntb_driver_init(void) |
308 | { |
309 | return bus_register(bus: &ntb_bus); |
310 | } |
311 | module_init(ntb_driver_init); |
312 | |
313 | static void __exit ntb_driver_exit(void) |
314 | { |
315 | bus_unregister(bus: &ntb_bus); |
316 | } |
317 | module_exit(ntb_driver_exit); |
318 | |