1 | /* This file is part of the Emulex RoCE Device Driver for |
2 | * RoCE (RDMA over Converged Ethernet) adapters. |
3 | * Copyright (C) 2012-2015 Emulex. All rights reserved. |
4 | * EMULEX and SLI are trademarks of Emulex. |
5 | * www.emulex.com |
6 | * |
7 | * This software is available to you under a choice of one of two licenses. |
8 | * You may choose to be licensed under the terms of the GNU General Public |
9 | * License (GPL) Version 2, available from the file COPYING in the main |
10 | * directory of this source tree, or the BSD license below: |
11 | * |
12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions |
14 | * are met: |
15 | * |
16 | * - Redistributions of source code must retain the above copyright notice, |
17 | * this list of conditions and the following disclaimer. |
18 | * |
19 | * - Redistributions in binary form must reproduce the above copyright |
20 | * notice, this list of conditions and the following disclaimer in |
21 | * the documentation and/or other materials provided with the distribution. |
22 | * |
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE |
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
27 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
30 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
31 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
32 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
33 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
34 | * |
35 | * Contact Information: |
36 | * linux-drivers@emulex.com |
37 | * |
38 | * Emulex |
39 | * 3333 Susan Street |
40 | * Costa Mesa, CA 92626 |
41 | */ |
42 | |
43 | #include <linux/module.h> |
44 | #include <linux/idr.h> |
45 | #include <rdma/ib_verbs.h> |
46 | #include <rdma/ib_user_verbs.h> |
47 | #include <rdma/ib_addr.h> |
48 | #include <rdma/ib_mad.h> |
49 | |
50 | #include <linux/netdevice.h> |
51 | #include <net/addrconf.h> |
52 | |
53 | #include "ocrdma.h" |
54 | #include "ocrdma_verbs.h" |
55 | #include "ocrdma_ah.h" |
56 | #include "be_roce.h" |
57 | #include "ocrdma_hw.h" |
58 | #include "ocrdma_stats.h" |
59 | #include <rdma/ocrdma-abi.h> |
60 | |
61 | MODULE_DESCRIPTION(OCRDMA_ROCE_DRV_DESC " " OCRDMA_ROCE_DRV_VERSION); |
62 | MODULE_AUTHOR("Emulex Corporation" ); |
63 | MODULE_LICENSE("Dual BSD/GPL" ); |
64 | |
65 | static enum rdma_link_layer ocrdma_link_layer(struct ib_device *device, |
66 | u32 port_num) |
67 | { |
68 | return IB_LINK_LAYER_ETHERNET; |
69 | } |
70 | |
71 | static int ocrdma_port_immutable(struct ib_device *ibdev, u32 port_num, |
72 | struct ib_port_immutable *immutable) |
73 | { |
74 | struct ib_port_attr attr; |
75 | struct ocrdma_dev *dev; |
76 | int err; |
77 | |
78 | dev = get_ocrdma_dev(ibdev); |
79 | immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE; |
80 | if (ocrdma_is_udp_encap_supported(dev)) |
81 | immutable->core_cap_flags |= RDMA_CORE_CAP_PROT_ROCE_UDP_ENCAP; |
82 | |
83 | err = ib_query_port(device: ibdev, port_num, port_attr: &attr); |
84 | if (err) |
85 | return err; |
86 | |
87 | immutable->pkey_tbl_len = attr.pkey_tbl_len; |
88 | immutable->gid_tbl_len = attr.gid_tbl_len; |
89 | immutable->max_mad_size = IB_MGMT_MAD_SIZE; |
90 | |
91 | return 0; |
92 | } |
93 | |
94 | static void get_dev_fw_str(struct ib_device *device, char *str) |
95 | { |
96 | struct ocrdma_dev *dev = get_ocrdma_dev(ibdev: device); |
97 | |
98 | snprintf(buf: str, IB_FW_VERSION_NAME_MAX, fmt: "%s" , &dev->attr.fw_ver[0]); |
99 | } |
100 | |
101 | /* OCRDMA sysfs interface */ |
102 | static ssize_t hw_rev_show(struct device *device, |
103 | struct device_attribute *attr, char *buf) |
104 | { |
105 | struct ocrdma_dev *dev = |
106 | rdma_device_to_drv_device(device, struct ocrdma_dev, ibdev); |
107 | |
108 | return sysfs_emit(buf, fmt: "0x%x\n" , dev->nic_info.pdev->vendor); |
109 | } |
110 | static DEVICE_ATTR_RO(hw_rev); |
111 | |
112 | static ssize_t hca_type_show(struct device *device, |
113 | struct device_attribute *attr, char *buf) |
114 | { |
115 | struct ocrdma_dev *dev = |
116 | rdma_device_to_drv_device(device, struct ocrdma_dev, ibdev); |
117 | |
118 | return sysfs_emit(buf, fmt: "%s\n" , &dev->model_number[0]); |
119 | } |
120 | static DEVICE_ATTR_RO(hca_type); |
121 | |
122 | static struct attribute *ocrdma_attributes[] = { |
123 | &dev_attr_hw_rev.attr, |
124 | &dev_attr_hca_type.attr, |
125 | NULL |
126 | }; |
127 | |
128 | static const struct attribute_group ocrdma_attr_group = { |
129 | .attrs = ocrdma_attributes, |
130 | }; |
131 | |
132 | static const struct ib_device_ops ocrdma_dev_ops = { |
133 | .owner = THIS_MODULE, |
134 | .driver_id = RDMA_DRIVER_OCRDMA, |
135 | .uverbs_abi_ver = OCRDMA_ABI_VERSION, |
136 | |
137 | .alloc_mr = ocrdma_alloc_mr, |
138 | .alloc_pd = ocrdma_alloc_pd, |
139 | .alloc_ucontext = ocrdma_alloc_ucontext, |
140 | .create_ah = ocrdma_create_ah, |
141 | .create_cq = ocrdma_create_cq, |
142 | .create_qp = ocrdma_create_qp, |
143 | .create_user_ah = ocrdma_create_ah, |
144 | .dealloc_pd = ocrdma_dealloc_pd, |
145 | .dealloc_ucontext = ocrdma_dealloc_ucontext, |
146 | .dereg_mr = ocrdma_dereg_mr, |
147 | .destroy_ah = ocrdma_destroy_ah, |
148 | .destroy_cq = ocrdma_destroy_cq, |
149 | .destroy_qp = ocrdma_destroy_qp, |
150 | .device_group = &ocrdma_attr_group, |
151 | .get_dev_fw_str = get_dev_fw_str, |
152 | .get_dma_mr = ocrdma_get_dma_mr, |
153 | .get_link_layer = ocrdma_link_layer, |
154 | .get_port_immutable = ocrdma_port_immutable, |
155 | .map_mr_sg = ocrdma_map_mr_sg, |
156 | .mmap = ocrdma_mmap, |
157 | .modify_qp = ocrdma_modify_qp, |
158 | .poll_cq = ocrdma_poll_cq, |
159 | .post_recv = ocrdma_post_recv, |
160 | .post_send = ocrdma_post_send, |
161 | .process_mad = ocrdma_process_mad, |
162 | .query_ah = ocrdma_query_ah, |
163 | .query_device = ocrdma_query_device, |
164 | .query_pkey = ocrdma_query_pkey, |
165 | .query_port = ocrdma_query_port, |
166 | .query_qp = ocrdma_query_qp, |
167 | .reg_user_mr = ocrdma_reg_user_mr, |
168 | .req_notify_cq = ocrdma_arm_cq, |
169 | .resize_cq = ocrdma_resize_cq, |
170 | |
171 | INIT_RDMA_OBJ_SIZE(ib_ah, ocrdma_ah, ibah), |
172 | INIT_RDMA_OBJ_SIZE(ib_cq, ocrdma_cq, ibcq), |
173 | INIT_RDMA_OBJ_SIZE(ib_pd, ocrdma_pd, ibpd), |
174 | INIT_RDMA_OBJ_SIZE(ib_qp, ocrdma_qp, ibqp), |
175 | INIT_RDMA_OBJ_SIZE(ib_ucontext, ocrdma_ucontext, ibucontext), |
176 | }; |
177 | |
178 | static const struct ib_device_ops ocrdma_dev_srq_ops = { |
179 | .create_srq = ocrdma_create_srq, |
180 | .destroy_srq = ocrdma_destroy_srq, |
181 | .modify_srq = ocrdma_modify_srq, |
182 | .post_srq_recv = ocrdma_post_srq_recv, |
183 | .query_srq = ocrdma_query_srq, |
184 | |
185 | INIT_RDMA_OBJ_SIZE(ib_srq, ocrdma_srq, ibsrq), |
186 | }; |
187 | |
188 | static int ocrdma_register_device(struct ocrdma_dev *dev) |
189 | { |
190 | int ret; |
191 | |
192 | addrconf_addr_eui48(eui: (u8 *)&dev->ibdev.node_guid, |
193 | addr: dev->nic_info.mac_addr); |
194 | BUILD_BUG_ON(sizeof(OCRDMA_NODE_DESC) > IB_DEVICE_NODE_DESC_MAX); |
195 | memcpy(dev->ibdev.node_desc, OCRDMA_NODE_DESC, |
196 | sizeof(OCRDMA_NODE_DESC)); |
197 | |
198 | dev->ibdev.node_type = RDMA_NODE_IB_CA; |
199 | dev->ibdev.phys_port_cnt = 1; |
200 | dev->ibdev.num_comp_vectors = dev->eq_cnt; |
201 | |
202 | /* mandatory to support user space verbs consumer. */ |
203 | dev->ibdev.dev.parent = &dev->nic_info.pdev->dev; |
204 | |
205 | ib_set_device_ops(device: &dev->ibdev, ops: &ocrdma_dev_ops); |
206 | |
207 | if (ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R) |
208 | ib_set_device_ops(device: &dev->ibdev, ops: &ocrdma_dev_srq_ops); |
209 | |
210 | ret = ib_device_set_netdev(ib_dev: &dev->ibdev, ndev: dev->nic_info.netdev, port: 1); |
211 | if (ret) |
212 | return ret; |
213 | |
214 | dma_set_max_seg_size(dev: &dev->nic_info.pdev->dev, UINT_MAX); |
215 | return ib_register_device(device: &dev->ibdev, name: "ocrdma%d" , |
216 | dma_device: &dev->nic_info.pdev->dev); |
217 | } |
218 | |
219 | static int ocrdma_alloc_resources(struct ocrdma_dev *dev) |
220 | { |
221 | mutex_init(&dev->dev_lock); |
222 | dev->cq_tbl = kcalloc(OCRDMA_MAX_CQ, size: sizeof(struct ocrdma_cq *), |
223 | GFP_KERNEL); |
224 | if (!dev->cq_tbl) |
225 | goto alloc_err; |
226 | |
227 | if (dev->attr.max_qp) { |
228 | dev->qp_tbl = kcalloc(OCRDMA_MAX_QP, |
229 | size: sizeof(struct ocrdma_qp *), |
230 | GFP_KERNEL); |
231 | if (!dev->qp_tbl) |
232 | goto alloc_err; |
233 | } |
234 | |
235 | dev->stag_arr = kcalloc(OCRDMA_MAX_STAG, size: sizeof(u64), GFP_KERNEL); |
236 | if (dev->stag_arr == NULL) |
237 | goto alloc_err; |
238 | |
239 | ocrdma_alloc_pd_pool(dev); |
240 | |
241 | if (!ocrdma_alloc_stats_resources(dev)) { |
242 | pr_err("%s: stats resource allocation failed\n" , __func__); |
243 | goto alloc_err; |
244 | } |
245 | |
246 | spin_lock_init(&dev->av_tbl.lock); |
247 | spin_lock_init(&dev->flush_q_lock); |
248 | return 0; |
249 | alloc_err: |
250 | pr_err("%s(%d) error.\n" , __func__, dev->id); |
251 | return -ENOMEM; |
252 | } |
253 | |
254 | static void ocrdma_free_resources(struct ocrdma_dev *dev) |
255 | { |
256 | ocrdma_release_stats_resources(dev); |
257 | kfree(objp: dev->stag_arr); |
258 | kfree(objp: dev->qp_tbl); |
259 | kfree(objp: dev->cq_tbl); |
260 | } |
261 | |
262 | static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info) |
263 | { |
264 | int status = 0; |
265 | u8 lstate = 0; |
266 | struct ocrdma_dev *dev; |
267 | |
268 | dev = ib_alloc_device(ocrdma_dev, ibdev); |
269 | if (!dev) { |
270 | pr_err("Unable to allocate ib device\n" ); |
271 | return NULL; |
272 | } |
273 | |
274 | dev->mbx_cmd = kzalloc(size: sizeof(struct ocrdma_mqe_emb_cmd), GFP_KERNEL); |
275 | if (!dev->mbx_cmd) |
276 | goto init_err; |
277 | |
278 | memcpy(&dev->nic_info, dev_info, sizeof(*dev_info)); |
279 | dev->id = PCI_FUNC(dev->nic_info.pdev->devfn); |
280 | status = ocrdma_init_hw(dev); |
281 | if (status) |
282 | goto init_err; |
283 | |
284 | status = ocrdma_alloc_resources(dev); |
285 | if (status) |
286 | goto alloc_err; |
287 | |
288 | ocrdma_init_service_level(dev); |
289 | status = ocrdma_register_device(dev); |
290 | if (status) |
291 | goto alloc_err; |
292 | |
293 | /* Query Link state and update */ |
294 | status = ocrdma_mbx_get_link_speed(dev, NULL, lnk_st: &lstate); |
295 | if (!status) |
296 | ocrdma_update_link_state(dev, lstate); |
297 | |
298 | /* Init stats */ |
299 | ocrdma_add_port_stats(dev); |
300 | /* Interrupt Moderation */ |
301 | INIT_DELAYED_WORK(&dev->eqd_work, ocrdma_eqd_set_task); |
302 | schedule_delayed_work(dwork: &dev->eqd_work, delay: msecs_to_jiffies(m: 1000)); |
303 | |
304 | pr_info("%s %s: %s \"%s\" port %d\n" , |
305 | dev_name(&dev->nic_info.pdev->dev), hca_name(dev), |
306 | port_speed_string(dev), dev->model_number, |
307 | dev->hba_port_num); |
308 | pr_info("%s ocrdma%d driver loaded successfully\n" , |
309 | dev_name(&dev->nic_info.pdev->dev), dev->id); |
310 | return dev; |
311 | |
312 | alloc_err: |
313 | ocrdma_free_resources(dev); |
314 | ocrdma_cleanup_hw(dev); |
315 | init_err: |
316 | kfree(objp: dev->mbx_cmd); |
317 | ib_dealloc_device(device: &dev->ibdev); |
318 | pr_err("%s() leaving. ret=%d\n" , __func__, status); |
319 | return NULL; |
320 | } |
321 | |
322 | static void ocrdma_remove_free(struct ocrdma_dev *dev) |
323 | { |
324 | |
325 | kfree(objp: dev->mbx_cmd); |
326 | ib_dealloc_device(device: &dev->ibdev); |
327 | } |
328 | |
329 | static void ocrdma_remove(struct ocrdma_dev *dev) |
330 | { |
331 | /* first unregister with stack to stop all the active traffic |
332 | * of the registered clients. |
333 | */ |
334 | cancel_delayed_work_sync(dwork: &dev->eqd_work); |
335 | ib_unregister_device(device: &dev->ibdev); |
336 | |
337 | ocrdma_rem_port_stats(dev); |
338 | ocrdma_free_resources(dev); |
339 | ocrdma_cleanup_hw(dev); |
340 | ocrdma_remove_free(dev); |
341 | } |
342 | |
343 | static int ocrdma_dispatch_port_active(struct ocrdma_dev *dev) |
344 | { |
345 | struct ib_event port_event; |
346 | |
347 | port_event.event = IB_EVENT_PORT_ACTIVE; |
348 | port_event.element.port_num = 1; |
349 | port_event.device = &dev->ibdev; |
350 | ib_dispatch_event(event: &port_event); |
351 | return 0; |
352 | } |
353 | |
354 | static int ocrdma_dispatch_port_error(struct ocrdma_dev *dev) |
355 | { |
356 | struct ib_event err_event; |
357 | |
358 | err_event.event = IB_EVENT_PORT_ERR; |
359 | err_event.element.port_num = 1; |
360 | err_event.device = &dev->ibdev; |
361 | ib_dispatch_event(event: &err_event); |
362 | return 0; |
363 | } |
364 | |
365 | static void ocrdma_shutdown(struct ocrdma_dev *dev) |
366 | { |
367 | ocrdma_dispatch_port_error(dev); |
368 | ocrdma_remove(dev); |
369 | } |
370 | |
371 | /* event handling via NIC driver ensures that all the NIC specific |
372 | * initialization done before RoCE driver notifies |
373 | * event to stack. |
374 | */ |
375 | static void ocrdma_event_handler(struct ocrdma_dev *dev, u32 event) |
376 | { |
377 | switch (event) { |
378 | case BE_DEV_SHUTDOWN: |
379 | ocrdma_shutdown(dev); |
380 | break; |
381 | default: |
382 | break; |
383 | } |
384 | } |
385 | |
386 | void ocrdma_update_link_state(struct ocrdma_dev *dev, u8 lstate) |
387 | { |
388 | if (!(dev->flags & OCRDMA_FLAGS_LINK_STATUS_INIT)) { |
389 | dev->flags |= OCRDMA_FLAGS_LINK_STATUS_INIT; |
390 | if (!lstate) |
391 | return; |
392 | } |
393 | |
394 | if (!lstate) |
395 | ocrdma_dispatch_port_error(dev); |
396 | else |
397 | ocrdma_dispatch_port_active(dev); |
398 | } |
399 | |
400 | static struct ocrdma_driver ocrdma_drv = { |
401 | .name = "ocrdma_driver" , |
402 | .add = ocrdma_add, |
403 | .remove = ocrdma_remove, |
404 | .state_change_handler = ocrdma_event_handler, |
405 | .be_abi_version = OCRDMA_BE_ROCE_ABI_VERSION, |
406 | }; |
407 | |
408 | static int __init ocrdma_init_module(void) |
409 | { |
410 | int status; |
411 | |
412 | ocrdma_init_debugfs(); |
413 | |
414 | status = be_roce_register_driver(&ocrdma_drv); |
415 | if (status) |
416 | goto err_be_reg; |
417 | |
418 | return 0; |
419 | |
420 | err_be_reg: |
421 | |
422 | return status; |
423 | } |
424 | |
425 | static void __exit ocrdma_exit_module(void) |
426 | { |
427 | be_roce_unregister_driver(&ocrdma_drv); |
428 | ocrdma_rem_debugfs(); |
429 | } |
430 | |
431 | module_init(ocrdma_init_module); |
432 | module_exit(ocrdma_exit_module); |
433 | |