]>
Commit | Line | Data |
---|---|---|
fe2caefc PP |
1 | /******************************************************************* |
2 | * This file is part of the Emulex RoCE Device Driver for * | |
3 | * RoCE (RDMA over Converged Ethernet) adapters. * | |
4 | * Copyright (C) 2008-2012 Emulex. All rights reserved. * | |
5 | * EMULEX and SLI are trademarks of Emulex. * | |
6 | * www.emulex.com * | |
7 | * * | |
8 | * This program is free software; you can redistribute it and/or * | |
9 | * modify it under the terms of version 2 of the GNU General * | |
10 | * Public License as published by the Free Software Foundation. * | |
11 | * This program is distributed in the hope that it will be useful. * | |
12 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * | |
13 | * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * | |
14 | * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * | |
15 | * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * | |
16 | * TO BE LEGALLY INVALID. See the GNU General Public License for * | |
17 | * more details, a copy of which can be found in the file COPYING * | |
18 | * included with this package. * | |
19 | * | |
20 | * Contact Information: | |
21 | * linux-drivers@emulex.com | |
22 | * | |
23 | * Emulex | |
24 | * 3333 Susan Street | |
25 | * Costa Mesa, CA 92626 | |
26 | *******************************************************************/ | |
27 | ||
28 | #include <linux/module.h> | |
fe2caefc PP |
29 | #include <linux/idr.h> |
30 | #include <rdma/ib_verbs.h> | |
31 | #include <rdma/ib_user_verbs.h> | |
32 | #include <rdma/ib_addr.h> | |
33 | ||
34 | #include <linux/netdevice.h> | |
35 | #include <net/addrconf.h> | |
36 | ||
37 | #include "ocrdma.h" | |
38 | #include "ocrdma_verbs.h" | |
39 | #include "ocrdma_ah.h" | |
40 | #include "be_roce.h" | |
41 | #include "ocrdma_hw.h" | |
a51f06e1 | 42 | #include "ocrdma_stats.h" |
38754397 | 43 | #include "ocrdma_abi.h" |
fe2caefc | 44 | |
0154410b DS |
45 | MODULE_VERSION(OCRDMA_ROCE_DRV_VERSION); |
46 | MODULE_DESCRIPTION(OCRDMA_ROCE_DRV_DESC " " OCRDMA_ROCE_DRV_VERSION); | |
fe2caefc PP |
47 | MODULE_AUTHOR("Emulex Corporation"); |
48 | MODULE_LICENSE("GPL"); | |
49 | ||
50 | static LIST_HEAD(ocrdma_dev_list); | |
3e4d60a8 | 51 | static DEFINE_SPINLOCK(ocrdma_devlist_lock); |
fe2caefc PP |
52 | static DEFINE_IDR(ocrdma_dev_id); |
53 | ||
54 | static union ib_gid ocrdma_zero_sgid; | |
fe2caefc | 55 | |
fe2caefc PP |
56 | void ocrdma_get_guid(struct ocrdma_dev *dev, u8 *guid) |
57 | { | |
58 | u8 mac_addr[6]; | |
59 | ||
60 | memcpy(&mac_addr[0], &dev->nic_info.mac_addr[0], ETH_ALEN); | |
61 | guid[0] = mac_addr[0] ^ 2; | |
62 | guid[1] = mac_addr[1]; | |
63 | guid[2] = mac_addr[2]; | |
64 | guid[3] = 0xff; | |
65 | guid[4] = 0xfe; | |
66 | guid[5] = mac_addr[3]; | |
67 | guid[6] = mac_addr[4]; | |
68 | guid[7] = mac_addr[5]; | |
69 | } | |
70 | ||
37721d85 | 71 | static bool ocrdma_add_sgid(struct ocrdma_dev *dev, union ib_gid *new_sgid) |
fe2caefc PP |
72 | { |
73 | int i; | |
fe2caefc PP |
74 | unsigned long flags; |
75 | ||
76 | memset(&ocrdma_zero_sgid, 0, sizeof(union ib_gid)); | |
77 | ||
fe2caefc PP |
78 | |
79 | spin_lock_irqsave(&dev->sgid_lock, flags); | |
80 | for (i = 0; i < OCRDMA_MAX_SGID; i++) { | |
81 | if (!memcmp(&dev->sgid_tbl[i], &ocrdma_zero_sgid, | |
82 | sizeof(union ib_gid))) { | |
83 | /* found free entry */ | |
37721d85 | 84 | memcpy(&dev->sgid_tbl[i], new_sgid, |
6ab6827e PP |
85 | sizeof(union ib_gid)); |
86 | spin_unlock_irqrestore(&dev->sgid_lock, flags); | |
87 | return true; | |
37721d85 | 88 | } else if (!memcmp(&dev->sgid_tbl[i], new_sgid, |
fe2caefc PP |
89 | sizeof(union ib_gid))) { |
90 | /* entry already present, no addition is required. */ | |
91 | spin_unlock_irqrestore(&dev->sgid_lock, flags); | |
6ab6827e | 92 | return false; |
fe2caefc PP |
93 | } |
94 | } | |
fe2caefc | 95 | spin_unlock_irqrestore(&dev->sgid_lock, flags); |
6ab6827e | 96 | return false; |
fe2caefc PP |
97 | } |
98 | ||
37721d85 | 99 | static bool ocrdma_del_sgid(struct ocrdma_dev *dev, union ib_gid *sgid) |
fe2caefc PP |
100 | { |
101 | int found = false; | |
102 | int i; | |
fe2caefc PP |
103 | unsigned long flags; |
104 | ||
fe2caefc PP |
105 | |
106 | spin_lock_irqsave(&dev->sgid_lock, flags); | |
107 | /* first is default sgid, which cannot be deleted. */ | |
108 | for (i = 1; i < OCRDMA_MAX_SGID; i++) { | |
37721d85 | 109 | if (!memcmp(&dev->sgid_tbl[i], sgid, sizeof(union ib_gid))) { |
fe2caefc PP |
110 | /* found matching entry */ |
111 | memset(&dev->sgid_tbl[i], 0, sizeof(union ib_gid)); | |
112 | found = true; | |
113 | break; | |
114 | } | |
115 | } | |
116 | spin_unlock_irqrestore(&dev->sgid_lock, flags); | |
117 | return found; | |
118 | } | |
119 | ||
37721d85 MS |
120 | static int ocrdma_addr_event(unsigned long event, struct net_device *netdev, |
121 | union ib_gid *gid) | |
6ab6827e | 122 | { |
fe2caefc PP |
123 | struct ib_event gid_event; |
124 | struct ocrdma_dev *dev; | |
125 | bool found = false; | |
6ab6827e | 126 | bool updated = false; |
fe2caefc | 127 | bool is_vlan = false; |
fe2caefc | 128 | |
d549f55f | 129 | is_vlan = netdev->priv_flags & IFF_802_1Q_VLAN; |
37721d85 | 130 | if (is_vlan) |
09de3f13 | 131 | netdev = rdma_vlan_dev_real_dev(netdev); |
d549f55f | 132 | |
3e4d60a8 SL |
133 | rcu_read_lock(); |
134 | list_for_each_entry_rcu(dev, &ocrdma_dev_list, entry) { | |
fe2caefc PP |
135 | if (dev->nic_info.netdev == netdev) { |
136 | found = true; | |
137 | break; | |
138 | } | |
139 | } | |
3e4d60a8 | 140 | rcu_read_unlock(); |
fe2caefc PP |
141 | |
142 | if (!found) | |
143 | return NOTIFY_DONE; | |
fe2caefc PP |
144 | |
145 | mutex_lock(&dev->dev_lock); | |
146 | switch (event) { | |
147 | case NETDEV_UP: | |
37721d85 | 148 | updated = ocrdma_add_sgid(dev, gid); |
fe2caefc PP |
149 | break; |
150 | case NETDEV_DOWN: | |
37721d85 | 151 | updated = ocrdma_del_sgid(dev, gid); |
fe2caefc PP |
152 | break; |
153 | default: | |
154 | break; | |
155 | } | |
6ab6827e PP |
156 | if (updated) { |
157 | /* GID table updated, notify the consumers about it */ | |
158 | gid_event.device = &dev->ibdev; | |
159 | gid_event.element.port_num = 1; | |
160 | gid_event.event = IB_EVENT_GID_CHANGE; | |
161 | ib_dispatch_event(&gid_event); | |
162 | } | |
fe2caefc PP |
163 | mutex_unlock(&dev->dev_lock); |
164 | return NOTIFY_OK; | |
165 | } | |
166 | ||
37721d85 MS |
167 | static int ocrdma_inetaddr_event(struct notifier_block *notifier, |
168 | unsigned long event, void *ptr) | |
169 | { | |
170 | struct in_ifaddr *ifa = ptr; | |
171 | union ib_gid gid; | |
172 | struct net_device *netdev = ifa->ifa_dev->dev; | |
173 | ||
174 | ipv6_addr_set_v4mapped(ifa->ifa_address, (struct in6_addr *)&gid); | |
175 | return ocrdma_addr_event(event, netdev, &gid); | |
176 | } | |
177 | ||
31ab8acb RD |
178 | static struct notifier_block ocrdma_inetaddr_notifier = { |
179 | .notifier_call = ocrdma_inetaddr_event | |
180 | }; | |
181 | ||
37721d85 MS |
182 | #if IS_ENABLED(CONFIG_IPV6) |
183 | ||
184 | static int ocrdma_inet6addr_event(struct notifier_block *notifier, | |
185 | unsigned long event, void *ptr) | |
186 | { | |
187 | struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; | |
188 | union ib_gid *gid = (union ib_gid *)&ifa->addr; | |
189 | struct net_device *netdev = ifa->idev->dev; | |
190 | return ocrdma_addr_event(event, netdev, gid); | |
191 | } | |
192 | ||
34955669 RD |
193 | static struct notifier_block ocrdma_inet6addr_notifier = { |
194 | .notifier_call = ocrdma_inet6addr_event | |
195 | }; | |
196 | ||
6ab6827e | 197 | #endif /* IPV6 and VLAN */ |
34955669 | 198 | |
fe2caefc PP |
199 | static enum rdma_link_layer ocrdma_link_layer(struct ib_device *device, |
200 | u8 port_num) | |
201 | { | |
202 | return IB_LINK_LAYER_ETHERNET; | |
203 | } | |
204 | ||
abe3afac | 205 | static int ocrdma_register_device(struct ocrdma_dev *dev) |
fe2caefc PP |
206 | { |
207 | strlcpy(dev->ibdev.name, "ocrdma%d", IB_DEVICE_NAME_MAX); | |
208 | ocrdma_get_guid(dev, (u8 *)&dev->ibdev.node_guid); | |
209 | memcpy(dev->ibdev.node_desc, OCRDMA_NODE_DESC, | |
210 | sizeof(OCRDMA_NODE_DESC)); | |
211 | dev->ibdev.owner = THIS_MODULE; | |
38754397 | 212 | dev->ibdev.uverbs_abi_ver = OCRDMA_ABI_VERSION; |
fe2caefc PP |
213 | dev->ibdev.uverbs_cmd_mask = |
214 | OCRDMA_UVERBS(GET_CONTEXT) | | |
215 | OCRDMA_UVERBS(QUERY_DEVICE) | | |
216 | OCRDMA_UVERBS(QUERY_PORT) | | |
217 | OCRDMA_UVERBS(ALLOC_PD) | | |
218 | OCRDMA_UVERBS(DEALLOC_PD) | | |
219 | OCRDMA_UVERBS(REG_MR) | | |
220 | OCRDMA_UVERBS(DEREG_MR) | | |
221 | OCRDMA_UVERBS(CREATE_COMP_CHANNEL) | | |
222 | OCRDMA_UVERBS(CREATE_CQ) | | |
223 | OCRDMA_UVERBS(RESIZE_CQ) | | |
224 | OCRDMA_UVERBS(DESTROY_CQ) | | |
225 | OCRDMA_UVERBS(REQ_NOTIFY_CQ) | | |
226 | OCRDMA_UVERBS(CREATE_QP) | | |
227 | OCRDMA_UVERBS(MODIFY_QP) | | |
228 | OCRDMA_UVERBS(QUERY_QP) | | |
229 | OCRDMA_UVERBS(DESTROY_QP) | | |
230 | OCRDMA_UVERBS(POLL_CQ) | | |
231 | OCRDMA_UVERBS(POST_SEND) | | |
232 | OCRDMA_UVERBS(POST_RECV); | |
233 | ||
234 | dev->ibdev.uverbs_cmd_mask |= | |
235 | OCRDMA_UVERBS(CREATE_AH) | | |
236 | OCRDMA_UVERBS(MODIFY_AH) | | |
237 | OCRDMA_UVERBS(QUERY_AH) | | |
238 | OCRDMA_UVERBS(DESTROY_AH); | |
239 | ||
240 | dev->ibdev.node_type = RDMA_NODE_IB_CA; | |
241 | dev->ibdev.phys_port_cnt = 1; | |
242 | dev->ibdev.num_comp_vectors = 1; | |
243 | ||
244 | /* mandatory verbs. */ | |
245 | dev->ibdev.query_device = ocrdma_query_device; | |
246 | dev->ibdev.query_port = ocrdma_query_port; | |
247 | dev->ibdev.modify_port = ocrdma_modify_port; | |
248 | dev->ibdev.query_gid = ocrdma_query_gid; | |
249 | dev->ibdev.get_link_layer = ocrdma_link_layer; | |
250 | dev->ibdev.alloc_pd = ocrdma_alloc_pd; | |
251 | dev->ibdev.dealloc_pd = ocrdma_dealloc_pd; | |
252 | ||
253 | dev->ibdev.create_cq = ocrdma_create_cq; | |
254 | dev->ibdev.destroy_cq = ocrdma_destroy_cq; | |
255 | dev->ibdev.resize_cq = ocrdma_resize_cq; | |
256 | ||
257 | dev->ibdev.create_qp = ocrdma_create_qp; | |
258 | dev->ibdev.modify_qp = ocrdma_modify_qp; | |
259 | dev->ibdev.query_qp = ocrdma_query_qp; | |
260 | dev->ibdev.destroy_qp = ocrdma_destroy_qp; | |
261 | ||
262 | dev->ibdev.query_pkey = ocrdma_query_pkey; | |
263 | dev->ibdev.create_ah = ocrdma_create_ah; | |
264 | dev->ibdev.destroy_ah = ocrdma_destroy_ah; | |
265 | dev->ibdev.query_ah = ocrdma_query_ah; | |
266 | dev->ibdev.modify_ah = ocrdma_modify_ah; | |
267 | ||
268 | dev->ibdev.poll_cq = ocrdma_poll_cq; | |
269 | dev->ibdev.post_send = ocrdma_post_send; | |
270 | dev->ibdev.post_recv = ocrdma_post_recv; | |
271 | dev->ibdev.req_notify_cq = ocrdma_arm_cq; | |
272 | ||
273 | dev->ibdev.get_dma_mr = ocrdma_get_dma_mr; | |
cffce990 | 274 | dev->ibdev.reg_phys_mr = ocrdma_reg_kernel_mr; |
fe2caefc PP |
275 | dev->ibdev.dereg_mr = ocrdma_dereg_mr; |
276 | dev->ibdev.reg_user_mr = ocrdma_reg_user_mr; | |
277 | ||
7c33880c NG |
278 | dev->ibdev.alloc_fast_reg_mr = ocrdma_alloc_frmr; |
279 | dev->ibdev.alloc_fast_reg_page_list = ocrdma_alloc_frmr_page_list; | |
280 | dev->ibdev.free_fast_reg_page_list = ocrdma_free_frmr_page_list; | |
281 | ||
fe2caefc PP |
282 | /* mandatory to support user space verbs consumer. */ |
283 | dev->ibdev.alloc_ucontext = ocrdma_alloc_ucontext; | |
284 | dev->ibdev.dealloc_ucontext = ocrdma_dealloc_ucontext; | |
285 | dev->ibdev.mmap = ocrdma_mmap; | |
286 | dev->ibdev.dma_device = &dev->nic_info.pdev->dev; | |
287 | ||
288 | dev->ibdev.process_mad = ocrdma_process_mad; | |
289 | ||
21c3391a | 290 | if (ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R) { |
fe2caefc PP |
291 | dev->ibdev.uverbs_cmd_mask |= |
292 | OCRDMA_UVERBS(CREATE_SRQ) | | |
293 | OCRDMA_UVERBS(MODIFY_SRQ) | | |
294 | OCRDMA_UVERBS(QUERY_SRQ) | | |
295 | OCRDMA_UVERBS(DESTROY_SRQ) | | |
296 | OCRDMA_UVERBS(POST_SRQ_RECV); | |
297 | ||
298 | dev->ibdev.create_srq = ocrdma_create_srq; | |
299 | dev->ibdev.modify_srq = ocrdma_modify_srq; | |
300 | dev->ibdev.query_srq = ocrdma_query_srq; | |
301 | dev->ibdev.destroy_srq = ocrdma_destroy_srq; | |
302 | dev->ibdev.post_srq_recv = ocrdma_post_srq_recv; | |
303 | } | |
304 | return ib_register_device(&dev->ibdev, NULL); | |
305 | } | |
306 | ||
307 | static int ocrdma_alloc_resources(struct ocrdma_dev *dev) | |
308 | { | |
309 | mutex_init(&dev->dev_lock); | |
310 | dev->sgid_tbl = kzalloc(sizeof(union ib_gid) * | |
311 | OCRDMA_MAX_SGID, GFP_KERNEL); | |
312 | if (!dev->sgid_tbl) | |
313 | goto alloc_err; | |
314 | spin_lock_init(&dev->sgid_lock); | |
315 | ||
316 | dev->cq_tbl = kzalloc(sizeof(struct ocrdma_cq *) * | |
317 | OCRDMA_MAX_CQ, GFP_KERNEL); | |
318 | if (!dev->cq_tbl) | |
319 | goto alloc_err; | |
320 | ||
321 | if (dev->attr.max_qp) { | |
322 | dev->qp_tbl = kzalloc(sizeof(struct ocrdma_qp *) * | |
323 | OCRDMA_MAX_QP, GFP_KERNEL); | |
324 | if (!dev->qp_tbl) | |
325 | goto alloc_err; | |
326 | } | |
4f1df844 SX |
327 | |
328 | dev->stag_arr = kzalloc(sizeof(u64) * OCRDMA_MAX_STAG, GFP_KERNEL); | |
329 | if (dev->stag_arr == NULL) | |
330 | goto alloc_err; | |
331 | ||
fe2caefc PP |
332 | spin_lock_init(&dev->av_tbl.lock); |
333 | spin_lock_init(&dev->flush_q_lock); | |
334 | return 0; | |
335 | alloc_err: | |
ef99c4c2 | 336 | pr_err("%s(%d) error.\n", __func__, dev->id); |
fe2caefc PP |
337 | return -ENOMEM; |
338 | } | |
339 | ||
340 | static void ocrdma_free_resources(struct ocrdma_dev *dev) | |
341 | { | |
4f1df844 | 342 | kfree(dev->stag_arr); |
fe2caefc PP |
343 | kfree(dev->qp_tbl); |
344 | kfree(dev->cq_tbl); | |
345 | kfree(dev->sgid_tbl); | |
346 | } | |
347 | ||
334b8db3 SX |
348 | /* OCRDMA sysfs interface */ |
349 | static ssize_t show_rev(struct device *device, struct device_attribute *attr, | |
350 | char *buf) | |
351 | { | |
352 | struct ocrdma_dev *dev = dev_get_drvdata(device); | |
353 | ||
354 | return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->nic_info.pdev->vendor); | |
355 | } | |
356 | ||
357 | static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr, | |
358 | char *buf) | |
359 | { | |
360 | struct ocrdma_dev *dev = dev_get_drvdata(device); | |
361 | ||
4808b184 SX |
362 | return scnprintf(buf, PAGE_SIZE, "%s\n", &dev->attr.fw_ver[0]); |
363 | } | |
364 | ||
365 | static ssize_t show_hca_type(struct device *device, | |
366 | struct device_attribute *attr, char *buf) | |
367 | { | |
368 | struct ocrdma_dev *dev = dev_get_drvdata(device); | |
369 | ||
370 | return scnprintf(buf, PAGE_SIZE, "%s\n", &dev->model_number[0]); | |
334b8db3 SX |
371 | } |
372 | ||
373 | static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); | |
374 | static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); | |
4808b184 | 375 | static DEVICE_ATTR(hca_type, S_IRUGO, show_hca_type, NULL); |
334b8db3 SX |
376 | |
377 | static struct device_attribute *ocrdma_attributes[] = { | |
378 | &dev_attr_hw_rev, | |
4808b184 SX |
379 | &dev_attr_fw_ver, |
380 | &dev_attr_hca_type | |
334b8db3 SX |
381 | }; |
382 | ||
383 | static void ocrdma_remove_sysfiles(struct ocrdma_dev *dev) | |
384 | { | |
385 | int i; | |
386 | ||
387 | for (i = 0; i < ARRAY_SIZE(ocrdma_attributes); i++) | |
388 | device_remove_file(&dev->ibdev.dev, ocrdma_attributes[i]); | |
389 | } | |
390 | ||
b8806324 SX |
391 | static void ocrdma_init_ipv4_gids(struct ocrdma_dev *dev, |
392 | struct net_device *net) | |
393 | { | |
394 | struct in_device *in_dev; | |
395 | union ib_gid gid; | |
396 | in_dev = in_dev_get(net); | |
397 | if (in_dev) { | |
398 | for_ifa(in_dev) { | |
399 | ipv6_addr_set_v4mapped(ifa->ifa_address, | |
400 | (struct in6_addr *)&gid); | |
401 | ocrdma_add_sgid(dev, &gid); | |
402 | } | |
403 | endfor_ifa(in_dev); | |
404 | in_dev_put(in_dev); | |
405 | } | |
406 | } | |
407 | ||
408 | static void ocrdma_init_ipv6_gids(struct ocrdma_dev *dev, | |
409 | struct net_device *net) | |
410 | { | |
411 | #if IS_ENABLED(CONFIG_IPV6) | |
412 | struct inet6_dev *in6_dev; | |
413 | union ib_gid *pgid; | |
414 | struct inet6_ifaddr *ifp; | |
415 | in6_dev = in6_dev_get(net); | |
416 | if (in6_dev) { | |
417 | read_lock_bh(&in6_dev->lock); | |
418 | list_for_each_entry(ifp, &in6_dev->addr_list, if_list) { | |
419 | pgid = (union ib_gid *)&ifp->addr; | |
420 | ocrdma_add_sgid(dev, pgid); | |
421 | } | |
422 | read_unlock_bh(&in6_dev->lock); | |
423 | in6_dev_put(in6_dev); | |
424 | } | |
425 | #endif | |
426 | } | |
427 | ||
428 | static void ocrdma_init_gid_table(struct ocrdma_dev *dev) | |
429 | { | |
430 | struct net_device *net_dev; | |
431 | ||
432 | for_each_netdev(&init_net, net_dev) { | |
433 | struct net_device *real_dev = rdma_vlan_dev_real_dev(net_dev) ? | |
434 | rdma_vlan_dev_real_dev(net_dev) : net_dev; | |
435 | ||
436 | if (real_dev == dev->nic_info.netdev) { | |
437 | ocrdma_init_ipv4_gids(dev, net_dev); | |
438 | ocrdma_init_ipv6_gids(dev, net_dev); | |
439 | } | |
440 | } | |
441 | } | |
442 | ||
fe2caefc PP |
443 | static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info) |
444 | { | |
334b8db3 | 445 | int status = 0, i; |
fe2caefc PP |
446 | struct ocrdma_dev *dev; |
447 | ||
448 | dev = (struct ocrdma_dev *)ib_alloc_device(sizeof(struct ocrdma_dev)); | |
449 | if (!dev) { | |
ef99c4c2 | 450 | pr_err("Unable to allocate ib device\n"); |
fe2caefc PP |
451 | return NULL; |
452 | } | |
453 | dev->mbx_cmd = kzalloc(sizeof(struct ocrdma_mqe_emb_cmd), GFP_KERNEL); | |
454 | if (!dev->mbx_cmd) | |
455 | goto idr_err; | |
456 | ||
457 | memcpy(&dev->nic_info, dev_info, sizeof(*dev_info)); | |
cffcd59f | 458 | dev->id = idr_alloc(&ocrdma_dev_id, NULL, 0, 0, GFP_KERNEL); |
fe2caefc PP |
459 | if (dev->id < 0) |
460 | goto idr_err; | |
461 | ||
462 | status = ocrdma_init_hw(dev); | |
463 | if (status) | |
464 | goto init_err; | |
465 | ||
466 | status = ocrdma_alloc_resources(dev); | |
467 | if (status) | |
468 | goto alloc_err; | |
469 | ||
31dbdd9a | 470 | ocrdma_init_service_level(dev); |
b8806324 | 471 | ocrdma_init_gid_table(dev); |
fe2caefc PP |
472 | status = ocrdma_register_device(dev); |
473 | if (status) | |
474 | goto alloc_err; | |
475 | ||
334b8db3 SX |
476 | for (i = 0; i < ARRAY_SIZE(ocrdma_attributes); i++) |
477 | if (device_create_file(&dev->ibdev.dev, ocrdma_attributes[i])) | |
478 | goto sysfs_err; | |
3e4d60a8 SL |
479 | spin_lock(&ocrdma_devlist_lock); |
480 | list_add_tail_rcu(&dev->entry, &ocrdma_dev_list); | |
481 | spin_unlock(&ocrdma_devlist_lock); | |
a51f06e1 SX |
482 | /* Init stats */ |
483 | ocrdma_add_port_stats(dev); | |
484 | ||
485 | pr_info("%s %s: %s \"%s\" port %d\n", | |
486 | dev_name(&dev->nic_info.pdev->dev), hca_name(dev), | |
487 | port_speed_string(dev), dev->model_number, | |
488 | dev->hba_port_num); | |
489 | pr_info("%s ocrdma%d driver loaded successfully\n", | |
490 | dev_name(&dev->nic_info.pdev->dev), dev->id); | |
fe2caefc PP |
491 | return dev; |
492 | ||
334b8db3 SX |
493 | sysfs_err: |
494 | ocrdma_remove_sysfiles(dev); | |
fe2caefc PP |
495 | alloc_err: |
496 | ocrdma_free_resources(dev); | |
497 | ocrdma_cleanup_hw(dev); | |
498 | init_err: | |
499 | idr_remove(&ocrdma_dev_id, dev->id); | |
500 | idr_err: | |
501 | kfree(dev->mbx_cmd); | |
502 | ib_dealloc_device(&dev->ibdev); | |
ef99c4c2 | 503 | pr_err("%s() leaving. ret=%d\n", __func__, status); |
fe2caefc PP |
504 | return NULL; |
505 | } | |
506 | ||
3e4d60a8 | 507 | static void ocrdma_remove_free(struct rcu_head *rcu) |
fe2caefc | 508 | { |
3e4d60a8 | 509 | struct ocrdma_dev *dev = container_of(rcu, struct ocrdma_dev, rcu); |
fe2caefc | 510 | |
fe2caefc PP |
511 | idr_remove(&ocrdma_dev_id, dev->id); |
512 | kfree(dev->mbx_cmd); | |
513 | ib_dealloc_device(&dev->ibdev); | |
514 | } | |
515 | ||
3e4d60a8 SL |
516 | static void ocrdma_remove(struct ocrdma_dev *dev) |
517 | { | |
518 | /* first unregister with stack to stop all the active traffic | |
519 | * of the registered clients. | |
520 | */ | |
a51f06e1 | 521 | ocrdma_rem_port_stats(dev); |
334b8db3 SX |
522 | ocrdma_remove_sysfiles(dev); |
523 | ||
3e4d60a8 SL |
524 | ib_unregister_device(&dev->ibdev); |
525 | ||
526 | spin_lock(&ocrdma_devlist_lock); | |
527 | list_del_rcu(&dev->entry); | |
528 | spin_unlock(&ocrdma_devlist_lock); | |
1852d1da NG |
529 | |
530 | ocrdma_free_resources(dev); | |
531 | ocrdma_cleanup_hw(dev); | |
532 | ||
3e4d60a8 SL |
533 | call_rcu(&dev->rcu, ocrdma_remove_free); |
534 | } | |
535 | ||
fe2caefc PP |
536 | static int ocrdma_open(struct ocrdma_dev *dev) |
537 | { | |
538 | struct ib_event port_event; | |
539 | ||
540 | port_event.event = IB_EVENT_PORT_ACTIVE; | |
541 | port_event.element.port_num = 1; | |
542 | port_event.device = &dev->ibdev; | |
543 | ib_dispatch_event(&port_event); | |
544 | return 0; | |
545 | } | |
546 | ||
547 | static int ocrdma_close(struct ocrdma_dev *dev) | |
548 | { | |
549 | int i; | |
550 | struct ocrdma_qp *qp, **cur_qp; | |
551 | struct ib_event err_event; | |
552 | struct ib_qp_attr attrs; | |
553 | int attr_mask = IB_QP_STATE; | |
554 | ||
555 | attrs.qp_state = IB_QPS_ERR; | |
556 | mutex_lock(&dev->dev_lock); | |
557 | if (dev->qp_tbl) { | |
558 | cur_qp = dev->qp_tbl; | |
559 | for (i = 0; i < OCRDMA_MAX_QP; i++) { | |
560 | qp = cur_qp[i]; | |
fad51b7d | 561 | if (qp && qp->ibqp.qp_type != IB_QPT_GSI) { |
fe2caefc PP |
562 | /* change the QP state to ERROR */ |
563 | _ocrdma_modify_qp(&qp->ibqp, &attrs, attr_mask); | |
564 | ||
565 | err_event.event = IB_EVENT_QP_FATAL; | |
566 | err_event.element.qp = &qp->ibqp; | |
567 | err_event.device = &dev->ibdev; | |
568 | ib_dispatch_event(&err_event); | |
569 | } | |
570 | } | |
571 | } | |
572 | mutex_unlock(&dev->dev_lock); | |
573 | ||
574 | err_event.event = IB_EVENT_PORT_ERR; | |
575 | err_event.element.port_num = 1; | |
576 | err_event.device = &dev->ibdev; | |
577 | ib_dispatch_event(&err_event); | |
578 | return 0; | |
579 | } | |
580 | ||
efe45937 DS |
581 | static void ocrdma_shutdown(struct ocrdma_dev *dev) |
582 | { | |
583 | ocrdma_close(dev); | |
584 | ocrdma_remove(dev); | |
585 | } | |
586 | ||
fe2caefc PP |
587 | /* event handling via NIC driver ensures that all the NIC specific |
588 | * initialization done before RoCE driver notifies | |
589 | * event to stack. | |
590 | */ | |
591 | static void ocrdma_event_handler(struct ocrdma_dev *dev, u32 event) | |
592 | { | |
593 | switch (event) { | |
594 | case BE_DEV_UP: | |
595 | ocrdma_open(dev); | |
596 | break; | |
597 | case BE_DEV_DOWN: | |
598 | ocrdma_close(dev); | |
599 | break; | |
efe45937 DS |
600 | case BE_DEV_SHUTDOWN: |
601 | ocrdma_shutdown(dev); | |
602 | break; | |
2b50176d | 603 | } |
fe2caefc PP |
604 | } |
605 | ||
abe3afac | 606 | static struct ocrdma_driver ocrdma_drv = { |
fe2caefc PP |
607 | .name = "ocrdma_driver", |
608 | .add = ocrdma_add, | |
609 | .remove = ocrdma_remove, | |
610 | .state_change_handler = ocrdma_event_handler, | |
b6b87d2e | 611 | .be_abi_version = OCRDMA_BE_ROCE_ABI_VERSION, |
fe2caefc PP |
612 | }; |
613 | ||
34955669 RD |
614 | static void ocrdma_unregister_inet6addr_notifier(void) |
615 | { | |
d90f9b35 | 616 | #if IS_ENABLED(CONFIG_IPV6) |
34955669 RD |
617 | unregister_inet6addr_notifier(&ocrdma_inet6addr_notifier); |
618 | #endif | |
619 | } | |
620 | ||
2d8f57d5 SX |
621 | static void ocrdma_unregister_inetaddr_notifier(void) |
622 | { | |
623 | unregister_inetaddr_notifier(&ocrdma_inetaddr_notifier); | |
624 | } | |
625 | ||
fe2caefc PP |
626 | static int __init ocrdma_init_module(void) |
627 | { | |
628 | int status; | |
629 | ||
a51f06e1 SX |
630 | ocrdma_init_debugfs(); |
631 | ||
37721d85 MS |
632 | status = register_inetaddr_notifier(&ocrdma_inetaddr_notifier); |
633 | if (status) | |
634 | return status; | |
635 | ||
d90f9b35 | 636 | #if IS_ENABLED(CONFIG_IPV6) |
fe2caefc PP |
637 | status = register_inet6addr_notifier(&ocrdma_inet6addr_notifier); |
638 | if (status) | |
2d8f57d5 | 639 | goto err_notifier6; |
34955669 RD |
640 | #endif |
641 | ||
fe2caefc PP |
642 | status = be_roce_register_driver(&ocrdma_drv); |
643 | if (status) | |
2d8f57d5 | 644 | goto err_be_reg; |
34955669 | 645 | |
2d8f57d5 SX |
646 | return 0; |
647 | ||
648 | err_be_reg: | |
649 | ocrdma_unregister_inet6addr_notifier(); | |
650 | err_notifier6: | |
651 | ocrdma_unregister_inetaddr_notifier(); | |
fe2caefc PP |
652 | return status; |
653 | } | |
654 | ||
655 | static void __exit ocrdma_exit_module(void) | |
656 | { | |
657 | be_roce_unregister_driver(&ocrdma_drv); | |
34955669 | 658 | ocrdma_unregister_inet6addr_notifier(); |
2d8f57d5 | 659 | ocrdma_unregister_inetaddr_notifier(); |
a51f06e1 | 660 | ocrdma_rem_debugfs(); |
fe2caefc PP |
661 | } |
662 | ||
663 | module_init(ocrdma_init_module); | |
664 | module_exit(ocrdma_exit_module); |