diff options
author | Upinder Malhi <umalhi@cisco.com> | 2014-01-09 17:48:17 -0500 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2014-01-14 03:44:44 -0500 |
commit | c7845bcafe4d2ecd5c479fa64d1b425c21dde17c (patch) | |
tree | 14661c7eb6d065bb2bb66c7e199d2c5821e1745c /drivers/infiniband | |
parent | 6214105460842759020bdd7f4dbb50afa1be9d17 (diff) |
IB/usnic: Add UDP support in u*verbs.c, u*main.c and u*util.h
Add supports for:
1) Parsing the socket file descriptor pass down from userspace.
2) IP notifiers
3) Encoding the IP in the GID
4) Other aux. changes to support UDP
Signed-off-by: Upinder Malhi <umalhi@cisco.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/hw/usnic/usnic_common_util.h | 17 | ||||
-rw-r--r-- | drivers/infiniband/hw/usnic/usnic_ib_main.c | 84 | ||||
-rw-r--r-- | drivers/infiniband/hw/usnic/usnic_ib_verbs.c | 44 |
3 files changed, 136 insertions, 9 deletions
diff --git a/drivers/infiniband/hw/usnic/usnic_common_util.h b/drivers/infiniband/hw/usnic/usnic_common_util.h index 128550a4f9e2..afd8bfa379ed 100644 --- a/drivers/infiniband/hw/usnic/usnic_common_util.h +++ b/drivers/infiniband/hw/usnic/usnic_common_util.h | |||
@@ -36,6 +36,23 @@ usnic_mac_to_gid(const char *const mac, char *raw_gid) | |||
36 | } | 36 | } |
37 | 37 | ||
38 | static inline void | 38 | static inline void |
39 | usnic_mac_ip_to_gid(const char *const mac, const uint32_t inaddr, char *raw_gid) | ||
40 | { | ||
41 | raw_gid[0] = 0xfe; | ||
42 | raw_gid[1] = 0x80; | ||
43 | memset(&raw_gid[2], 0, 2); | ||
44 | memcpy(&raw_gid[4], &inaddr, 4); | ||
45 | raw_gid[8] = mac[0]^2; | ||
46 | raw_gid[9] = mac[1]; | ||
47 | raw_gid[10] = mac[2]; | ||
48 | raw_gid[11] = 0xff; | ||
49 | raw_gid[12] = 0xfe; | ||
50 | raw_gid[13] = mac[3]; | ||
51 | raw_gid[14] = mac[4]; | ||
52 | raw_gid[15] = mac[5]; | ||
53 | } | ||
54 | |||
55 | static inline void | ||
39 | usnic_write_gid_if_id_from_mac(char *mac, char *raw_gid) | 56 | usnic_write_gid_if_id_from_mac(char *mac, char *raw_gid) |
40 | { | 57 | { |
41 | raw_gid[8] = mac[0]^2; | 58 | raw_gid[8] = mac[0]^2; |
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c index 6ab0b41be9c5..3b7e8bd22df6 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_main.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c | |||
@@ -25,6 +25,7 @@ | |||
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/inetdevice.h> | ||
28 | #include <linux/init.h> | 29 | #include <linux/init.h> |
29 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
30 | #include <linux/errno.h> | 31 | #include <linux/errno.h> |
@@ -236,13 +237,79 @@ static struct notifier_block usnic_ib_netdevice_notifier = { | |||
236 | }; | 237 | }; |
237 | /* End of netdev section */ | 238 | /* End of netdev section */ |
238 | 239 | ||
240 | /* Start of inet section */ | ||
241 | static int usnic_ib_handle_inet_event(struct usnic_ib_dev *us_ibdev, | ||
242 | unsigned long event, void *ptr) | ||
243 | { | ||
244 | struct in_ifaddr *ifa = ptr; | ||
245 | struct ib_event ib_event; | ||
246 | |||
247 | mutex_lock(&us_ibdev->usdev_lock); | ||
248 | |||
249 | switch (event) { | ||
250 | case NETDEV_DOWN: | ||
251 | usnic_info("%s via ip notifiers", | ||
252 | usnic_ib_netdev_event_to_string(event)); | ||
253 | usnic_fwd_del_ipaddr(us_ibdev->ufdev); | ||
254 | usnic_ib_qp_grp_modify_active_to_err(us_ibdev); | ||
255 | ib_event.event = IB_EVENT_GID_CHANGE; | ||
256 | ib_event.device = &us_ibdev->ib_dev; | ||
257 | ib_event.element.port_num = 1; | ||
258 | ib_dispatch_event(&ib_event); | ||
259 | break; | ||
260 | case NETDEV_UP: | ||
261 | usnic_fwd_add_ipaddr(us_ibdev->ufdev, ifa->ifa_address); | ||
262 | usnic_info("%s via ip notifiers: ip %pI4", | ||
263 | usnic_ib_netdev_event_to_string(event), | ||
264 | &us_ibdev->ufdev->inaddr); | ||
265 | ib_event.event = IB_EVENT_GID_CHANGE; | ||
266 | ib_event.device = &us_ibdev->ib_dev; | ||
267 | ib_event.element.port_num = 1; | ||
268 | ib_dispatch_event(&ib_event); | ||
269 | break; | ||
270 | default: | ||
271 | usnic_info("Ignorning event %s on %s", | ||
272 | usnic_ib_netdev_event_to_string(event), | ||
273 | us_ibdev->ib_dev.name); | ||
274 | } | ||
275 | mutex_unlock(&us_ibdev->usdev_lock); | ||
276 | |||
277 | return NOTIFY_DONE; | ||
278 | } | ||
279 | |||
280 | static int usnic_ib_inetaddr_event(struct notifier_block *notifier, | ||
281 | unsigned long event, void *ptr) | ||
282 | { | ||
283 | struct usnic_ib_dev *us_ibdev; | ||
284 | struct in_ifaddr *ifa = ptr; | ||
285 | struct net_device *netdev = ifa->ifa_dev->dev; | ||
286 | |||
287 | mutex_lock(&usnic_ib_ibdev_list_lock); | ||
288 | list_for_each_entry(us_ibdev, &usnic_ib_ibdev_list, ib_dev_link) { | ||
289 | if (us_ibdev->netdev == netdev) { | ||
290 | usnic_ib_handle_inet_event(us_ibdev, event, ptr); | ||
291 | break; | ||
292 | } | ||
293 | } | ||
294 | mutex_unlock(&usnic_ib_ibdev_list_lock); | ||
295 | |||
296 | return NOTIFY_DONE; | ||
297 | } | ||
298 | static struct notifier_block usnic_ib_inetaddr_notifier = { | ||
299 | .notifier_call = usnic_ib_inetaddr_event | ||
300 | }; | ||
301 | /* End of inet section*/ | ||
302 | |||
239 | /* Start of PF discovery section */ | 303 | /* Start of PF discovery section */ |
240 | static void *usnic_ib_device_add(struct pci_dev *dev) | 304 | static void *usnic_ib_device_add(struct pci_dev *dev) |
241 | { | 305 | { |
242 | struct usnic_ib_dev *us_ibdev; | 306 | struct usnic_ib_dev *us_ibdev; |
243 | union ib_gid gid; | 307 | union ib_gid gid; |
308 | struct in_ifaddr *in; | ||
309 | struct net_device *netdev; | ||
244 | 310 | ||
245 | usnic_dbg("\n"); | 311 | usnic_dbg("\n"); |
312 | netdev = pci_get_drvdata(dev); | ||
246 | 313 | ||
247 | us_ibdev = (struct usnic_ib_dev *)ib_alloc_device(sizeof(*us_ibdev)); | 314 | us_ibdev = (struct usnic_ib_dev *)ib_alloc_device(sizeof(*us_ibdev)); |
248 | if (IS_ERR_OR_NULL(us_ibdev)) { | 315 | if (IS_ERR_OR_NULL(us_ibdev)) { |
@@ -326,6 +393,12 @@ static void *usnic_ib_device_add(struct pci_dev *dev) | |||
326 | if (netif_carrier_ok(us_ibdev->netdev)) | 393 | if (netif_carrier_ok(us_ibdev->netdev)) |
327 | usnic_fwd_carrier_up(us_ibdev->ufdev); | 394 | usnic_fwd_carrier_up(us_ibdev->ufdev); |
328 | 395 | ||
396 | in = ((struct in_device *)(netdev->ip_ptr))->ifa_list; | ||
397 | if (in != NULL) | ||
398 | usnic_fwd_add_ipaddr(us_ibdev->ufdev, in->ifa_address); | ||
399 | |||
400 | usnic_mac_ip_to_gid(us_ibdev->netdev->perm_addr, | ||
401 | us_ibdev->ufdev->inaddr, &gid.raw[0]); | ||
329 | memcpy(&us_ibdev->ib_dev.node_guid, &gid.global.interface_id, | 402 | memcpy(&us_ibdev->ib_dev.node_guid, &gid.global.interface_id, |
330 | sizeof(gid.global.interface_id)); | 403 | sizeof(gid.global.interface_id)); |
331 | kref_init(&us_ibdev->vf_cnt); | 404 | kref_init(&us_ibdev->vf_cnt); |
@@ -555,16 +628,24 @@ static int __init usnic_ib_init(void) | |||
555 | goto out_pci_unreg; | 628 | goto out_pci_unreg; |
556 | } | 629 | } |
557 | 630 | ||
631 | err = register_inetaddr_notifier(&usnic_ib_inetaddr_notifier); | ||
632 | if (err) { | ||
633 | usnic_err("Failed to register inet addr notifier\n"); | ||
634 | goto out_unreg_netdev_notifier; | ||
635 | } | ||
636 | |||
558 | err = usnic_transport_init(); | 637 | err = usnic_transport_init(); |
559 | if (err) { | 638 | if (err) { |
560 | usnic_err("Failed to initialize transport\n"); | 639 | usnic_err("Failed to initialize transport\n"); |
561 | goto out_unreg_netdev_notifier; | 640 | goto out_unreg_inetaddr_notifier; |
562 | } | 641 | } |
563 | 642 | ||
564 | usnic_debugfs_init(); | 643 | usnic_debugfs_init(); |
565 | 644 | ||
566 | return 0; | 645 | return 0; |
567 | 646 | ||
647 | out_unreg_inetaddr_notifier: | ||
648 | unregister_inetaddr_notifier(&usnic_ib_inetaddr_notifier); | ||
568 | out_unreg_netdev_notifier: | 649 | out_unreg_netdev_notifier: |
569 | unregister_netdevice_notifier(&usnic_ib_netdevice_notifier); | 650 | unregister_netdevice_notifier(&usnic_ib_netdevice_notifier); |
570 | out_pci_unreg: | 651 | out_pci_unreg: |
@@ -580,6 +661,7 @@ static void __exit usnic_ib_destroy(void) | |||
580 | usnic_dbg("\n"); | 661 | usnic_dbg("\n"); |
581 | usnic_debugfs_exit(); | 662 | usnic_debugfs_exit(); |
582 | usnic_transport_fini(); | 663 | usnic_transport_fini(); |
664 | unregister_inetaddr_notifier(&usnic_ib_inetaddr_notifier); | ||
583 | unregister_netdevice_notifier(&usnic_ib_netdevice_notifier); | 665 | unregister_netdevice_notifier(&usnic_ib_netdevice_notifier); |
584 | pci_unregister_driver(&usnic_ib_pci_driver); | 666 | pci_unregister_driver(&usnic_ib_pci_driver); |
585 | usnic_uiom_fini(); | 667 | usnic_uiom_fini(); |
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c index 2217bc0a6bbe..937113f2eeec 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c | |||
@@ -230,6 +230,15 @@ static void eth_speed_to_ib_speed(int speed, u8 *active_speed, | |||
230 | } | 230 | } |
231 | } | 231 | } |
232 | 232 | ||
233 | static int create_qp_validate_user_data(struct usnic_ib_create_qp_cmd cmd) | ||
234 | { | ||
235 | if (cmd.spec.trans_type <= USNIC_TRANSPORT_UNKNOWN || | ||
236 | cmd.spec.trans_type >= USNIC_TRANSPORT_MAX) | ||
237 | return -EINVAL; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
233 | /* Start of ib callback functions */ | 242 | /* Start of ib callback functions */ |
234 | 243 | ||
235 | enum rdma_link_layer usnic_ib_port_link_layer(struct ib_device *device, | 244 | enum rdma_link_layer usnic_ib_port_link_layer(struct ib_device *device, |
@@ -252,7 +261,8 @@ int usnic_ib_query_device(struct ib_device *ibdev, | |||
252 | us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info); | 261 | us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info); |
253 | us_ibdev->netdev->ethtool_ops->get_settings(us_ibdev->netdev, &cmd); | 262 | us_ibdev->netdev->ethtool_ops->get_settings(us_ibdev->netdev, &cmd); |
254 | memset(props, 0, sizeof(*props)); | 263 | memset(props, 0, sizeof(*props)); |
255 | usnic_mac_to_gid(us_ibdev->ufdev->mac, &gid.raw[0]); | 264 | usnic_mac_ip_to_gid(us_ibdev->ufdev->mac, us_ibdev->ufdev->inaddr, |
265 | &gid.raw[0]); | ||
256 | memcpy(&props->sys_image_guid, &gid.global.interface_id, | 266 | memcpy(&props->sys_image_guid, &gid.global.interface_id, |
257 | sizeof(gid.global.interface_id)); | 267 | sizeof(gid.global.interface_id)); |
258 | usnic_ib_fw_string_to_u64(&info.fw_version[0], &props->fw_ver); | 268 | usnic_ib_fw_string_to_u64(&info.fw_version[0], &props->fw_ver); |
@@ -310,12 +320,15 @@ int usnic_ib_query_port(struct ib_device *ibdev, u8 port, | |||
310 | props->sm_lid = 0; | 320 | props->sm_lid = 0; |
311 | props->sm_sl = 0; | 321 | props->sm_sl = 0; |
312 | 322 | ||
313 | if (us_ibdev->ufdev->link_up) { | 323 | if (!us_ibdev->ufdev->link_up) { |
314 | props->state = IB_PORT_ACTIVE; | ||
315 | props->phys_state = 5; | ||
316 | } else { | ||
317 | props->state = IB_PORT_DOWN; | 324 | props->state = IB_PORT_DOWN; |
318 | props->phys_state = 3; | 325 | props->phys_state = 3; |
326 | } else if (!us_ibdev->ufdev->inaddr) { | ||
327 | props->state = IB_PORT_INIT; | ||
328 | props->phys_state = 4; | ||
329 | } else { | ||
330 | props->state = IB_PORT_ACTIVE; | ||
331 | props->phys_state = 5; | ||
319 | } | 332 | } |
320 | 333 | ||
321 | props->port_cap_flags = 0; | 334 | props->port_cap_flags = 0; |
@@ -385,7 +398,8 @@ int usnic_ib_query_gid(struct ib_device *ibdev, u8 port, int index, | |||
385 | 398 | ||
386 | mutex_lock(&us_ibdev->usdev_lock); | 399 | mutex_lock(&us_ibdev->usdev_lock); |
387 | memset(&(gid->raw[0]), 0, sizeof(gid->raw)); | 400 | memset(&(gid->raw[0]), 0, sizeof(gid->raw)); |
388 | usnic_mac_to_gid(us_ibdev->ufdev->mac, &gid->raw[0]); | 401 | usnic_mac_ip_to_gid(us_ibdev->ufdev->mac, us_ibdev->ufdev->inaddr, |
402 | &gid->raw[0]); | ||
389 | mutex_unlock(&us_ibdev->usdev_lock); | 403 | mutex_unlock(&us_ibdev->usdev_lock); |
390 | 404 | ||
391 | return 0; | 405 | return 0; |
@@ -444,6 +458,7 @@ struct ib_qp *usnic_ib_create_qp(struct ib_pd *pd, | |||
444 | struct usnic_ib_ucontext *ucontext; | 458 | struct usnic_ib_ucontext *ucontext; |
445 | int cq_cnt; | 459 | int cq_cnt; |
446 | struct usnic_vnic_res_spec res_spec; | 460 | struct usnic_vnic_res_spec res_spec; |
461 | struct usnic_ib_create_qp_cmd cmd; | ||
447 | struct usnic_transport_spec trans_spec; | 462 | struct usnic_transport_spec trans_spec; |
448 | 463 | ||
449 | usnic_dbg("\n"); | 464 | usnic_dbg("\n"); |
@@ -451,14 +466,27 @@ struct ib_qp *usnic_ib_create_qp(struct ib_pd *pd, | |||
451 | ucontext = to_uucontext(pd->uobject->context); | 466 | ucontext = to_uucontext(pd->uobject->context); |
452 | us_ibdev = to_usdev(pd->device); | 467 | us_ibdev = to_usdev(pd->device); |
453 | 468 | ||
469 | err = ib_copy_from_udata(&cmd, udata, sizeof(cmd)); | ||
470 | if (err) { | ||
471 | usnic_err("%s: cannot copy udata for create_qp\n", | ||
472 | us_ibdev->ib_dev.name); | ||
473 | return ERR_PTR(-EINVAL); | ||
474 | } | ||
475 | |||
476 | err = create_qp_validate_user_data(cmd); | ||
477 | if (err) { | ||
478 | usnic_err("%s: Failed to validate user data\n", | ||
479 | us_ibdev->ib_dev.name); | ||
480 | return ERR_PTR(-EINVAL); | ||
481 | } | ||
482 | |||
454 | if (init_attr->qp_type != IB_QPT_UD) { | 483 | if (init_attr->qp_type != IB_QPT_UD) { |
455 | usnic_err("%s asked to make a non-UD QP: %d\n", | 484 | usnic_err("%s asked to make a non-UD QP: %d\n", |
456 | us_ibdev->ib_dev.name, init_attr->qp_type); | 485 | us_ibdev->ib_dev.name, init_attr->qp_type); |
457 | return ERR_PTR(-EINVAL); | 486 | return ERR_PTR(-EINVAL); |
458 | } | 487 | } |
459 | 488 | ||
460 | memset(&trans_spec, 0, sizeof(trans_spec)); | 489 | trans_spec = cmd.spec; |
461 | trans_spec.trans_type = USNIC_TRANSPORT_ROCE_CUSTOM; | ||
462 | mutex_lock(&us_ibdev->usdev_lock); | 490 | mutex_lock(&us_ibdev->usdev_lock); |
463 | cq_cnt = (init_attr->send_cq == init_attr->recv_cq) ? 1 : 2; | 491 | cq_cnt = (init_attr->send_cq == init_attr->recv_cq) ? 1 : 2; |
464 | res_spec = min_transport_spec[trans_spec.trans_type]; | 492 | res_spec = min_transport_spec[trans_spec.trans_type]; |