aboutsummaryrefslogtreecommitdiffstats
path: root/net/ncsi
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2016-10-19 20:45:51 -0400
committerDavid S. Miller <davem@davemloft.net>2016-10-20 11:23:07 -0400
commitbbc7c01e95ceef4e23e343f8cbb6edca887121a5 (patch)
tree72f1831b284bfe9d3dd163d6eaf70a42e2231a39 /net/ncsi
parent008a424a24a904ed12c03b203f6f257bcaf12358 (diff)
net/ncsi: Choose hot channel as active one if necessary
The issue was found on BCM5718 which has two NCSI channels in one package: C0 and C1. C0 is in link-up state while C1 is in link-down state. C0 is chosen as active channel until unplugging and plugging C0's cable: On unplugging C0's cable, LSC (Link State Change) AEN packet received on C0 to report link-down event. After that, C1 is chosen as active channel. LSC AEN for link-up event is lost on C0 when plugging C0's cable back. We lose the network even C0 is usable. This resolves the issue by recording the (hot) channel that was ever chosen as active one. The hot channel is chosen to be active one if none of available channels in link-up state. With this, C0 is still the active one after unplugging C0's cable. LSC AEN packet received on C0 when plugging its cable back. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ncsi')
-rw-r--r--net/ncsi/internal.h1
-rw-r--r--net/ncsi/ncsi-manage.c22
2 files changed, 20 insertions, 3 deletions
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index eac48584cdd1..1308a56f2591 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -265,6 +265,7 @@ struct ncsi_dev_priv {
265#endif 265#endif
266 unsigned int package_num; /* Number of packages */ 266 unsigned int package_num; /* Number of packages */
267 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 */
268 struct ncsi_request requests[256]; /* Request table */ 269 struct ncsi_request requests[256]; /* Request table */
269 unsigned int request_id; /* Last used request ID */ 270 unsigned int request_id; /* Last used request ID */
270#define NCSI_REQ_START_IDX 1 271#define NCSI_REQ_START_IDX 1
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 4789f8681695..a3bd5fa8ad09 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -645,6 +645,7 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
645 struct net_device *dev = nd->dev; 645 struct net_device *dev = nd->dev;
646 struct ncsi_package *np = ndp->active_package; 646 struct ncsi_package *np = ndp->active_package;
647 struct ncsi_channel *nc = ndp->active_channel; 647 struct ncsi_channel *nc = ndp->active_channel;
648 struct ncsi_channel *hot_nc = NULL;
648 struct ncsi_cmd_arg nca; 649 struct ncsi_cmd_arg nca;
649 unsigned char index; 650 unsigned char index;
650 unsigned long flags; 651 unsigned long flags;
@@ -750,12 +751,20 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
750 break; 751 break;
751 case ncsi_dev_state_config_done: 752 case ncsi_dev_state_config_done:
752 spin_lock_irqsave(&nc->lock, flags); 753 spin_lock_irqsave(&nc->lock, flags);
753 if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) 754 if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) {
755 hot_nc = nc;
754 nc->state = NCSI_CHANNEL_ACTIVE; 756 nc->state = NCSI_CHANNEL_ACTIVE;
755 else 757 } else {
758 hot_nc = NULL;
756 nc->state = NCSI_CHANNEL_INACTIVE; 759 nc->state = NCSI_CHANNEL_INACTIVE;
760 }
757 spin_unlock_irqrestore(&nc->lock, flags); 761 spin_unlock_irqrestore(&nc->lock, flags);
758 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
759 ncsi_start_channel_monitor(nc); 768 ncsi_start_channel_monitor(nc);
760 ncsi_process_next_channel(ndp); 769 ncsi_process_next_channel(ndp);
761 break; 770 break;
@@ -773,10 +782,14 @@ error:
773static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp) 782static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
774{ 783{
775 struct ncsi_package *np; 784 struct ncsi_package *np;
776 struct ncsi_channel *nc, *found; 785 struct ncsi_channel *nc, *found, *hot_nc;
777 struct ncsi_channel_mode *ncm; 786 struct ncsi_channel_mode *ncm;
778 unsigned long flags; 787 unsigned long flags;
779 788
789 spin_lock_irqsave(&ndp->lock, flags);
790 hot_nc = ndp->hot_channel;
791 spin_unlock_irqrestore(&ndp->lock, flags);
792
780 /* The search is done once an inactive channel with up 793 /* The search is done once an inactive channel with up
781 * link is found. 794 * link is found.
782 */ 795 */
@@ -794,6 +807,9 @@ static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
794 if (!found) 807 if (!found)
795 found = nc; 808 found = nc;
796 809
810 if (nc == hot_nc)
811 found = nc;
812
797 ncm = &nc->modes[NCSI_MODE_LINK]; 813 ncm = &nc->modes[NCSI_MODE_LINK];
798 if (ncm->data[2] & 0x1) { 814 if (ncm->data[2] & 0x1) {
799 spin_unlock_irqrestore(&nc->lock, flags); 815 spin_unlock_irqrestore(&nc->lock, flags);