diff options
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib.h | 17 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_ib.c | 42 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_main.c | 44 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_verbs.c | 18 |
4 files changed, 91 insertions, 30 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 2c522572e3c5..bb19587c5eaf 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h | |||
@@ -54,6 +54,12 @@ | |||
54 | 54 | ||
55 | /* constants */ | 55 | /* constants */ |
56 | 56 | ||
57 | enum ipoib_flush_level { | ||
58 | IPOIB_FLUSH_LIGHT, | ||
59 | IPOIB_FLUSH_NORMAL, | ||
60 | IPOIB_FLUSH_HEAVY | ||
61 | }; | ||
62 | |||
57 | enum { | 63 | enum { |
58 | IPOIB_ENCAP_LEN = 4, | 64 | IPOIB_ENCAP_LEN = 4, |
59 | 65 | ||
@@ -284,10 +290,11 @@ struct ipoib_dev_priv { | |||
284 | 290 | ||
285 | struct delayed_work pkey_poll_task; | 291 | struct delayed_work pkey_poll_task; |
286 | struct delayed_work mcast_task; | 292 | struct delayed_work mcast_task; |
287 | struct work_struct flush_task; | 293 | struct work_struct flush_light; |
294 | struct work_struct flush_normal; | ||
295 | struct work_struct flush_heavy; | ||
288 | struct work_struct restart_task; | 296 | struct work_struct restart_task; |
289 | struct delayed_work ah_reap_task; | 297 | struct delayed_work ah_reap_task; |
290 | struct work_struct pkey_event_task; | ||
291 | 298 | ||
292 | struct ib_device *ca; | 299 | struct ib_device *ca; |
293 | u8 port; | 300 | u8 port; |
@@ -369,6 +376,7 @@ struct ipoib_path { | |||
369 | 376 | ||
370 | struct rb_node rb_node; | 377 | struct rb_node rb_node; |
371 | struct list_head list; | 378 | struct list_head list; |
379 | int valid; | ||
372 | }; | 380 | }; |
373 | 381 | ||
374 | struct ipoib_neigh { | 382 | struct ipoib_neigh { |
@@ -433,11 +441,14 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, | |||
433 | struct ipoib_ah *address, u32 qpn); | 441 | struct ipoib_ah *address, u32 qpn); |
434 | void ipoib_reap_ah(struct work_struct *work); | 442 | void ipoib_reap_ah(struct work_struct *work); |
435 | 443 | ||
444 | void ipoib_mark_paths_invalid(struct net_device *dev); | ||
436 | void ipoib_flush_paths(struct net_device *dev); | 445 | void ipoib_flush_paths(struct net_device *dev); |
437 | struct ipoib_dev_priv *ipoib_intf_alloc(const char *format); | 446 | struct ipoib_dev_priv *ipoib_intf_alloc(const char *format); |
438 | 447 | ||
439 | int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port); | 448 | int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port); |
440 | void ipoib_ib_dev_flush(struct work_struct *work); | 449 | void ipoib_ib_dev_flush_light(struct work_struct *work); |
450 | void ipoib_ib_dev_flush_normal(struct work_struct *work); | ||
451 | void ipoib_ib_dev_flush_heavy(struct work_struct *work); | ||
441 | void ipoib_pkey_event(struct work_struct *work); | 452 | void ipoib_pkey_event(struct work_struct *work); |
442 | void ipoib_ib_dev_cleanup(struct net_device *dev); | 453 | void ipoib_ib_dev_cleanup(struct net_device *dev); |
443 | 454 | ||
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 5d50e5261eed..66cafa20c246 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c | |||
@@ -902,7 +902,8 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port) | |||
902 | return 0; | 902 | return 0; |
903 | } | 903 | } |
904 | 904 | ||
905 | static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, int pkey_event) | 905 | static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, |
906 | enum ipoib_flush_level level) | ||
906 | { | 907 | { |
907 | struct ipoib_dev_priv *cpriv; | 908 | struct ipoib_dev_priv *cpriv; |
908 | struct net_device *dev = priv->dev; | 909 | struct net_device *dev = priv->dev; |
@@ -915,7 +916,7 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, int pkey_event) | |||
915 | * the parent is down. | 916 | * the parent is down. |
916 | */ | 917 | */ |
917 | list_for_each_entry(cpriv, &priv->child_intfs, list) | 918 | list_for_each_entry(cpriv, &priv->child_intfs, list) |
918 | __ipoib_ib_dev_flush(cpriv, pkey_event); | 919 | __ipoib_ib_dev_flush(cpriv, level); |
919 | 920 | ||
920 | mutex_unlock(&priv->vlan_mutex); | 921 | mutex_unlock(&priv->vlan_mutex); |
921 | 922 | ||
@@ -929,7 +930,7 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, int pkey_event) | |||
929 | return; | 930 | return; |
930 | } | 931 | } |
931 | 932 | ||
932 | if (pkey_event) { | 933 | if (level == IPOIB_FLUSH_HEAVY) { |
933 | if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) { | 934 | if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) { |
934 | clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); | 935 | clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); |
935 | ipoib_ib_dev_down(dev, 0); | 936 | ipoib_ib_dev_down(dev, 0); |
@@ -947,11 +948,15 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, int pkey_event) | |||
947 | priv->pkey_index = new_index; | 948 | priv->pkey_index = new_index; |
948 | } | 949 | } |
949 | 950 | ||
950 | ipoib_dbg(priv, "flushing\n"); | 951 | if (level == IPOIB_FLUSH_LIGHT) { |
952 | ipoib_mark_paths_invalid(dev); | ||
953 | ipoib_mcast_dev_flush(dev); | ||
954 | } | ||
951 | 955 | ||
952 | ipoib_ib_dev_down(dev, 0); | 956 | if (level >= IPOIB_FLUSH_NORMAL) |
957 | ipoib_ib_dev_down(dev, 0); | ||
953 | 958 | ||
954 | if (pkey_event) { | 959 | if (level == IPOIB_FLUSH_HEAVY) { |
955 | ipoib_ib_dev_stop(dev, 0); | 960 | ipoib_ib_dev_stop(dev, 0); |
956 | ipoib_ib_dev_open(dev); | 961 | ipoib_ib_dev_open(dev); |
957 | } | 962 | } |
@@ -961,27 +966,34 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, int pkey_event) | |||
961 | * we get here, don't bring it back up if it's not configured up | 966 | * we get here, don't bring it back up if it's not configured up |
962 | */ | 967 | */ |
963 | if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) { | 968 | if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) { |
964 | ipoib_ib_dev_up(dev); | 969 | if (level >= IPOIB_FLUSH_NORMAL) |
970 | ipoib_ib_dev_up(dev); | ||
965 | ipoib_mcast_restart_task(&priv->restart_task); | 971 | ipoib_mcast_restart_task(&priv->restart_task); |
966 | } | 972 | } |
967 | } | 973 | } |
968 | 974 | ||
969 | void ipoib_ib_dev_flush(struct work_struct *work) | 975 | void ipoib_ib_dev_flush_light(struct work_struct *work) |
976 | { | ||
977 | struct ipoib_dev_priv *priv = | ||
978 | container_of(work, struct ipoib_dev_priv, flush_light); | ||
979 | |||
980 | __ipoib_ib_dev_flush(priv, IPOIB_FLUSH_LIGHT); | ||
981 | } | ||
982 | |||
983 | void ipoib_ib_dev_flush_normal(struct work_struct *work) | ||
970 | { | 984 | { |
971 | struct ipoib_dev_priv *priv = | 985 | struct ipoib_dev_priv *priv = |
972 | container_of(work, struct ipoib_dev_priv, flush_task); | 986 | container_of(work, struct ipoib_dev_priv, flush_normal); |
973 | 987 | ||
974 | ipoib_dbg(priv, "Flushing %s\n", priv->dev->name); | 988 | __ipoib_ib_dev_flush(priv, IPOIB_FLUSH_NORMAL); |
975 | __ipoib_ib_dev_flush(priv, 0); | ||
976 | } | 989 | } |
977 | 990 | ||
978 | void ipoib_pkey_event(struct work_struct *work) | 991 | void ipoib_ib_dev_flush_heavy(struct work_struct *work) |
979 | { | 992 | { |
980 | struct ipoib_dev_priv *priv = | 993 | struct ipoib_dev_priv *priv = |
981 | container_of(work, struct ipoib_dev_priv, pkey_event_task); | 994 | container_of(work, struct ipoib_dev_priv, flush_heavy); |
982 | 995 | ||
983 | ipoib_dbg(priv, "Flushing %s and restarting its QP\n", priv->dev->name); | 996 | __ipoib_ib_dev_flush(priv, IPOIB_FLUSH_HEAVY); |
984 | __ipoib_ib_dev_flush(priv, 1); | ||
985 | } | 997 | } |
986 | 998 | ||
987 | void ipoib_ib_dev_cleanup(struct net_device *dev) | 999 | void ipoib_ib_dev_cleanup(struct net_device *dev) |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index fead88f7fb17..b3fd7e8333cf 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c | |||
@@ -357,6 +357,23 @@ void ipoib_path_iter_read(struct ipoib_path_iter *iter, | |||
357 | 357 | ||
358 | #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */ | 358 | #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */ |
359 | 359 | ||
360 | void ipoib_mark_paths_invalid(struct net_device *dev) | ||
361 | { | ||
362 | struct ipoib_dev_priv *priv = netdev_priv(dev); | ||
363 | struct ipoib_path *path, *tp; | ||
364 | |||
365 | spin_lock_irq(&priv->lock); | ||
366 | |||
367 | list_for_each_entry_safe(path, tp, &priv->path_list, list) { | ||
368 | ipoib_dbg(priv, "mark path LID 0x%04x GID " IPOIB_GID_FMT " invalid\n", | ||
369 | be16_to_cpu(path->pathrec.dlid), | ||
370 | IPOIB_GID_ARG(path->pathrec.dgid)); | ||
371 | path->valid = 0; | ||
372 | } | ||
373 | |||
374 | spin_unlock_irq(&priv->lock); | ||
375 | } | ||
376 | |||
360 | void ipoib_flush_paths(struct net_device *dev) | 377 | void ipoib_flush_paths(struct net_device *dev) |
361 | { | 378 | { |
362 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 379 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
@@ -393,6 +410,7 @@ static void path_rec_completion(int status, | |||
393 | struct net_device *dev = path->dev; | 410 | struct net_device *dev = path->dev; |
394 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 411 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
395 | struct ipoib_ah *ah = NULL; | 412 | struct ipoib_ah *ah = NULL; |
413 | struct ipoib_ah *old_ah; | ||
396 | struct ipoib_neigh *neigh, *tn; | 414 | struct ipoib_neigh *neigh, *tn; |
397 | struct sk_buff_head skqueue; | 415 | struct sk_buff_head skqueue; |
398 | struct sk_buff *skb; | 416 | struct sk_buff *skb; |
@@ -416,6 +434,7 @@ static void path_rec_completion(int status, | |||
416 | 434 | ||
417 | spin_lock_irqsave(&priv->lock, flags); | 435 | spin_lock_irqsave(&priv->lock, flags); |
418 | 436 | ||
437 | old_ah = path->ah; | ||
419 | path->ah = ah; | 438 | path->ah = ah; |
420 | 439 | ||
421 | if (ah) { | 440 | if (ah) { |
@@ -428,6 +447,17 @@ static void path_rec_completion(int status, | |||
428 | __skb_queue_tail(&skqueue, skb); | 447 | __skb_queue_tail(&skqueue, skb); |
429 | 448 | ||
430 | list_for_each_entry_safe(neigh, tn, &path->neigh_list, list) { | 449 | list_for_each_entry_safe(neigh, tn, &path->neigh_list, list) { |
450 | if (neigh->ah) { | ||
451 | WARN_ON(neigh->ah != old_ah); | ||
452 | /* | ||
453 | * Dropping the ah reference inside | ||
454 | * priv->lock is safe here, because we | ||
455 | * will hold one more reference from | ||
456 | * the original value of path->ah (ie | ||
457 | * old_ah). | ||
458 | */ | ||
459 | ipoib_put_ah(neigh->ah); | ||
460 | } | ||
431 | kref_get(&path->ah->ref); | 461 | kref_get(&path->ah->ref); |
432 | neigh->ah = path->ah; | 462 | neigh->ah = path->ah; |
433 | memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw, | 463 | memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw, |
@@ -450,6 +480,7 @@ static void path_rec_completion(int status, | |||
450 | while ((skb = __skb_dequeue(&neigh->queue))) | 480 | while ((skb = __skb_dequeue(&neigh->queue))) |
451 | __skb_queue_tail(&skqueue, skb); | 481 | __skb_queue_tail(&skqueue, skb); |
452 | } | 482 | } |
483 | path->valid = 1; | ||
453 | } | 484 | } |
454 | 485 | ||
455 | path->query = NULL; | 486 | path->query = NULL; |
@@ -457,6 +488,9 @@ static void path_rec_completion(int status, | |||
457 | 488 | ||
458 | spin_unlock_irqrestore(&priv->lock, flags); | 489 | spin_unlock_irqrestore(&priv->lock, flags); |
459 | 490 | ||
491 | if (old_ah) | ||
492 | ipoib_put_ah(old_ah); | ||
493 | |||
460 | while ((skb = __skb_dequeue(&skqueue))) { | 494 | while ((skb = __skb_dequeue(&skqueue))) { |
461 | skb->dev = dev; | 495 | skb->dev = dev; |
462 | if (dev_queue_xmit(skb)) | 496 | if (dev_queue_xmit(skb)) |
@@ -630,8 +664,9 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, | |||
630 | spin_lock(&priv->lock); | 664 | spin_lock(&priv->lock); |
631 | 665 | ||
632 | path = __path_find(dev, phdr->hwaddr + 4); | 666 | path = __path_find(dev, phdr->hwaddr + 4); |
633 | if (!path) { | 667 | if (!path || !path->valid) { |
634 | path = path_rec_create(dev, phdr->hwaddr + 4); | 668 | if (!path) |
669 | path = path_rec_create(dev, phdr->hwaddr + 4); | ||
635 | if (path) { | 670 | if (path) { |
636 | /* put pseudoheader back on for next time */ | 671 | /* put pseudoheader back on for next time */ |
637 | skb_push(skb, sizeof *phdr); | 672 | skb_push(skb, sizeof *phdr); |
@@ -1046,9 +1081,10 @@ static void ipoib_setup(struct net_device *dev) | |||
1046 | INIT_LIST_HEAD(&priv->multicast_list); | 1081 | INIT_LIST_HEAD(&priv->multicast_list); |
1047 | 1082 | ||
1048 | INIT_DELAYED_WORK(&priv->pkey_poll_task, ipoib_pkey_poll); | 1083 | INIT_DELAYED_WORK(&priv->pkey_poll_task, ipoib_pkey_poll); |
1049 | INIT_WORK(&priv->pkey_event_task, ipoib_pkey_event); | ||
1050 | INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task); | 1084 | INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task); |
1051 | INIT_WORK(&priv->flush_task, ipoib_ib_dev_flush); | 1085 | INIT_WORK(&priv->flush_light, ipoib_ib_dev_flush_light); |
1086 | INIT_WORK(&priv->flush_normal, ipoib_ib_dev_flush_normal); | ||
1087 | INIT_WORK(&priv->flush_heavy, ipoib_ib_dev_flush_heavy); | ||
1052 | INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task); | 1088 | INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task); |
1053 | INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah); | 1089 | INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah); |
1054 | } | 1090 | } |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 7b8fa36f509b..96f9aa79cbbe 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c | |||
@@ -290,15 +290,17 @@ void ipoib_event(struct ib_event_handler *handler, | |||
290 | if (record->element.port_num != priv->port) | 290 | if (record->element.port_num != priv->port) |
291 | return; | 291 | return; |
292 | 292 | ||
293 | if (record->event == IB_EVENT_PORT_ERR || | 293 | ipoib_dbg(priv, "Event %d on device %s port %d\n", record->event, |
294 | record->event == IB_EVENT_PORT_ACTIVE || | 294 | record->device->name, record->element.port_num); |
295 | record->event == IB_EVENT_LID_CHANGE || | 295 | |
296 | record->event == IB_EVENT_SM_CHANGE || | 296 | if (record->event == IB_EVENT_SM_CHANGE || |
297 | record->event == IB_EVENT_CLIENT_REREGISTER) { | 297 | record->event == IB_EVENT_CLIENT_REREGISTER) { |
298 | ipoib_dbg(priv, "Port state change event\n"); | 298 | queue_work(ipoib_workqueue, &priv->flush_light); |
299 | queue_work(ipoib_workqueue, &priv->flush_task); | 299 | } else if (record->event == IB_EVENT_PORT_ERR || |
300 | record->event == IB_EVENT_PORT_ACTIVE || | ||
301 | record->event == IB_EVENT_LID_CHANGE) { | ||
302 | queue_work(ipoib_workqueue, &priv->flush_normal); | ||
300 | } else if (record->event == IB_EVENT_PKEY_CHANGE) { | 303 | } else if (record->event == IB_EVENT_PKEY_CHANGE) { |
301 | ipoib_dbg(priv, "P_Key change event on port:%d\n", priv->port); | 304 | queue_work(ipoib_workqueue, &priv->flush_heavy); |
302 | queue_work(ipoib_workqueue, &priv->pkey_event_task); | ||
303 | } | 305 | } |
304 | } | 306 | } |