aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-10-20 11:23:08 -0400
committerDavid S. Miller <davem@davemloft.net>2016-10-20 11:23:08 -0400
commitae3877bce505e5591832bcb7d8a7aefb74a04ffb (patch)
treee27ab3bc1a06c24831946d1319a64d292f55f7d5
parent5712bf9c5c30ade3204016147d7b04bece6952d9 (diff)
parent22d8aa93d7ea169a349fb2f9dee5babc68f6a683 (diff)
Merge branch 'ncsi-fixes'
Gavin Shan says: ==================== net/ncsi: More bug fixes This series fixes 2 issues that were found during NCSI's availability testing on BCM5718 and improves HNCDSC AEN handler: * PATCH[1] refactors the code so that minimal code change is put to PATCH[2]. * PATCH[2] fixes the NCSI channel's stale link state before doing failover. * PATCH[3] chooses the hot channel, which was ever chosen as active channel, when the available channels are all in link-down state. * PATCH[4] improves Host Network Controller Driver Status Change (HNCDSC) AEN handler Changelog ========= v2: * Merged PATCH[v1 1/2] to PATCH[v2 1]. * Avoid if/else statements in ncsi_suspend_channel() as Joel suggested. * Added comments to explain why we need retrieve last link states in ncsi_suspend_channel(). ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ncsi/internal.h2
-rw-r--r--net/ncsi/ncsi-aen.c18
-rw-r--r--net/ncsi/ncsi-manage.c126
3 files changed, 112 insertions, 34 deletions
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index 13290a70fa71..1308a56f2591 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -246,6 +246,7 @@ enum {
246 ncsi_dev_state_config_gls, 246 ncsi_dev_state_config_gls,
247 ncsi_dev_state_config_done, 247 ncsi_dev_state_config_done,
248 ncsi_dev_state_suspend_select = 0x0401, 248 ncsi_dev_state_suspend_select = 0x0401,
249 ncsi_dev_state_suspend_gls,
249 ncsi_dev_state_suspend_dcnt, 250 ncsi_dev_state_suspend_dcnt,
250 ncsi_dev_state_suspend_dc, 251 ncsi_dev_state_suspend_dc,
251 ncsi_dev_state_suspend_deselect, 252 ncsi_dev_state_suspend_deselect,
@@ -264,6 +265,7 @@ struct ncsi_dev_priv {
264#endif 265#endif
265 unsigned int package_num; /* Number of packages */ 266 unsigned int package_num; /* Number of packages */
266 struct list_head packages; /* List of packages */ 267 struct list_head packages; /* List of packages */
268 struct ncsi_channel *hot_channel; /* Channel was ever active */
267 struct ncsi_request requests[256]; /* Request table */ 269 struct ncsi_request requests[256]; /* Request table */
268 unsigned int request_id; /* Last used request ID */ 270 unsigned int request_id; /* Last used request ID */
269#define NCSI_REQ_START_IDX 1 271#define NCSI_REQ_START_IDX 1
diff --git a/net/ncsi/ncsi-aen.c b/net/ncsi/ncsi-aen.c
index b41a6617d498..6898e7229285 100644
--- a/net/ncsi/ncsi-aen.c
+++ b/net/ncsi/ncsi-aen.c
@@ -141,23 +141,35 @@ static int ncsi_aen_handler_hncdsc(struct ncsi_dev_priv *ndp,
141 return -ENODEV; 141 return -ENODEV;
142 142
143 /* If the channel is active one, we need reconfigure it */ 143 /* If the channel is active one, we need reconfigure it */
144 spin_lock_irqsave(&nc->lock, flags);
144 ncm = &nc->modes[NCSI_MODE_LINK]; 145 ncm = &nc->modes[NCSI_MODE_LINK];
145 hncdsc = (struct ncsi_aen_hncdsc_pkt *)h; 146 hncdsc = (struct ncsi_aen_hncdsc_pkt *)h;
146 ncm->data[3] = ntohl(hncdsc->status); 147 ncm->data[3] = ntohl(hncdsc->status);
147 if (!list_empty(&nc->link) || 148 if (!list_empty(&nc->link) ||
148 nc->state != NCSI_CHANNEL_ACTIVE || 149 nc->state != NCSI_CHANNEL_ACTIVE) {
149 (ncm->data[3] & 0x1)) 150 spin_unlock_irqrestore(&nc->lock, flags);
150 return 0; 151 return 0;
152 }
151 153
152 if (ndp->flags & NCSI_DEV_HWA) 154 spin_unlock_irqrestore(&nc->lock, flags);
155 if (!(ndp->flags & NCSI_DEV_HWA) && !(ncm->data[3] & 0x1))
153 ndp->flags |= NCSI_DEV_RESHUFFLE; 156 ndp->flags |= NCSI_DEV_RESHUFFLE;
154 157
155 /* If this channel is the active one and the link doesn't 158 /* If this channel is the active one and the link doesn't
156 * work, we have to choose another channel to be active one. 159 * work, we have to choose another channel to be active one.
157 * The logic here is exactly similar to what we do when link 160 * The logic here is exactly similar to what we do when link
158 * is down on the active channel. 161 * is down on the active channel.
162 *
163 * On the other hand, we need configure it when host driver
164 * state on the active channel becomes ready.
159 */ 165 */
160 ncsi_stop_channel_monitor(nc); 166 ncsi_stop_channel_monitor(nc);
167
168 spin_lock_irqsave(&nc->lock, flags);
169 nc->state = (ncm->data[3] & 0x1) ? NCSI_CHANNEL_INACTIVE :
170 NCSI_CHANNEL_ACTIVE;
171 spin_unlock_irqrestore(&nc->lock, flags);
172
161 spin_lock_irqsave(&ndp->lock, flags); 173 spin_lock_irqsave(&ndp->lock, flags);
162 list_add_tail_rcu(&nc->link, &ndp->channel_queue); 174 list_add_tail_rcu(&nc->link, &ndp->channel_queue);
163 spin_unlock_irqrestore(&ndp->lock, flags); 175 spin_unlock_irqrestore(&ndp->lock, flags);
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 5e509e547c2d..a3bd5fa8ad09 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -540,42 +540,86 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
540 nd->state = ncsi_dev_state_suspend_select; 540 nd->state = ncsi_dev_state_suspend_select;
541 /* Fall through */ 541 /* Fall through */
542 case ncsi_dev_state_suspend_select: 542 case ncsi_dev_state_suspend_select:
543 case ncsi_dev_state_suspend_dcnt:
544 case ncsi_dev_state_suspend_dc:
545 case ncsi_dev_state_suspend_deselect:
546 ndp->pending_req_num = 1; 543 ndp->pending_req_num = 1;
547 544
548 np = ndp->active_package; 545 nca.type = NCSI_PKT_CMD_SP;
549 nc = ndp->active_channel;
550 nca.package = np->id; 546 nca.package = np->id;
551 if (nd->state == ncsi_dev_state_suspend_select) { 547 nca.channel = NCSI_RESERVED_CHANNEL;
552 nca.type = NCSI_PKT_CMD_SP; 548 if (ndp->flags & NCSI_DEV_HWA)
553 nca.channel = NCSI_RESERVED_CHANNEL; 549 nca.bytes[0] = 0;
554 if (ndp->flags & NCSI_DEV_HWA) 550 else
555 nca.bytes[0] = 0; 551 nca.bytes[0] = 1;
556 else 552
557 nca.bytes[0] = 1; 553 /* To retrieve the last link states of channels in current
554 * package when current active channel needs fail over to
555 * another one. It means we will possibly select another
556 * channel as next active one. The link states of channels
557 * are most important factor of the selection. So we need
558 * accurate link states. Unfortunately, the link states on
559 * inactive channels can't be updated with LSC AEN in time.
560 */
561 if (ndp->flags & NCSI_DEV_RESHUFFLE)
562 nd->state = ncsi_dev_state_suspend_gls;
563 else
558 nd->state = ncsi_dev_state_suspend_dcnt; 564 nd->state = ncsi_dev_state_suspend_dcnt;
559 } else if (nd->state == ncsi_dev_state_suspend_dcnt) { 565 ret = ncsi_xmit_cmd(&nca);
560 nca.type = NCSI_PKT_CMD_DCNT; 566 if (ret)
561 nca.channel = nc->id; 567 goto error;
562 nd->state = ncsi_dev_state_suspend_dc; 568
563 } else if (nd->state == ncsi_dev_state_suspend_dc) { 569 break;
564 nca.type = NCSI_PKT_CMD_DC; 570 case ncsi_dev_state_suspend_gls:
571 ndp->pending_req_num = np->channel_num;
572
573 nca.type = NCSI_PKT_CMD_GLS;
574 nca.package = np->id;
575
576 nd->state = ncsi_dev_state_suspend_dcnt;
577 NCSI_FOR_EACH_CHANNEL(np, nc) {
565 nca.channel = nc->id; 578 nca.channel = nc->id;
566 nca.bytes[0] = 1; 579 ret = ncsi_xmit_cmd(&nca);
567 nd->state = ncsi_dev_state_suspend_deselect; 580 if (ret)
568 } else if (nd->state == ncsi_dev_state_suspend_deselect) { 581 goto error;
569 nca.type = NCSI_PKT_CMD_DP;
570 nca.channel = NCSI_RESERVED_CHANNEL;
571 nd->state = ncsi_dev_state_suspend_done;
572 } 582 }
573 583
584 break;
585 case ncsi_dev_state_suspend_dcnt:
586 ndp->pending_req_num = 1;
587
588 nca.type = NCSI_PKT_CMD_DCNT;
589 nca.package = np->id;
590 nca.channel = nc->id;
591
592 nd->state = ncsi_dev_state_suspend_dc;
574 ret = ncsi_xmit_cmd(&nca); 593 ret = ncsi_xmit_cmd(&nca);
575 if (ret) { 594 if (ret)
576 nd->state = ncsi_dev_state_functional; 595 goto error;
577 return; 596
578 } 597 break;
598 case ncsi_dev_state_suspend_dc:
599 ndp->pending_req_num = 1;
600
601 nca.type = NCSI_PKT_CMD_DC;
602 nca.package = np->id;
603 nca.channel = nc->id;
604 nca.bytes[0] = 1;
605
606 nd->state = ncsi_dev_state_suspend_deselect;
607 ret = ncsi_xmit_cmd(&nca);
608 if (ret)
609 goto error;
610
611 break;
612 case ncsi_dev_state_suspend_deselect:
613 ndp->pending_req_num = 1;
614
615 nca.type = NCSI_PKT_CMD_DP;
616 nca.package = np->id;
617 nca.channel = NCSI_RESERVED_CHANNEL;
618
619 nd->state = ncsi_dev_state_suspend_done;
620 ret = ncsi_xmit_cmd(&nca);
621 if (ret)
622 goto error;
579 623
580 break; 624 break;
581 case ncsi_dev_state_suspend_done: 625 case ncsi_dev_state_suspend_done:
@@ -589,6 +633,10 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
589 netdev_warn(nd->dev, "Wrong NCSI state 0x%x in suspend\n", 633 netdev_warn(nd->dev, "Wrong NCSI state 0x%x in suspend\n",
590 nd->state); 634 nd->state);
591 } 635 }
636
637 return;
638error:
639 nd->state = ncsi_dev_state_functional;
592} 640}
593 641
594static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) 642static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
@@ -597,6 +645,7 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
597 struct net_device *dev = nd->dev; 645 struct net_device *dev = nd->dev;
598 struct ncsi_package *np = ndp->active_package; 646 struct ncsi_package *np = ndp->active_package;
599 struct ncsi_channel *nc = ndp->active_channel; 647 struct ncsi_channel *nc = ndp->active_channel;
648 struct ncsi_channel *hot_nc = NULL;
600 struct ncsi_cmd_arg nca; 649 struct ncsi_cmd_arg nca;
601 unsigned char index; 650 unsigned char index;
602 unsigned long flags; 651 unsigned long flags;
@@ -702,12 +751,20 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
702 break; 751 break;
703 case ncsi_dev_state_config_done: 752 case ncsi_dev_state_config_done:
704 spin_lock_irqsave(&nc->lock, flags); 753 spin_lock_irqsave(&nc->lock, flags);
705 if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) 754 if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) {
755 hot_nc = nc;
706 nc->state = NCSI_CHANNEL_ACTIVE; 756 nc->state = NCSI_CHANNEL_ACTIVE;
707 else 757 } else {
758 hot_nc = NULL;
708 nc->state = NCSI_CHANNEL_INACTIVE; 759 nc->state = NCSI_CHANNEL_INACTIVE;
760 }
709 spin_unlock_irqrestore(&nc->lock, flags); 761 spin_unlock_irqrestore(&nc->lock, flags);
710 762
763 /* Update the hot channel */
764 spin_lock_irqsave(&ndp->lock, flags);
765 ndp->hot_channel = hot_nc;
766 spin_unlock_irqrestore(&ndp->lock, flags);
767
711 ncsi_start_channel_monitor(nc); 768 ncsi_start_channel_monitor(nc);
712 ncsi_process_next_channel(ndp); 769 ncsi_process_next_channel(ndp);
713 break; 770 break;
@@ -725,10 +782,14 @@ error:
725static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp) 782static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
726{ 783{
727 struct ncsi_package *np; 784 struct ncsi_package *np;
728 struct ncsi_channel *nc, *found; 785 struct ncsi_channel *nc, *found, *hot_nc;
729 struct ncsi_channel_mode *ncm; 786 struct ncsi_channel_mode *ncm;
730 unsigned long flags; 787 unsigned long flags;
731 788
789 spin_lock_irqsave(&ndp->lock, flags);
790 hot_nc = ndp->hot_channel;
791 spin_unlock_irqrestore(&ndp->lock, flags);
792
732 /* The search is done once an inactive channel with up 793 /* The search is done once an inactive channel with up
733 * link is found. 794 * link is found.
734 */ 795 */
@@ -746,6 +807,9 @@ static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
746 if (!found) 807 if (!found)
747 found = nc; 808 found = nc;
748 809
810 if (nc == hot_nc)
811 found = nc;
812
749 ncm = &nc->modes[NCSI_MODE_LINK]; 813 ncm = &nc->modes[NCSI_MODE_LINK];
750 if (ncm->data[2] & 0x1) { 814 if (ncm->data[2] & 0x1) {
751 spin_unlock_irqrestore(&nc->lock, flags); 815 spin_unlock_irqrestore(&nc->lock, flags);