aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/core/multicast.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/core/multicast.c')
-rw-r--r--drivers/infiniband/core/multicast.c55
1 files changed, 45 insertions, 10 deletions
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
index 1bc1fe605282..107f170c57cd 100644
--- a/drivers/infiniband/core/multicast.c
+++ b/drivers/infiniband/core/multicast.c
@@ -73,11 +73,20 @@ struct mcast_device {
73}; 73};
74 74
75enum mcast_state { 75enum mcast_state {
76 MCAST_IDLE,
77 MCAST_JOINING, 76 MCAST_JOINING,
78 MCAST_MEMBER, 77 MCAST_MEMBER,
78 MCAST_ERROR,
79};
80
81enum mcast_group_state {
82 MCAST_IDLE,
79 MCAST_BUSY, 83 MCAST_BUSY,
80 MCAST_ERROR 84 MCAST_GROUP_ERROR,
85 MCAST_PKEY_EVENT
86};
87
88enum {
89 MCAST_INVALID_PKEY_INDEX = 0xFFFF
81}; 90};
82 91
83struct mcast_member; 92struct mcast_member;
@@ -93,9 +102,10 @@ struct mcast_group {
93 struct mcast_member *last_join; 102 struct mcast_member *last_join;
94 int members[3]; 103 int members[3];
95 atomic_t refcount; 104 atomic_t refcount;
96 enum mcast_state state; 105 enum mcast_group_state state;
97 struct ib_sa_query *query; 106 struct ib_sa_query *query;
98 int query_id; 107 int query_id;
108 u16 pkey_index;
99}; 109};
100 110
101struct mcast_member { 111struct mcast_member {
@@ -378,9 +388,19 @@ static int fail_join(struct mcast_group *group, struct mcast_member *member,
378static void process_group_error(struct mcast_group *group) 388static void process_group_error(struct mcast_group *group)
379{ 389{
380 struct mcast_member *member; 390 struct mcast_member *member;
381 int ret; 391 int ret = 0;
392 u16 pkey_index;
393
394 if (group->state == MCAST_PKEY_EVENT)
395 ret = ib_find_pkey(group->port->dev->device,
396 group->port->port_num,
397 be16_to_cpu(group->rec.pkey), &pkey_index);
382 398
383 spin_lock_irq(&group->lock); 399 spin_lock_irq(&group->lock);
400 if (group->state == MCAST_PKEY_EVENT && !ret &&
401 group->pkey_index == pkey_index)
402 goto out;
403
384 while (!list_empty(&group->active_list)) { 404 while (!list_empty(&group->active_list)) {
385 member = list_entry(group->active_list.next, 405 member = list_entry(group->active_list.next,
386 struct mcast_member, list); 406 struct mcast_member, list);
@@ -399,6 +419,7 @@ static void process_group_error(struct mcast_group *group)
399 } 419 }
400 420
401 group->rec.join_state = 0; 421 group->rec.join_state = 0;
422out:
402 group->state = MCAST_BUSY; 423 group->state = MCAST_BUSY;
403 spin_unlock_irq(&group->lock); 424 spin_unlock_irq(&group->lock);
404} 425}
@@ -415,9 +436,9 @@ static void mcast_work_handler(struct work_struct *work)
415retest: 436retest:
416 spin_lock_irq(&group->lock); 437 spin_lock_irq(&group->lock);
417 while (!list_empty(&group->pending_list) || 438 while (!list_empty(&group->pending_list) ||
418 (group->state == MCAST_ERROR)) { 439 (group->state != MCAST_BUSY)) {
419 440
420 if (group->state == MCAST_ERROR) { 441 if (group->state != MCAST_BUSY) {
421 spin_unlock_irq(&group->lock); 442 spin_unlock_irq(&group->lock);
422 process_group_error(group); 443 process_group_error(group);
423 goto retest; 444 goto retest;
@@ -494,12 +515,19 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec,
494 void *context) 515 void *context)
495{ 516{
496 struct mcast_group *group = context; 517 struct mcast_group *group = context;
518 u16 pkey_index = MCAST_INVALID_PKEY_INDEX;
497 519
498 if (status) 520 if (status)
499 process_join_error(group, status); 521 process_join_error(group, status);
500 else { 522 else {
523 ib_find_pkey(group->port->dev->device, group->port->port_num,
524 be16_to_cpu(rec->pkey), &pkey_index);
525
501 spin_lock_irq(&group->port->lock); 526 spin_lock_irq(&group->port->lock);
502 group->rec = *rec; 527 group->rec = *rec;
528 if (group->state == MCAST_BUSY &&
529 group->pkey_index == MCAST_INVALID_PKEY_INDEX)
530 group->pkey_index = pkey_index;
503 if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) { 531 if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) {
504 rb_erase(&group->node, &group->port->table); 532 rb_erase(&group->node, &group->port->table);
505 mcast_insert(group->port, group, 1); 533 mcast_insert(group->port, group, 1);
@@ -539,6 +567,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port,
539 567
540 group->port = port; 568 group->port = port;
541 group->rec.mgid = *mgid; 569 group->rec.mgid = *mgid;
570 group->pkey_index = MCAST_INVALID_PKEY_INDEX;
542 INIT_LIST_HEAD(&group->pending_list); 571 INIT_LIST_HEAD(&group->pending_list);
543 INIT_LIST_HEAD(&group->active_list); 572 INIT_LIST_HEAD(&group->active_list);
544 INIT_WORK(&group->work, mcast_work_handler); 573 INIT_WORK(&group->work, mcast_work_handler);
@@ -707,7 +736,8 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num,
707} 736}
708EXPORT_SYMBOL(ib_init_ah_from_mcmember); 737EXPORT_SYMBOL(ib_init_ah_from_mcmember);
709 738
710static void mcast_groups_lost(struct mcast_port *port) 739static void mcast_groups_event(struct mcast_port *port,
740 enum mcast_group_state state)
711{ 741{
712 struct mcast_group *group; 742 struct mcast_group *group;
713 struct rb_node *node; 743 struct rb_node *node;
@@ -721,7 +751,8 @@ static void mcast_groups_lost(struct mcast_port *port)
721 atomic_inc(&group->refcount); 751 atomic_inc(&group->refcount);
722 queue_work(mcast_wq, &group->work); 752 queue_work(mcast_wq, &group->work);
723 } 753 }
724 group->state = MCAST_ERROR; 754 if (group->state != MCAST_GROUP_ERROR)
755 group->state = state;
725 spin_unlock(&group->lock); 756 spin_unlock(&group->lock);
726 } 757 }
727 spin_unlock_irqrestore(&port->lock, flags); 758 spin_unlock_irqrestore(&port->lock, flags);
@@ -731,16 +762,20 @@ static void mcast_event_handler(struct ib_event_handler *handler,
731 struct ib_event *event) 762 struct ib_event *event)
732{ 763{
733 struct mcast_device *dev; 764 struct mcast_device *dev;
765 int index;
734 766
735 dev = container_of(handler, struct mcast_device, event_handler); 767 dev = container_of(handler, struct mcast_device, event_handler);
768 index = event->element.port_num - dev->start_port;
736 769
737 switch (event->event) { 770 switch (event->event) {
738 case IB_EVENT_PORT_ERR: 771 case IB_EVENT_PORT_ERR:
739 case IB_EVENT_LID_CHANGE: 772 case IB_EVENT_LID_CHANGE:
740 case IB_EVENT_SM_CHANGE: 773 case IB_EVENT_SM_CHANGE:
741 case IB_EVENT_CLIENT_REREGISTER: 774 case IB_EVENT_CLIENT_REREGISTER:
742 mcast_groups_lost(&dev->port[event->element.port_num - 775 mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR);
743 dev->start_port]); 776 break;
777 case IB_EVENT_PKEY_CHANGE:
778 mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT);
744 break; 779 break;
745 default: 780 default:
746 break; 781 break;