|
@@ -132,6 +132,7 @@ static void ncsi_report_link(struct ncsi_dev_priv *ndp, bool force_down)
|
|
|
struct ncsi_dev *nd = &ndp->ndev;
|
|
|
struct ncsi_package *np;
|
|
|
struct ncsi_channel *nc;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
nd->state = ncsi_dev_state_functional;
|
|
|
if (force_down) {
|
|
@@ -142,14 +143,21 @@ static void ncsi_report_link(struct ncsi_dev_priv *ndp, bool force_down)
|
|
|
nd->link_up = 0;
|
|
|
NCSI_FOR_EACH_PACKAGE(ndp, np) {
|
|
|
NCSI_FOR_EACH_CHANNEL(np, nc) {
|
|
|
+ spin_lock_irqsave(&nc->lock, flags);
|
|
|
+
|
|
|
if (!list_empty(&nc->link) ||
|
|
|
- nc->state != NCSI_CHANNEL_ACTIVE)
|
|
|
+ nc->state != NCSI_CHANNEL_ACTIVE) {
|
|
|
+ spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
continue;
|
|
|
+ }
|
|
|
|
|
|
if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) {
|
|
|
+ spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
nd->link_up = 1;
|
|
|
goto report;
|
|
|
}
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -163,43 +171,55 @@ static void ncsi_channel_monitor(unsigned long data)
|
|
|
struct ncsi_package *np = nc->package;
|
|
|
struct ncsi_dev_priv *ndp = np->ndp;
|
|
|
struct ncsi_cmd_arg nca;
|
|
|
- bool enabled;
|
|
|
- unsigned int timeout;
|
|
|
+ bool enabled, chained;
|
|
|
+ unsigned int monitor_state;
|
|
|
unsigned long flags;
|
|
|
- int ret;
|
|
|
+ int state, ret;
|
|
|
|
|
|
spin_lock_irqsave(&nc->lock, flags);
|
|
|
- timeout = nc->timeout;
|
|
|
- enabled = nc->enabled;
|
|
|
+ state = nc->state;
|
|
|
+ chained = !list_empty(&nc->link);
|
|
|
+ enabled = nc->monitor.enabled;
|
|
|
+ monitor_state = nc->monitor.state;
|
|
|
spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
|
|
|
- if (!enabled || !list_empty(&nc->link))
|
|
|
+ if (!enabled || chained)
|
|
|
return;
|
|
|
- if (nc->state != NCSI_CHANNEL_INACTIVE &&
|
|
|
- nc->state != NCSI_CHANNEL_ACTIVE)
|
|
|
+ if (state != NCSI_CHANNEL_INACTIVE &&
|
|
|
+ state != NCSI_CHANNEL_ACTIVE)
|
|
|
return;
|
|
|
|
|
|
- if (!(timeout % 2)) {
|
|
|
+ switch (monitor_state) {
|
|
|
+ case NCSI_CHANNEL_MONITOR_START:
|
|
|
+ case NCSI_CHANNEL_MONITOR_RETRY:
|
|
|
nca.ndp = ndp;
|
|
|
nca.package = np->id;
|
|
|
nca.channel = nc->id;
|
|
|
nca.type = NCSI_PKT_CMD_GLS;
|
|
|
- nca.driven = false;
|
|
|
+ nca.req_flags = 0;
|
|
|
ret = ncsi_xmit_cmd(&nca);
|
|
|
if (ret) {
|
|
|
netdev_err(ndp->ndev.dev, "Error %d sending GLS\n",
|
|
|
ret);
|
|
|
return;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if (timeout + 1 >= 3) {
|
|
|
+ break;
|
|
|
+ case NCSI_CHANNEL_MONITOR_WAIT ... NCSI_CHANNEL_MONITOR_WAIT_MAX:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
if (!(ndp->flags & NCSI_DEV_HWA) &&
|
|
|
- nc->state == NCSI_CHANNEL_ACTIVE)
|
|
|
+ state == NCSI_CHANNEL_ACTIVE) {
|
|
|
ncsi_report_link(ndp, true);
|
|
|
+ ndp->flags |= NCSI_DEV_RESHUFFLE;
|
|
|
+ }
|
|
|
+
|
|
|
+ spin_lock_irqsave(&nc->lock, flags);
|
|
|
+ nc->state = NCSI_CHANNEL_INVISIBLE;
|
|
|
+ spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
|
|
|
spin_lock_irqsave(&ndp->lock, flags);
|
|
|
- xchg(&nc->state, NCSI_CHANNEL_INACTIVE);
|
|
|
+ nc->state = NCSI_CHANNEL_INACTIVE;
|
|
|
list_add_tail_rcu(&nc->link, &ndp->channel_queue);
|
|
|
spin_unlock_irqrestore(&ndp->lock, flags);
|
|
|
ncsi_process_next_channel(ndp);
|
|
@@ -207,10 +227,9 @@ static void ncsi_channel_monitor(unsigned long data)
|
|
|
}
|
|
|
|
|
|
spin_lock_irqsave(&nc->lock, flags);
|
|
|
- nc->timeout = timeout + 1;
|
|
|
- nc->enabled = true;
|
|
|
+ nc->monitor.state++;
|
|
|
spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
- mod_timer(&nc->timer, jiffies + HZ * (1 << (nc->timeout / 2)));
|
|
|
+ mod_timer(&nc->monitor.timer, jiffies + HZ);
|
|
|
}
|
|
|
|
|
|
void ncsi_start_channel_monitor(struct ncsi_channel *nc)
|
|
@@ -218,12 +237,12 @@ void ncsi_start_channel_monitor(struct ncsi_channel *nc)
|
|
|
unsigned long flags;
|
|
|
|
|
|
spin_lock_irqsave(&nc->lock, flags);
|
|
|
- WARN_ON_ONCE(nc->enabled);
|
|
|
- nc->timeout = 0;
|
|
|
- nc->enabled = true;
|
|
|
+ WARN_ON_ONCE(nc->monitor.enabled);
|
|
|
+ nc->monitor.enabled = true;
|
|
|
+ nc->monitor.state = NCSI_CHANNEL_MONITOR_START;
|
|
|
spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
|
|
|
- mod_timer(&nc->timer, jiffies + HZ * (1 << (nc->timeout / 2)));
|
|
|
+ mod_timer(&nc->monitor.timer, jiffies + HZ);
|
|
|
}
|
|
|
|
|
|
void ncsi_stop_channel_monitor(struct ncsi_channel *nc)
|
|
@@ -231,14 +250,14 @@ void ncsi_stop_channel_monitor(struct ncsi_channel *nc)
|
|
|
unsigned long flags;
|
|
|
|
|
|
spin_lock_irqsave(&nc->lock, flags);
|
|
|
- if (!nc->enabled) {
|
|
|
+ if (!nc->monitor.enabled) {
|
|
|
spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
return;
|
|
|
}
|
|
|
- nc->enabled = false;
|
|
|
+ nc->monitor.enabled = false;
|
|
|
spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
|
|
|
- del_timer_sync(&nc->timer);
|
|
|
+ del_timer_sync(&nc->monitor.timer);
|
|
|
}
|
|
|
|
|
|
struct ncsi_channel *ncsi_find_channel(struct ncsi_package *np,
|
|
@@ -267,8 +286,9 @@ struct ncsi_channel *ncsi_add_channel(struct ncsi_package *np, unsigned char id)
|
|
|
nc->id = id;
|
|
|
nc->package = np;
|
|
|
nc->state = NCSI_CHANNEL_INACTIVE;
|
|
|
- nc->enabled = false;
|
|
|
- setup_timer(&nc->timer, ncsi_channel_monitor, (unsigned long)nc);
|
|
|
+ nc->monitor.enabled = false;
|
|
|
+ setup_timer(&nc->monitor.timer,
|
|
|
+ ncsi_channel_monitor, (unsigned long)nc);
|
|
|
spin_lock_init(&nc->lock);
|
|
|
INIT_LIST_HEAD(&nc->link);
|
|
|
for (index = 0; index < NCSI_CAP_MAX; index++)
|
|
@@ -405,7 +425,8 @@ void ncsi_find_package_and_channel(struct ncsi_dev_priv *ndp,
|
|
|
* be same. Otherwise, the bogus response might be replied. So
|
|
|
* the available IDs are allocated in round-robin fashion.
|
|
|
*/
|
|
|
-struct ncsi_request *ncsi_alloc_request(struct ncsi_dev_priv *ndp, bool driven)
|
|
|
+struct ncsi_request *ncsi_alloc_request(struct ncsi_dev_priv *ndp,
|
|
|
+ unsigned int req_flags)
|
|
|
{
|
|
|
struct ncsi_request *nr = NULL;
|
|
|
int i, limit = ARRAY_SIZE(ndp->requests);
|
|
@@ -413,30 +434,31 @@ struct ncsi_request *ncsi_alloc_request(struct ncsi_dev_priv *ndp, bool driven)
|
|
|
|
|
|
/* Check if there is one available request until the ceiling */
|
|
|
spin_lock_irqsave(&ndp->lock, flags);
|
|
|
- for (i = ndp->request_id; !nr && i < limit; i++) {
|
|
|
+ for (i = ndp->request_id; i < limit; i++) {
|
|
|
if (ndp->requests[i].used)
|
|
|
continue;
|
|
|
|
|
|
nr = &ndp->requests[i];
|
|
|
nr->used = true;
|
|
|
- nr->driven = driven;
|
|
|
- if (++ndp->request_id >= limit)
|
|
|
- ndp->request_id = 0;
|
|
|
+ nr->flags = req_flags;
|
|
|
+ ndp->request_id = i + 1;
|
|
|
+ goto found;
|
|
|
}
|
|
|
|
|
|
/* Fail back to check from the starting cursor */
|
|
|
- for (i = 0; !nr && i < ndp->request_id; i++) {
|
|
|
+ for (i = NCSI_REQ_START_IDX; i < ndp->request_id; i++) {
|
|
|
if (ndp->requests[i].used)
|
|
|
continue;
|
|
|
|
|
|
nr = &ndp->requests[i];
|
|
|
nr->used = true;
|
|
|
- nr->driven = driven;
|
|
|
- if (++ndp->request_id >= limit)
|
|
|
- ndp->request_id = 0;
|
|
|
+ nr->flags = req_flags;
|
|
|
+ ndp->request_id = i + 1;
|
|
|
+ goto found;
|
|
|
}
|
|
|
- spin_unlock_irqrestore(&ndp->lock, flags);
|
|
|
|
|
|
+found:
|
|
|
+ spin_unlock_irqrestore(&ndp->lock, flags);
|
|
|
return nr;
|
|
|
}
|
|
|
|
|
@@ -458,7 +480,7 @@ void ncsi_free_request(struct ncsi_request *nr)
|
|
|
nr->cmd = NULL;
|
|
|
nr->rsp = NULL;
|
|
|
nr->used = false;
|
|
|
- driven = nr->driven;
|
|
|
+ driven = !!(nr->flags & NCSI_REQ_FLAG_EVENT_DRIVEN);
|
|
|
spin_unlock_irqrestore(&ndp->lock, flags);
|
|
|
|
|
|
if (driven && cmd && --ndp->pending_req_num == 0)
|
|
@@ -508,10 +530,11 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
|
|
|
struct ncsi_package *np = ndp->active_package;
|
|
|
struct ncsi_channel *nc = ndp->active_channel;
|
|
|
struct ncsi_cmd_arg nca;
|
|
|
+ unsigned long flags;
|
|
|
int ret;
|
|
|
|
|
|
nca.ndp = ndp;
|
|
|
- nca.driven = true;
|
|
|
+ nca.req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN;
|
|
|
switch (nd->state) {
|
|
|
case ncsi_dev_state_suspend:
|
|
|
nd->state = ncsi_dev_state_suspend_select;
|
|
@@ -527,7 +550,7 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
|
|
|
nca.package = np->id;
|
|
|
if (nd->state == ncsi_dev_state_suspend_select) {
|
|
|
nca.type = NCSI_PKT_CMD_SP;
|
|
|
- nca.channel = 0x1f;
|
|
|
+ nca.channel = NCSI_RESERVED_CHANNEL;
|
|
|
if (ndp->flags & NCSI_DEV_HWA)
|
|
|
nca.bytes[0] = 0;
|
|
|
else
|
|
@@ -544,7 +567,7 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
|
|
|
nd->state = ncsi_dev_state_suspend_deselect;
|
|
|
} else if (nd->state == ncsi_dev_state_suspend_deselect) {
|
|
|
nca.type = NCSI_PKT_CMD_DP;
|
|
|
- nca.channel = 0x1f;
|
|
|
+ nca.channel = NCSI_RESERVED_CHANNEL;
|
|
|
nd->state = ncsi_dev_state_suspend_done;
|
|
|
}
|
|
|
|
|
@@ -556,7 +579,9 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
|
|
|
|
|
|
break;
|
|
|
case ncsi_dev_state_suspend_done:
|
|
|
- xchg(&nc->state, NCSI_CHANNEL_INACTIVE);
|
|
|
+ spin_lock_irqsave(&nc->lock, flags);
|
|
|
+ nc->state = NCSI_CHANNEL_INACTIVE;
|
|
|
+ spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
ncsi_process_next_channel(ndp);
|
|
|
|
|
|
break;
|
|
@@ -574,10 +599,11 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
|
|
|
struct ncsi_channel *nc = ndp->active_channel;
|
|
|
struct ncsi_cmd_arg nca;
|
|
|
unsigned char index;
|
|
|
+ unsigned long flags;
|
|
|
int ret;
|
|
|
|
|
|
nca.ndp = ndp;
|
|
|
- nca.driven = true;
|
|
|
+ nca.req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN;
|
|
|
switch (nd->state) {
|
|
|
case ncsi_dev_state_config:
|
|
|
case ncsi_dev_state_config_sp:
|
|
@@ -590,7 +616,7 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
|
|
|
else
|
|
|
nca.bytes[0] = 1;
|
|
|
nca.package = np->id;
|
|
|
- nca.channel = 0x1f;
|
|
|
+ nca.channel = NCSI_RESERVED_CHANNEL;
|
|
|
ret = ncsi_xmit_cmd(&nca);
|
|
|
if (ret)
|
|
|
goto error;
|
|
@@ -675,10 +701,12 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
|
|
|
goto error;
|
|
|
break;
|
|
|
case ncsi_dev_state_config_done:
|
|
|
+ spin_lock_irqsave(&nc->lock, flags);
|
|
|
if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1)
|
|
|
- xchg(&nc->state, NCSI_CHANNEL_ACTIVE);
|
|
|
+ nc->state = NCSI_CHANNEL_ACTIVE;
|
|
|
else
|
|
|
- xchg(&nc->state, NCSI_CHANNEL_INACTIVE);
|
|
|
+ nc->state = NCSI_CHANNEL_INACTIVE;
|
|
|
+ spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
|
|
|
ncsi_start_channel_monitor(nc);
|
|
|
ncsi_process_next_channel(ndp);
|
|
@@ -707,18 +735,25 @@ static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
|
|
|
found = NULL;
|
|
|
NCSI_FOR_EACH_PACKAGE(ndp, np) {
|
|
|
NCSI_FOR_EACH_CHANNEL(np, nc) {
|
|
|
+ spin_lock_irqsave(&nc->lock, flags);
|
|
|
+
|
|
|
if (!list_empty(&nc->link) ||
|
|
|
- nc->state != NCSI_CHANNEL_INACTIVE)
|
|
|
+ nc->state != NCSI_CHANNEL_INACTIVE) {
|
|
|
+ spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
continue;
|
|
|
+ }
|
|
|
|
|
|
if (!found)
|
|
|
found = nc;
|
|
|
|
|
|
ncm = &nc->modes[NCSI_MODE_LINK];
|
|
|
if (ncm->data[2] & 0x1) {
|
|
|
+ spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
found = nc;
|
|
|
goto out;
|
|
|
}
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -797,7 +832,7 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
|
|
|
int ret;
|
|
|
|
|
|
nca.ndp = ndp;
|
|
|
- nca.driven = true;
|
|
|
+ nca.req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN;
|
|
|
switch (nd->state) {
|
|
|
case ncsi_dev_state_probe:
|
|
|
nd->state = ncsi_dev_state_probe_deselect;
|
|
@@ -807,7 +842,7 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
|
|
|
|
|
|
/* Deselect all possible packages */
|
|
|
nca.type = NCSI_PKT_CMD_DP;
|
|
|
- nca.channel = 0x1f;
|
|
|
+ nca.channel = NCSI_RESERVED_CHANNEL;
|
|
|
for (index = 0; index < 8; index++) {
|
|
|
nca.package = index;
|
|
|
ret = ncsi_xmit_cmd(&nca);
|
|
@@ -823,7 +858,7 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
|
|
|
/* Select all possible packages */
|
|
|
nca.type = NCSI_PKT_CMD_SP;
|
|
|
nca.bytes[0] = 1;
|
|
|
- nca.channel = 0x1f;
|
|
|
+ nca.channel = NCSI_RESERVED_CHANNEL;
|
|
|
for (index = 0; index < 8; index++) {
|
|
|
nca.package = index;
|
|
|
ret = ncsi_xmit_cmd(&nca);
|
|
@@ -876,7 +911,7 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
|
|
|
nca.type = NCSI_PKT_CMD_SP;
|
|
|
nca.bytes[0] = 1;
|
|
|
nca.package = ndp->active_package->id;
|
|
|
- nca.channel = 0x1f;
|
|
|
+ nca.channel = NCSI_RESERVED_CHANNEL;
|
|
|
ret = ncsi_xmit_cmd(&nca);
|
|
|
if (ret)
|
|
|
goto error;
|
|
@@ -884,12 +919,12 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
|
|
|
nd->state = ncsi_dev_state_probe_cis;
|
|
|
break;
|
|
|
case ncsi_dev_state_probe_cis:
|
|
|
- ndp->pending_req_num = 32;
|
|
|
+ ndp->pending_req_num = NCSI_RESERVED_CHANNEL;
|
|
|
|
|
|
/* Clear initial state */
|
|
|
nca.type = NCSI_PKT_CMD_CIS;
|
|
|
nca.package = ndp->active_package->id;
|
|
|
- for (index = 0; index < 0x20; index++) {
|
|
|
+ for (index = 0; index < NCSI_RESERVED_CHANNEL; index++) {
|
|
|
nca.channel = index;
|
|
|
ret = ncsi_xmit_cmd(&nca);
|
|
|
if (ret)
|
|
@@ -933,7 +968,7 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
|
|
|
/* Deselect the active package */
|
|
|
nca.type = NCSI_PKT_CMD_DP;
|
|
|
nca.package = ndp->active_package->id;
|
|
|
- nca.channel = 0x1f;
|
|
|
+ nca.channel = NCSI_RESERVED_CHANNEL;
|
|
|
ret = ncsi_xmit_cmd(&nca);
|
|
|
if (ret)
|
|
|
goto error;
|
|
@@ -987,11 +1022,14 @@ int ncsi_process_next_channel(struct ncsi_dev_priv *ndp)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- old_state = xchg(&nc->state, NCSI_CHANNEL_INVISIBLE);
|
|
|
list_del_init(&nc->link);
|
|
|
-
|
|
|
spin_unlock_irqrestore(&ndp->lock, flags);
|
|
|
|
|
|
+ spin_lock_irqsave(&nc->lock, flags);
|
|
|
+ old_state = nc->state;
|
|
|
+ nc->state = NCSI_CHANNEL_INVISIBLE;
|
|
|
+ spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
+
|
|
|
ndp->active_channel = nc;
|
|
|
ndp->active_package = nc->package;
|
|
|
|
|
@@ -1006,7 +1044,7 @@ int ncsi_process_next_channel(struct ncsi_dev_priv *ndp)
|
|
|
break;
|
|
|
default:
|
|
|
netdev_err(ndp->ndev.dev, "Invalid state 0x%x on %d:%d\n",
|
|
|
- nc->state, nc->package->id, nc->id);
|
|
|
+ old_state, nc->package->id, nc->id);
|
|
|
ncsi_report_link(ndp, false);
|
|
|
return -EINVAL;
|
|
|
}
|
|
@@ -1070,7 +1108,7 @@ static int ncsi_inet6addr_event(struct notifier_block *this,
|
|
|
return NOTIFY_OK;
|
|
|
|
|
|
nca.ndp = ndp;
|
|
|
- nca.driven = false;
|
|
|
+ nca.req_flags = 0;
|
|
|
nca.package = np->id;
|
|
|
nca.channel = nc->id;
|
|
|
nca.dwords[0] = nc->caps[NCSI_CAP_MC].cap;
|
|
@@ -1118,7 +1156,7 @@ struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
|
|
|
/* Initialize private NCSI device */
|
|
|
spin_lock_init(&ndp->lock);
|
|
|
INIT_LIST_HEAD(&ndp->packages);
|
|
|
- ndp->request_id = 0;
|
|
|
+ ndp->request_id = NCSI_REQ_START_IDX;
|
|
|
for (i = 0; i < ARRAY_SIZE(ndp->requests); i++) {
|
|
|
ndp->requests[i].id = i;
|
|
|
ndp->requests[i].ndp = ndp;
|
|
@@ -1149,9 +1187,7 @@ EXPORT_SYMBOL_GPL(ncsi_register_dev);
|
|
|
int ncsi_start_dev(struct ncsi_dev *nd)
|
|
|
{
|
|
|
struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
|
|
|
- struct ncsi_package *np;
|
|
|
- struct ncsi_channel *nc;
|
|
|
- int old_state, ret;
|
|
|
+ int ret;
|
|
|
|
|
|
if (nd->state != ncsi_dev_state_registered &&
|
|
|
nd->state != ncsi_dev_state_functional)
|
|
@@ -1163,15 +1199,6 @@ int ncsi_start_dev(struct ncsi_dev *nd)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- /* Reset channel's state and start over */
|
|
|
- NCSI_FOR_EACH_PACKAGE(ndp, np) {
|
|
|
- NCSI_FOR_EACH_CHANNEL(np, nc) {
|
|
|
- old_state = xchg(&nc->state, NCSI_CHANNEL_INACTIVE);
|
|
|
- WARN_ON_ONCE(!list_empty(&nc->link) ||
|
|
|
- old_state == NCSI_CHANNEL_INVISIBLE);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
if (ndp->flags & NCSI_DEV_HWA)
|
|
|
ret = ncsi_enable_hwa(ndp);
|
|
|
else
|
|
@@ -1181,6 +1208,35 @@ int ncsi_start_dev(struct ncsi_dev *nd)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(ncsi_start_dev);
|
|
|
|
|
|
+void ncsi_stop_dev(struct ncsi_dev *nd)
|
|
|
+{
|
|
|
+ struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
|
|
|
+ struct ncsi_package *np;
|
|
|
+ struct ncsi_channel *nc;
|
|
|
+ bool chained;
|
|
|
+ int old_state;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ /* Stop the channel monitor and reset channel's state */
|
|
|
+ NCSI_FOR_EACH_PACKAGE(ndp, np) {
|
|
|
+ NCSI_FOR_EACH_CHANNEL(np, nc) {
|
|
|
+ ncsi_stop_channel_monitor(nc);
|
|
|
+
|
|
|
+ spin_lock_irqsave(&nc->lock, flags);
|
|
|
+ chained = !list_empty(&nc->link);
|
|
|
+ old_state = nc->state;
|
|
|
+ nc->state = NCSI_CHANNEL_INACTIVE;
|
|
|
+ spin_unlock_irqrestore(&nc->lock, flags);
|
|
|
+
|
|
|
+ WARN_ON_ONCE(chained ||
|
|
|
+ old_state == NCSI_CHANNEL_INVISIBLE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ncsi_report_link(ndp, true);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(ncsi_stop_dev);
|
|
|
+
|
|
|
void ncsi_unregister_dev(struct ncsi_dev *nd)
|
|
|
{
|
|
|
struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
|