summaryrefslogtreecommitdiffstats
path: root/net/ncsi/ncsi-manage.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ncsi/ncsi-manage.c')
-rw-r--r--net/ncsi/ncsi-manage.c71
1 files changed, 54 insertions, 17 deletions
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index ef017b871857..a26ce5132549 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -132,6 +132,7 @@ static void ncsi_report_link(struct ncsi_dev_priv *ndp, bool force_down)
132 struct ncsi_dev *nd = &ndp->ndev; 132 struct ncsi_dev *nd = &ndp->ndev;
133 struct ncsi_package *np; 133 struct ncsi_package *np;
134 struct ncsi_channel *nc; 134 struct ncsi_channel *nc;
135 unsigned long flags;
135 136
136 nd->state = ncsi_dev_state_functional; 137 nd->state = ncsi_dev_state_functional;
137 if (force_down) { 138 if (force_down) {
@@ -142,14 +143,21 @@ static void ncsi_report_link(struct ncsi_dev_priv *ndp, bool force_down)
142 nd->link_up = 0; 143 nd->link_up = 0;
143 NCSI_FOR_EACH_PACKAGE(ndp, np) { 144 NCSI_FOR_EACH_PACKAGE(ndp, np) {
144 NCSI_FOR_EACH_CHANNEL(np, nc) { 145 NCSI_FOR_EACH_CHANNEL(np, nc) {
146 spin_lock_irqsave(&nc->lock, flags);
147
145 if (!list_empty(&nc->link) || 148 if (!list_empty(&nc->link) ||
146 nc->state != NCSI_CHANNEL_ACTIVE) 149 nc->state != NCSI_CHANNEL_ACTIVE) {
150 spin_unlock_irqrestore(&nc->lock, flags);
147 continue; 151 continue;
152 }
148 153
149 if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) { 154 if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) {
155 spin_unlock_irqrestore(&nc->lock, flags);
150 nd->link_up = 1; 156 nd->link_up = 1;
151 goto report; 157 goto report;
152 } 158 }
159
160 spin_unlock_irqrestore(&nc->lock, flags);
153 } 161 }
154 } 162 }
155 163
@@ -163,20 +171,22 @@ static void ncsi_channel_monitor(unsigned long data)
163 struct ncsi_package *np = nc->package; 171 struct ncsi_package *np = nc->package;
164 struct ncsi_dev_priv *ndp = np->ndp; 172 struct ncsi_dev_priv *ndp = np->ndp;
165 struct ncsi_cmd_arg nca; 173 struct ncsi_cmd_arg nca;
166 bool enabled; 174 bool enabled, chained;
167 unsigned int timeout; 175 unsigned int timeout;
168 unsigned long flags; 176 unsigned long flags;
169 int ret; 177 int state, ret;
170 178
171 spin_lock_irqsave(&nc->lock, flags); 179 spin_lock_irqsave(&nc->lock, flags);
180 state = nc->state;
181 chained = !list_empty(&nc->link);
172 timeout = nc->timeout; 182 timeout = nc->timeout;
173 enabled = nc->enabled; 183 enabled = nc->enabled;
174 spin_unlock_irqrestore(&nc->lock, flags); 184 spin_unlock_irqrestore(&nc->lock, flags);
175 185
176 if (!enabled || !list_empty(&nc->link)) 186 if (!enabled || chained)
177 return; 187 return;
178 if (nc->state != NCSI_CHANNEL_INACTIVE && 188 if (state != NCSI_CHANNEL_INACTIVE &&
179 nc->state != NCSI_CHANNEL_ACTIVE) 189 state != NCSI_CHANNEL_ACTIVE)
180 return; 190 return;
181 191
182 if (!(timeout % 2)) { 192 if (!(timeout % 2)) {
@@ -195,11 +205,15 @@ static void ncsi_channel_monitor(unsigned long data)
195 205
196 if (timeout + 1 >= 3) { 206 if (timeout + 1 >= 3) {
197 if (!(ndp->flags & NCSI_DEV_HWA) && 207 if (!(ndp->flags & NCSI_DEV_HWA) &&
198 nc->state == NCSI_CHANNEL_ACTIVE) 208 state == NCSI_CHANNEL_ACTIVE)
199 ncsi_report_link(ndp, true); 209 ncsi_report_link(ndp, true);
200 210
211 spin_lock_irqsave(&nc->lock, flags);
212 nc->state = NCSI_CHANNEL_INVISIBLE;
213 spin_unlock_irqrestore(&nc->lock, flags);
214
201 spin_lock_irqsave(&ndp->lock, flags); 215 spin_lock_irqsave(&ndp->lock, flags);
202 xchg(&nc->state, NCSI_CHANNEL_INACTIVE); 216 nc->state = NCSI_CHANNEL_INACTIVE;
203 list_add_tail_rcu(&nc->link, &ndp->channel_queue); 217 list_add_tail_rcu(&nc->link, &ndp->channel_queue);
204 spin_unlock_irqrestore(&ndp->lock, flags); 218 spin_unlock_irqrestore(&ndp->lock, flags);
205 ncsi_process_next_channel(ndp); 219 ncsi_process_next_channel(ndp);
@@ -508,6 +522,7 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
508 struct ncsi_package *np = ndp->active_package; 522 struct ncsi_package *np = ndp->active_package;
509 struct ncsi_channel *nc = ndp->active_channel; 523 struct ncsi_channel *nc = ndp->active_channel;
510 struct ncsi_cmd_arg nca; 524 struct ncsi_cmd_arg nca;
525 unsigned long flags;
511 int ret; 526 int ret;
512 527
513 nca.ndp = ndp; 528 nca.ndp = ndp;
@@ -556,7 +571,9 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
556 571
557 break; 572 break;
558 case ncsi_dev_state_suspend_done: 573 case ncsi_dev_state_suspend_done:
559 xchg(&nc->state, NCSI_CHANNEL_INACTIVE); 574 spin_lock_irqsave(&nc->lock, flags);
575 nc->state = NCSI_CHANNEL_INACTIVE;
576 spin_unlock_irqrestore(&nc->lock, flags);
560 ncsi_process_next_channel(ndp); 577 ncsi_process_next_channel(ndp);
561 578
562 break; 579 break;
@@ -574,6 +591,7 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
574 struct ncsi_channel *nc = ndp->active_channel; 591 struct ncsi_channel *nc = ndp->active_channel;
575 struct ncsi_cmd_arg nca; 592 struct ncsi_cmd_arg nca;
576 unsigned char index; 593 unsigned char index;
594 unsigned long flags;
577 int ret; 595 int ret;
578 596
579 nca.ndp = ndp; 597 nca.ndp = ndp;
@@ -675,10 +693,12 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
675 goto error; 693 goto error;
676 break; 694 break;
677 case ncsi_dev_state_config_done: 695 case ncsi_dev_state_config_done:
696 spin_lock_irqsave(&nc->lock, flags);
678 if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) 697 if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1)
679 xchg(&nc->state, NCSI_CHANNEL_ACTIVE); 698 nc->state = NCSI_CHANNEL_ACTIVE;
680 else 699 else
681 xchg(&nc->state, NCSI_CHANNEL_INACTIVE); 700 nc->state = NCSI_CHANNEL_INACTIVE;
701 spin_unlock_irqrestore(&nc->lock, flags);
682 702
683 ncsi_start_channel_monitor(nc); 703 ncsi_start_channel_monitor(nc);
684 ncsi_process_next_channel(ndp); 704 ncsi_process_next_channel(ndp);
@@ -707,18 +727,25 @@ static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
707 found = NULL; 727 found = NULL;
708 NCSI_FOR_EACH_PACKAGE(ndp, np) { 728 NCSI_FOR_EACH_PACKAGE(ndp, np) {
709 NCSI_FOR_EACH_CHANNEL(np, nc) { 729 NCSI_FOR_EACH_CHANNEL(np, nc) {
730 spin_lock_irqsave(&nc->lock, flags);
731
710 if (!list_empty(&nc->link) || 732 if (!list_empty(&nc->link) ||
711 nc->state != NCSI_CHANNEL_INACTIVE) 733 nc->state != NCSI_CHANNEL_INACTIVE) {
734 spin_unlock_irqrestore(&nc->lock, flags);
712 continue; 735 continue;
736 }
713 737
714 if (!found) 738 if (!found)
715 found = nc; 739 found = nc;
716 740
717 ncm = &nc->modes[NCSI_MODE_LINK]; 741 ncm = &nc->modes[NCSI_MODE_LINK];
718 if (ncm->data[2] & 0x1) { 742 if (ncm->data[2] & 0x1) {
743 spin_unlock_irqrestore(&nc->lock, flags);
719 found = nc; 744 found = nc;
720 goto out; 745 goto out;
721 } 746 }
747
748 spin_unlock_irqrestore(&nc->lock, flags);
722 } 749 }
723 } 750 }
724 751
@@ -987,11 +1014,14 @@ int ncsi_process_next_channel(struct ncsi_dev_priv *ndp)
987 goto out; 1014 goto out;
988 } 1015 }
989 1016
990 old_state = xchg(&nc->state, NCSI_CHANNEL_INVISIBLE);
991 list_del_init(&nc->link); 1017 list_del_init(&nc->link);
992
993 spin_unlock_irqrestore(&ndp->lock, flags); 1018 spin_unlock_irqrestore(&ndp->lock, flags);
994 1019
1020 spin_lock_irqsave(&nc->lock, flags);
1021 old_state = nc->state;
1022 nc->state = NCSI_CHANNEL_INVISIBLE;
1023 spin_unlock_irqrestore(&nc->lock, flags);
1024
995 ndp->active_channel = nc; 1025 ndp->active_channel = nc;
996 ndp->active_package = nc->package; 1026 ndp->active_package = nc->package;
997 1027
@@ -1006,7 +1036,7 @@ int ncsi_process_next_channel(struct ncsi_dev_priv *ndp)
1006 break; 1036 break;
1007 default: 1037 default:
1008 netdev_err(ndp->ndev.dev, "Invalid state 0x%x on %d:%d\n", 1038 netdev_err(ndp->ndev.dev, "Invalid state 0x%x on %d:%d\n",
1009 nc->state, nc->package->id, nc->id); 1039 old_state, nc->package->id, nc->id);
1010 ncsi_report_link(ndp, false); 1040 ncsi_report_link(ndp, false);
1011 return -EINVAL; 1041 return -EINVAL;
1012 } 1042 }
@@ -1151,6 +1181,8 @@ int ncsi_start_dev(struct ncsi_dev *nd)
1151 struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd); 1181 struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
1152 struct ncsi_package *np; 1182 struct ncsi_package *np;
1153 struct ncsi_channel *nc; 1183 struct ncsi_channel *nc;
1184 unsigned long flags;
1185 bool chained;
1154 int old_state, ret; 1186 int old_state, ret;
1155 1187
1156 if (nd->state != ncsi_dev_state_registered && 1188 if (nd->state != ncsi_dev_state_registered &&
@@ -1166,8 +1198,13 @@ int ncsi_start_dev(struct ncsi_dev *nd)
1166 /* Reset channel's state and start over */ 1198 /* Reset channel's state and start over */
1167 NCSI_FOR_EACH_PACKAGE(ndp, np) { 1199 NCSI_FOR_EACH_PACKAGE(ndp, np) {
1168 NCSI_FOR_EACH_CHANNEL(np, nc) { 1200 NCSI_FOR_EACH_CHANNEL(np, nc) {
1169 old_state = xchg(&nc->state, NCSI_CHANNEL_INACTIVE); 1201 spin_lock_irqsave(&nc->lock, flags);
1170 WARN_ON_ONCE(!list_empty(&nc->link) || 1202 chained = !list_empty(&nc->link);
1203 old_state = nc->state;
1204 nc->state = NCSI_CHANNEL_INACTIVE;
1205 spin_unlock_irqrestore(&nc->lock, flags);
1206
1207 WARN_ON_ONCE(chained ||
1171 old_state == NCSI_CHANNEL_INVISIBLE); 1208 old_state == NCSI_CHANNEL_INVISIBLE);
1172 } 1209 }
1173 } 1210 }