diff options
Diffstat (limited to 'net/ncsi/ncsi-manage.c')
-rw-r--r-- | net/ncsi/ncsi-manage.c | 71 |
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 | } |