Merge branch 'ncsi-next'
Gavin Shan says: ==================== net/ncsi: NCSI Improvment and bug fixes This series of patches improves NCSI stack according to the comments I received after the NCSI code was merged to 4.8.rc1: * PATCH[1/8] fixes the build warning caused by xchg() with ia64-linux-gcc. The atomic operations are removed. The NCSI's lock should be taken when reading or updating its state and chained state. * Channel ID (0x1f) is the reserved one and it cannot be valid channel ID. So we needn't try to probe channel whose ID is 0x1f. PATCH[2/8] and PATCH[3/8] are addressing this issue. * The request IDs are assigned in round-robin fashion, but it's broken. PATCH[4/8] make it work. * PATCH[5/8] and PATCH[6/8] reworks the channel monitoring to improve the code readability and its robustness. * PATCH[7/8] and PATCH[8/8] introduces ncsi_stop_dev() so that the network device can be closed and opened afterwards. No error will be seen. Changelog ========= v2: * The NCSI's lock is taken when reading or updating its state as the {READ,WRITE}_ONCE() isn't reliable. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
9a8dd213d2
@ -1190,6 +1190,8 @@ static int ftgmac100_stop(struct net_device *netdev)
|
|||||||
napi_disable(&priv->napi);
|
napi_disable(&priv->napi);
|
||||||
if (netdev->phydev)
|
if (netdev->phydev)
|
||||||
phy_stop(netdev->phydev);
|
phy_stop(netdev->phydev);
|
||||||
|
else if (priv->use_ncsi)
|
||||||
|
ncsi_stop_dev(priv->ndev);
|
||||||
|
|
||||||
ftgmac100_stop_hw(priv);
|
ftgmac100_stop_hw(priv);
|
||||||
free_irq(priv->irq, netdev);
|
free_irq(priv->irq, netdev);
|
||||||
|
@ -31,6 +31,7 @@ struct ncsi_dev {
|
|||||||
struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
|
struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
|
||||||
void (*notifier)(struct ncsi_dev *nd));
|
void (*notifier)(struct ncsi_dev *nd));
|
||||||
int ncsi_start_dev(struct ncsi_dev *nd);
|
int ncsi_start_dev(struct ncsi_dev *nd);
|
||||||
|
void ncsi_stop_dev(struct ncsi_dev *nd);
|
||||||
void ncsi_unregister_dev(struct ncsi_dev *nd);
|
void ncsi_unregister_dev(struct ncsi_dev *nd);
|
||||||
#else /* !CONFIG_NET_NCSI */
|
#else /* !CONFIG_NET_NCSI */
|
||||||
static inline struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
|
static inline struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
|
||||||
@ -44,6 +45,10 @@ static inline int ncsi_start_dev(struct ncsi_dev *nd)
|
|||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ncsi_stop_dev(struct ncsi_dev *nd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static inline void ncsi_unregister_dev(struct ncsi_dev *nd)
|
static inline void ncsi_unregister_dev(struct ncsi_dev *nd)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -170,6 +170,7 @@ struct ncsi_package;
|
|||||||
|
|
||||||
#define NCSI_PACKAGE_SHIFT 5
|
#define NCSI_PACKAGE_SHIFT 5
|
||||||
#define NCSI_PACKAGE_INDEX(c) (((c) >> NCSI_PACKAGE_SHIFT) & 0x7)
|
#define NCSI_PACKAGE_INDEX(c) (((c) >> NCSI_PACKAGE_SHIFT) & 0x7)
|
||||||
|
#define NCSI_RESERVED_CHANNEL 0x1f
|
||||||
#define NCSI_CHANNEL_INDEX(c) ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1))
|
#define NCSI_CHANNEL_INDEX(c) ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1))
|
||||||
#define NCSI_TO_CHANNEL(p, c) (((p) << NCSI_PACKAGE_SHIFT) | (c))
|
#define NCSI_TO_CHANNEL(p, c) (((p) << NCSI_PACKAGE_SHIFT) | (c))
|
||||||
|
|
||||||
@ -186,9 +187,15 @@ struct ncsi_channel {
|
|||||||
struct ncsi_channel_mode modes[NCSI_MODE_MAX];
|
struct ncsi_channel_mode modes[NCSI_MODE_MAX];
|
||||||
struct ncsi_channel_filter *filters[NCSI_FILTER_MAX];
|
struct ncsi_channel_filter *filters[NCSI_FILTER_MAX];
|
||||||
struct ncsi_channel_stats stats;
|
struct ncsi_channel_stats stats;
|
||||||
struct timer_list timer; /* Link monitor timer */
|
struct {
|
||||||
bool enabled; /* Timer is enabled */
|
struct timer_list timer;
|
||||||
unsigned int timeout; /* Times of timeout */
|
bool enabled;
|
||||||
|
unsigned int state;
|
||||||
|
#define NCSI_CHANNEL_MONITOR_START 0
|
||||||
|
#define NCSI_CHANNEL_MONITOR_RETRY 1
|
||||||
|
#define NCSI_CHANNEL_MONITOR_WAIT 2
|
||||||
|
#define NCSI_CHANNEL_MONITOR_WAIT_MAX 5
|
||||||
|
} monitor;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
struct list_head link;
|
struct list_head link;
|
||||||
};
|
};
|
||||||
@ -206,7 +213,8 @@ struct ncsi_package {
|
|||||||
struct ncsi_request {
|
struct ncsi_request {
|
||||||
unsigned char id; /* Request ID - 0 to 255 */
|
unsigned char id; /* Request ID - 0 to 255 */
|
||||||
bool used; /* Request that has been assigned */
|
bool used; /* Request that has been assigned */
|
||||||
bool driven; /* Drive state machine */
|
unsigned int flags; /* NCSI request property */
|
||||||
|
#define NCSI_REQ_FLAG_EVENT_DRIVEN 1
|
||||||
struct ncsi_dev_priv *ndp; /* Associated NCSI device */
|
struct ncsi_dev_priv *ndp; /* Associated NCSI device */
|
||||||
struct sk_buff *cmd; /* Associated NCSI command packet */
|
struct sk_buff *cmd; /* Associated NCSI command packet */
|
||||||
struct sk_buff *rsp; /* Associated NCSI response packet */
|
struct sk_buff *rsp; /* Associated NCSI response packet */
|
||||||
@ -258,6 +266,7 @@ struct ncsi_dev_priv {
|
|||||||
struct list_head packages; /* List of packages */
|
struct list_head packages; /* List of packages */
|
||||||
struct ncsi_request requests[256]; /* Request table */
|
struct ncsi_request requests[256]; /* Request table */
|
||||||
unsigned int request_id; /* Last used request ID */
|
unsigned int request_id; /* Last used request ID */
|
||||||
|
#define NCSI_REQ_START_IDX 1
|
||||||
unsigned int pending_req_num; /* Number of pending requests */
|
unsigned int pending_req_num; /* Number of pending requests */
|
||||||
struct ncsi_package *active_package; /* Currently handled package */
|
struct ncsi_package *active_package; /* Currently handled package */
|
||||||
struct ncsi_channel *active_channel; /* Currently handled channel */
|
struct ncsi_channel *active_channel; /* Currently handled channel */
|
||||||
@ -274,7 +283,7 @@ struct ncsi_cmd_arg {
|
|||||||
unsigned char package; /* Destination package ID */
|
unsigned char package; /* Destination package ID */
|
||||||
unsigned char channel; /* Detination channel ID or 0x1f */
|
unsigned char channel; /* Detination channel ID or 0x1f */
|
||||||
unsigned short payload; /* Command packet payload length */
|
unsigned short payload; /* Command packet payload length */
|
||||||
bool driven; /* Drive the state machine? */
|
unsigned int req_flags; /* NCSI request properties */
|
||||||
union {
|
union {
|
||||||
unsigned char bytes[16]; /* Command packet specific data */
|
unsigned char bytes[16]; /* Command packet specific data */
|
||||||
unsigned short words[8];
|
unsigned short words[8];
|
||||||
@ -313,7 +322,8 @@ void ncsi_find_package_and_channel(struct ncsi_dev_priv *ndp,
|
|||||||
unsigned char id,
|
unsigned char id,
|
||||||
struct ncsi_package **np,
|
struct ncsi_package **np,
|
||||||
struct ncsi_channel **nc);
|
struct ncsi_channel **nc);
|
||||||
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);
|
||||||
void ncsi_free_request(struct ncsi_request *nr);
|
void ncsi_free_request(struct ncsi_request *nr);
|
||||||
struct ncsi_dev *ncsi_find_dev(struct net_device *dev);
|
struct ncsi_dev *ncsi_find_dev(struct net_device *dev);
|
||||||
int ncsi_process_next_channel(struct ncsi_dev_priv *ndp);
|
int ncsi_process_next_channel(struct ncsi_dev_priv *ndp);
|
||||||
|
@ -53,7 +53,9 @@ static int ncsi_aen_handler_lsc(struct ncsi_dev_priv *ndp,
|
|||||||
struct ncsi_aen_lsc_pkt *lsc;
|
struct ncsi_aen_lsc_pkt *lsc;
|
||||||
struct ncsi_channel *nc;
|
struct ncsi_channel *nc;
|
||||||
struct ncsi_channel_mode *ncm;
|
struct ncsi_channel_mode *ncm;
|
||||||
unsigned long old_data;
|
bool chained;
|
||||||
|
int state;
|
||||||
|
unsigned long old_data, data;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
/* Find the NCSI channel */
|
/* Find the NCSI channel */
|
||||||
@ -62,20 +64,27 @@ static int ncsi_aen_handler_lsc(struct ncsi_dev_priv *ndp,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
/* Update the link status */
|
/* Update the link status */
|
||||||
ncm = &nc->modes[NCSI_MODE_LINK];
|
|
||||||
lsc = (struct ncsi_aen_lsc_pkt *)h;
|
lsc = (struct ncsi_aen_lsc_pkt *)h;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&nc->lock, flags);
|
||||||
|
ncm = &nc->modes[NCSI_MODE_LINK];
|
||||||
old_data = ncm->data[2];
|
old_data = ncm->data[2];
|
||||||
ncm->data[2] = ntohl(lsc->status);
|
data = ntohl(lsc->status);
|
||||||
|
ncm->data[2] = data;
|
||||||
ncm->data[4] = ntohl(lsc->oem_status);
|
ncm->data[4] = ntohl(lsc->oem_status);
|
||||||
if (!((old_data ^ ncm->data[2]) & 0x1) ||
|
|
||||||
!list_empty(&nc->link))
|
chained = !list_empty(&nc->link);
|
||||||
|
state = nc->state;
|
||||||
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
|
|
||||||
|
if (!((old_data ^ data) & 0x1) || chained)
|
||||||
return 0;
|
return 0;
|
||||||
if (!(nc->state == NCSI_CHANNEL_INACTIVE && (ncm->data[2] & 0x1)) &&
|
if (!(state == NCSI_CHANNEL_INACTIVE && (data & 0x1)) &&
|
||||||
!(nc->state == NCSI_CHANNEL_ACTIVE && !(ncm->data[2] & 0x1)))
|
!(state == NCSI_CHANNEL_ACTIVE && !(data & 0x1)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!(ndp->flags & NCSI_DEV_HWA) &&
|
if (!(ndp->flags & NCSI_DEV_HWA) &&
|
||||||
nc->state == NCSI_CHANNEL_ACTIVE)
|
state == NCSI_CHANNEL_ACTIVE)
|
||||||
ndp->flags |= NCSI_DEV_RESHUFFLE;
|
ndp->flags |= NCSI_DEV_RESHUFFLE;
|
||||||
|
|
||||||
ncsi_stop_channel_monitor(nc);
|
ncsi_stop_channel_monitor(nc);
|
||||||
@ -97,13 +106,21 @@ static int ncsi_aen_handler_cr(struct ncsi_dev_priv *ndp,
|
|||||||
if (!nc)
|
if (!nc)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&nc->lock, flags);
|
||||||
if (!list_empty(&nc->link) ||
|
if (!list_empty(&nc->link) ||
|
||||||
nc->state != NCSI_CHANNEL_ACTIVE)
|
nc->state != NCSI_CHANNEL_ACTIVE) {
|
||||||
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
|
|
||||||
ncsi_stop_channel_monitor(nc);
|
ncsi_stop_channel_monitor(nc);
|
||||||
|
spin_lock_irqsave(&nc->lock, flags);
|
||||||
|
nc->state = NCSI_CHANNEL_INVISIBLE;
|
||||||
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
|
|
||||||
spin_lock_irqsave(&ndp->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);
|
list_add_tail_rcu(&nc->link, &ndp->channel_queue);
|
||||||
spin_unlock_irqrestore(&ndp->lock, flags);
|
spin_unlock_irqrestore(&ndp->lock, flags);
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca)
|
|||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct ncsi_request *nr;
|
struct ncsi_request *nr;
|
||||||
|
|
||||||
nr = ncsi_alloc_request(ndp, nca->driven);
|
nr = ncsi_alloc_request(ndp, nca->req_flags);
|
||||||
if (!nr)
|
if (!nr)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -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_dev *nd = &ndp->ndev;
|
||||||
struct ncsi_package *np;
|
struct ncsi_package *np;
|
||||||
struct ncsi_channel *nc;
|
struct ncsi_channel *nc;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
nd->state = ncsi_dev_state_functional;
|
nd->state = ncsi_dev_state_functional;
|
||||||
if (force_down) {
|
if (force_down) {
|
||||||
@ -142,14 +143,21 @@ static void ncsi_report_link(struct ncsi_dev_priv *ndp, bool force_down)
|
|||||||
nd->link_up = 0;
|
nd->link_up = 0;
|
||||||
NCSI_FOR_EACH_PACKAGE(ndp, np) {
|
NCSI_FOR_EACH_PACKAGE(ndp, np) {
|
||||||
NCSI_FOR_EACH_CHANNEL(np, nc) {
|
NCSI_FOR_EACH_CHANNEL(np, nc) {
|
||||||
|
spin_lock_irqsave(&nc->lock, flags);
|
||||||
|
|
||||||
if (!list_empty(&nc->link) ||
|
if (!list_empty(&nc->link) ||
|
||||||
nc->state != NCSI_CHANNEL_ACTIVE)
|
nc->state != NCSI_CHANNEL_ACTIVE) {
|
||||||
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) {
|
if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) {
|
||||||
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
nd->link_up = 1;
|
nd->link_up = 1;
|
||||||
goto report;
|
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_package *np = nc->package;
|
||||||
struct ncsi_dev_priv *ndp = np->ndp;
|
struct ncsi_dev_priv *ndp = np->ndp;
|
||||||
struct ncsi_cmd_arg nca;
|
struct ncsi_cmd_arg nca;
|
||||||
bool enabled;
|
bool enabled, chained;
|
||||||
unsigned int timeout;
|
unsigned int monitor_state;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret;
|
int state, ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&nc->lock, flags);
|
spin_lock_irqsave(&nc->lock, flags);
|
||||||
timeout = nc->timeout;
|
state = nc->state;
|
||||||
enabled = nc->enabled;
|
chained = !list_empty(&nc->link);
|
||||||
|
enabled = nc->monitor.enabled;
|
||||||
|
monitor_state = nc->monitor.state;
|
||||||
spin_unlock_irqrestore(&nc->lock, flags);
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
|
|
||||||
if (!enabled || !list_empty(&nc->link))
|
if (!enabled || chained)
|
||||||
return;
|
return;
|
||||||
if (nc->state != NCSI_CHANNEL_INACTIVE &&
|
if (state != NCSI_CHANNEL_INACTIVE &&
|
||||||
nc->state != NCSI_CHANNEL_ACTIVE)
|
state != NCSI_CHANNEL_ACTIVE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(timeout % 2)) {
|
switch (monitor_state) {
|
||||||
|
case NCSI_CHANNEL_MONITOR_START:
|
||||||
|
case NCSI_CHANNEL_MONITOR_RETRY:
|
||||||
nca.ndp = ndp;
|
nca.ndp = ndp;
|
||||||
nca.package = np->id;
|
nca.package = np->id;
|
||||||
nca.channel = nc->id;
|
nca.channel = nc->id;
|
||||||
nca.type = NCSI_PKT_CMD_GLS;
|
nca.type = NCSI_PKT_CMD_GLS;
|
||||||
nca.driven = false;
|
nca.req_flags = 0;
|
||||||
ret = ncsi_xmit_cmd(&nca);
|
ret = ncsi_xmit_cmd(&nca);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
netdev_err(ndp->ndev.dev, "Error %d sending GLS\n",
|
netdev_err(ndp->ndev.dev, "Error %d sending GLS\n",
|
||||||
ret);
|
ret);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout + 1 >= 3) {
|
break;
|
||||||
|
case NCSI_CHANNEL_MONITOR_WAIT ... NCSI_CHANNEL_MONITOR_WAIT_MAX:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
if (!(ndp->flags & NCSI_DEV_HWA) &&
|
if (!(ndp->flags & NCSI_DEV_HWA) &&
|
||||||
nc->state == NCSI_CHANNEL_ACTIVE)
|
state == NCSI_CHANNEL_ACTIVE) {
|
||||||
ncsi_report_link(ndp, true);
|
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);
|
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);
|
list_add_tail_rcu(&nc->link, &ndp->channel_queue);
|
||||||
spin_unlock_irqrestore(&ndp->lock, flags);
|
spin_unlock_irqrestore(&ndp->lock, flags);
|
||||||
ncsi_process_next_channel(ndp);
|
ncsi_process_next_channel(ndp);
|
||||||
@ -207,10 +227,9 @@ static void ncsi_channel_monitor(unsigned long data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&nc->lock, flags);
|
spin_lock_irqsave(&nc->lock, flags);
|
||||||
nc->timeout = timeout + 1;
|
nc->monitor.state++;
|
||||||
nc->enabled = true;
|
|
||||||
spin_unlock_irqrestore(&nc->lock, flags);
|
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)
|
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;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&nc->lock, flags);
|
spin_lock_irqsave(&nc->lock, flags);
|
||||||
WARN_ON_ONCE(nc->enabled);
|
WARN_ON_ONCE(nc->monitor.enabled);
|
||||||
nc->timeout = 0;
|
nc->monitor.enabled = true;
|
||||||
nc->enabled = true;
|
nc->monitor.state = NCSI_CHANNEL_MONITOR_START;
|
||||||
spin_unlock_irqrestore(&nc->lock, flags);
|
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)
|
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;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&nc->lock, flags);
|
spin_lock_irqsave(&nc->lock, flags);
|
||||||
if (!nc->enabled) {
|
if (!nc->monitor.enabled) {
|
||||||
spin_unlock_irqrestore(&nc->lock, flags);
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nc->enabled = false;
|
nc->monitor.enabled = false;
|
||||||
spin_unlock_irqrestore(&nc->lock, flags);
|
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,
|
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->id = id;
|
||||||
nc->package = np;
|
nc->package = np;
|
||||||
nc->state = NCSI_CHANNEL_INACTIVE;
|
nc->state = NCSI_CHANNEL_INACTIVE;
|
||||||
nc->enabled = false;
|
nc->monitor.enabled = false;
|
||||||
setup_timer(&nc->timer, ncsi_channel_monitor, (unsigned long)nc);
|
setup_timer(&nc->monitor.timer,
|
||||||
|
ncsi_channel_monitor, (unsigned long)nc);
|
||||||
spin_lock_init(&nc->lock);
|
spin_lock_init(&nc->lock);
|
||||||
INIT_LIST_HEAD(&nc->link);
|
INIT_LIST_HEAD(&nc->link);
|
||||||
for (index = 0; index < NCSI_CAP_MAX; index++)
|
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
|
* be same. Otherwise, the bogus response might be replied. So
|
||||||
* the available IDs are allocated in round-robin fashion.
|
* 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;
|
struct ncsi_request *nr = NULL;
|
||||||
int i, limit = ARRAY_SIZE(ndp->requests);
|
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 */
|
/* Check if there is one available request until the ceiling */
|
||||||
spin_lock_irqsave(&ndp->lock, flags);
|
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)
|
if (ndp->requests[i].used)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
nr = &ndp->requests[i];
|
nr = &ndp->requests[i];
|
||||||
nr->used = true;
|
nr->used = true;
|
||||||
nr->driven = driven;
|
nr->flags = req_flags;
|
||||||
if (++ndp->request_id >= limit)
|
ndp->request_id = i + 1;
|
||||||
ndp->request_id = 0;
|
goto found;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fail back to check from the starting cursor */
|
/* 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)
|
if (ndp->requests[i].used)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
nr = &ndp->requests[i];
|
nr = &ndp->requests[i];
|
||||||
nr->used = true;
|
nr->used = true;
|
||||||
nr->driven = driven;
|
nr->flags = req_flags;
|
||||||
if (++ndp->request_id >= limit)
|
ndp->request_id = i + 1;
|
||||||
ndp->request_id = 0;
|
goto found;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&ndp->lock, flags);
|
|
||||||
|
|
||||||
|
found:
|
||||||
|
spin_unlock_irqrestore(&ndp->lock, flags);
|
||||||
return nr;
|
return nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +480,7 @@ void ncsi_free_request(struct ncsi_request *nr)
|
|||||||
nr->cmd = NULL;
|
nr->cmd = NULL;
|
||||||
nr->rsp = NULL;
|
nr->rsp = NULL;
|
||||||
nr->used = false;
|
nr->used = false;
|
||||||
driven = nr->driven;
|
driven = !!(nr->flags & NCSI_REQ_FLAG_EVENT_DRIVEN);
|
||||||
spin_unlock_irqrestore(&ndp->lock, flags);
|
spin_unlock_irqrestore(&ndp->lock, flags);
|
||||||
|
|
||||||
if (driven && cmd && --ndp->pending_req_num == 0)
|
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_package *np = ndp->active_package;
|
||||||
struct ncsi_channel *nc = ndp->active_channel;
|
struct ncsi_channel *nc = ndp->active_channel;
|
||||||
struct ncsi_cmd_arg nca;
|
struct ncsi_cmd_arg nca;
|
||||||
|
unsigned long flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
nca.ndp = ndp;
|
nca.ndp = ndp;
|
||||||
nca.driven = true;
|
nca.req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN;
|
||||||
switch (nd->state) {
|
switch (nd->state) {
|
||||||
case ncsi_dev_state_suspend:
|
case ncsi_dev_state_suspend:
|
||||||
nd->state = ncsi_dev_state_suspend_select;
|
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;
|
nca.package = np->id;
|
||||||
if (nd->state == ncsi_dev_state_suspend_select) {
|
if (nd->state == ncsi_dev_state_suspend_select) {
|
||||||
nca.type = NCSI_PKT_CMD_SP;
|
nca.type = NCSI_PKT_CMD_SP;
|
||||||
nca.channel = 0x1f;
|
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||||
if (ndp->flags & NCSI_DEV_HWA)
|
if (ndp->flags & NCSI_DEV_HWA)
|
||||||
nca.bytes[0] = 0;
|
nca.bytes[0] = 0;
|
||||||
else
|
else
|
||||||
@ -544,7 +567,7 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
|
|||||||
nd->state = ncsi_dev_state_suspend_deselect;
|
nd->state = ncsi_dev_state_suspend_deselect;
|
||||||
} else if (nd->state == ncsi_dev_state_suspend_deselect) {
|
} else if (nd->state == ncsi_dev_state_suspend_deselect) {
|
||||||
nca.type = NCSI_PKT_CMD_DP;
|
nca.type = NCSI_PKT_CMD_DP;
|
||||||
nca.channel = 0x1f;
|
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||||
nd->state = ncsi_dev_state_suspend_done;
|
nd->state = ncsi_dev_state_suspend_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,7 +579,9 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case ncsi_dev_state_suspend_done:
|
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);
|
ncsi_process_next_channel(ndp);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -574,10 +599,11 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
|
|||||||
struct ncsi_channel *nc = ndp->active_channel;
|
struct ncsi_channel *nc = ndp->active_channel;
|
||||||
struct ncsi_cmd_arg nca;
|
struct ncsi_cmd_arg nca;
|
||||||
unsigned char index;
|
unsigned char index;
|
||||||
|
unsigned long flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
nca.ndp = ndp;
|
nca.ndp = ndp;
|
||||||
nca.driven = true;
|
nca.req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN;
|
||||||
switch (nd->state) {
|
switch (nd->state) {
|
||||||
case ncsi_dev_state_config:
|
case ncsi_dev_state_config:
|
||||||
case ncsi_dev_state_config_sp:
|
case ncsi_dev_state_config_sp:
|
||||||
@ -590,7 +616,7 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
|
|||||||
else
|
else
|
||||||
nca.bytes[0] = 1;
|
nca.bytes[0] = 1;
|
||||||
nca.package = np->id;
|
nca.package = np->id;
|
||||||
nca.channel = 0x1f;
|
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||||
ret = ncsi_xmit_cmd(&nca);
|
ret = ncsi_xmit_cmd(&nca);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error;
|
goto error;
|
||||||
@ -675,10 +701,12 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
|
|||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
case ncsi_dev_state_config_done:
|
case ncsi_dev_state_config_done:
|
||||||
|
spin_lock_irqsave(&nc->lock, flags);
|
||||||
if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1)
|
if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1)
|
||||||
xchg(&nc->state, NCSI_CHANNEL_ACTIVE);
|
nc->state = NCSI_CHANNEL_ACTIVE;
|
||||||
else
|
else
|
||||||
xchg(&nc->state, NCSI_CHANNEL_INACTIVE);
|
nc->state = NCSI_CHANNEL_INACTIVE;
|
||||||
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
|
|
||||||
ncsi_start_channel_monitor(nc);
|
ncsi_start_channel_monitor(nc);
|
||||||
ncsi_process_next_channel(ndp);
|
ncsi_process_next_channel(ndp);
|
||||||
@ -707,18 +735,25 @@ static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
|
|||||||
found = NULL;
|
found = NULL;
|
||||||
NCSI_FOR_EACH_PACKAGE(ndp, np) {
|
NCSI_FOR_EACH_PACKAGE(ndp, np) {
|
||||||
NCSI_FOR_EACH_CHANNEL(np, nc) {
|
NCSI_FOR_EACH_CHANNEL(np, nc) {
|
||||||
|
spin_lock_irqsave(&nc->lock, flags);
|
||||||
|
|
||||||
if (!list_empty(&nc->link) ||
|
if (!list_empty(&nc->link) ||
|
||||||
nc->state != NCSI_CHANNEL_INACTIVE)
|
nc->state != NCSI_CHANNEL_INACTIVE) {
|
||||||
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
found = nc;
|
found = nc;
|
||||||
|
|
||||||
ncm = &nc->modes[NCSI_MODE_LINK];
|
ncm = &nc->modes[NCSI_MODE_LINK];
|
||||||
if (ncm->data[2] & 0x1) {
|
if (ncm->data[2] & 0x1) {
|
||||||
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
found = nc;
|
found = nc;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -797,7 +832,7 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
nca.ndp = ndp;
|
nca.ndp = ndp;
|
||||||
nca.driven = true;
|
nca.req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN;
|
||||||
switch (nd->state) {
|
switch (nd->state) {
|
||||||
case ncsi_dev_state_probe:
|
case ncsi_dev_state_probe:
|
||||||
nd->state = ncsi_dev_state_probe_deselect;
|
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 */
|
/* Deselect all possible packages */
|
||||||
nca.type = NCSI_PKT_CMD_DP;
|
nca.type = NCSI_PKT_CMD_DP;
|
||||||
nca.channel = 0x1f;
|
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||||
for (index = 0; index < 8; index++) {
|
for (index = 0; index < 8; index++) {
|
||||||
nca.package = index;
|
nca.package = index;
|
||||||
ret = ncsi_xmit_cmd(&nca);
|
ret = ncsi_xmit_cmd(&nca);
|
||||||
@ -823,7 +858,7 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
|
|||||||
/* Select all possible packages */
|
/* Select all possible packages */
|
||||||
nca.type = NCSI_PKT_CMD_SP;
|
nca.type = NCSI_PKT_CMD_SP;
|
||||||
nca.bytes[0] = 1;
|
nca.bytes[0] = 1;
|
||||||
nca.channel = 0x1f;
|
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||||
for (index = 0; index < 8; index++) {
|
for (index = 0; index < 8; index++) {
|
||||||
nca.package = index;
|
nca.package = index;
|
||||||
ret = ncsi_xmit_cmd(&nca);
|
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.type = NCSI_PKT_CMD_SP;
|
||||||
nca.bytes[0] = 1;
|
nca.bytes[0] = 1;
|
||||||
nca.package = ndp->active_package->id;
|
nca.package = ndp->active_package->id;
|
||||||
nca.channel = 0x1f;
|
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||||
ret = ncsi_xmit_cmd(&nca);
|
ret = ncsi_xmit_cmd(&nca);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error;
|
goto error;
|
||||||
@ -884,12 +919,12 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
|
|||||||
nd->state = ncsi_dev_state_probe_cis;
|
nd->state = ncsi_dev_state_probe_cis;
|
||||||
break;
|
break;
|
||||||
case ncsi_dev_state_probe_cis:
|
case ncsi_dev_state_probe_cis:
|
||||||
ndp->pending_req_num = 32;
|
ndp->pending_req_num = NCSI_RESERVED_CHANNEL;
|
||||||
|
|
||||||
/* Clear initial state */
|
/* Clear initial state */
|
||||||
nca.type = NCSI_PKT_CMD_CIS;
|
nca.type = NCSI_PKT_CMD_CIS;
|
||||||
nca.package = ndp->active_package->id;
|
nca.package = ndp->active_package->id;
|
||||||
for (index = 0; index < 0x20; index++) {
|
for (index = 0; index < NCSI_RESERVED_CHANNEL; index++) {
|
||||||
nca.channel = index;
|
nca.channel = index;
|
||||||
ret = ncsi_xmit_cmd(&nca);
|
ret = ncsi_xmit_cmd(&nca);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -933,7 +968,7 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
|
|||||||
/* Deselect the active package */
|
/* Deselect the active package */
|
||||||
nca.type = NCSI_PKT_CMD_DP;
|
nca.type = NCSI_PKT_CMD_DP;
|
||||||
nca.package = ndp->active_package->id;
|
nca.package = ndp->active_package->id;
|
||||||
nca.channel = 0x1f;
|
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||||
ret = ncsi_xmit_cmd(&nca);
|
ret = ncsi_xmit_cmd(&nca);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error;
|
goto error;
|
||||||
@ -987,11 +1022,14 @@ int ncsi_process_next_channel(struct ncsi_dev_priv *ndp)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_state = xchg(&nc->state, NCSI_CHANNEL_INVISIBLE);
|
|
||||||
list_del_init(&nc->link);
|
list_del_init(&nc->link);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ndp->lock, flags);
|
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_channel = nc;
|
||||||
ndp->active_package = nc->package;
|
ndp->active_package = nc->package;
|
||||||
|
|
||||||
@ -1006,7 +1044,7 @@ int ncsi_process_next_channel(struct ncsi_dev_priv *ndp)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
netdev_err(ndp->ndev.dev, "Invalid state 0x%x on %d:%d\n",
|
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);
|
ncsi_report_link(ndp, false);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -1070,7 +1108,7 @@ static int ncsi_inet6addr_event(struct notifier_block *this,
|
|||||||
return NOTIFY_OK;
|
return NOTIFY_OK;
|
||||||
|
|
||||||
nca.ndp = ndp;
|
nca.ndp = ndp;
|
||||||
nca.driven = false;
|
nca.req_flags = 0;
|
||||||
nca.package = np->id;
|
nca.package = np->id;
|
||||||
nca.channel = nc->id;
|
nca.channel = nc->id;
|
||||||
nca.dwords[0] = nc->caps[NCSI_CAP_MC].cap;
|
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 */
|
/* Initialize private NCSI device */
|
||||||
spin_lock_init(&ndp->lock);
|
spin_lock_init(&ndp->lock);
|
||||||
INIT_LIST_HEAD(&ndp->packages);
|
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++) {
|
for (i = 0; i < ARRAY_SIZE(ndp->requests); i++) {
|
||||||
ndp->requests[i].id = i;
|
ndp->requests[i].id = i;
|
||||||
ndp->requests[i].ndp = ndp;
|
ndp->requests[i].ndp = ndp;
|
||||||
@ -1149,9 +1187,7 @@ EXPORT_SYMBOL_GPL(ncsi_register_dev);
|
|||||||
int ncsi_start_dev(struct ncsi_dev *nd)
|
int ncsi_start_dev(struct ncsi_dev *nd)
|
||||||
{
|
{
|
||||||
struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
|
struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
|
||||||
struct ncsi_package *np;
|
int ret;
|
||||||
struct ncsi_channel *nc;
|
|
||||||
int old_state, ret;
|
|
||||||
|
|
||||||
if (nd->state != ncsi_dev_state_registered &&
|
if (nd->state != ncsi_dev_state_registered &&
|
||||||
nd->state != ncsi_dev_state_functional)
|
nd->state != ncsi_dev_state_functional)
|
||||||
@ -1163,15 +1199,6 @@ int ncsi_start_dev(struct ncsi_dev *nd)
|
|||||||
return 0;
|
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)
|
if (ndp->flags & NCSI_DEV_HWA)
|
||||||
ret = ncsi_enable_hwa(ndp);
|
ret = ncsi_enable_hwa(ndp);
|
||||||
else
|
else
|
||||||
@ -1181,6 +1208,35 @@ int ncsi_start_dev(struct ncsi_dev *nd)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ncsi_start_dev);
|
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)
|
void ncsi_unregister_dev(struct ncsi_dev *nd)
|
||||||
{
|
{
|
||||||
struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
|
struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
|
||||||
|
@ -317,12 +317,12 @@ static int ncsi_rsp_handler_gls(struct ncsi_request *nr)
|
|||||||
ncm->data[3] = ntohl(rsp->other);
|
ncm->data[3] = ntohl(rsp->other);
|
||||||
ncm->data[4] = ntohl(rsp->oem_status);
|
ncm->data[4] = ntohl(rsp->oem_status);
|
||||||
|
|
||||||
if (nr->driven)
|
if (nr->flags & NCSI_REQ_FLAG_EVENT_DRIVEN)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Reset the channel monitor if it has been enabled */
|
/* Reset the channel monitor if it has been enabled */
|
||||||
spin_lock_irqsave(&nc->lock, flags);
|
spin_lock_irqsave(&nc->lock, flags);
|
||||||
nc->timeout = 0;
|
nc->monitor.state = NCSI_CHANNEL_MONITOR_START;
|
||||||
spin_unlock_irqrestore(&nc->lock, flags);
|
spin_unlock_irqrestore(&nc->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user