diff options
| -rw-r--r-- | drivers/net/ethernet/faraday/ftgmac100.c | 2 | ||||
| -rw-r--r-- | include/net/ncsi.h | 5 | ||||
| -rw-r--r-- | net/ncsi/internal.h | 22 | ||||
| -rw-r--r-- | net/ncsi/ncsi-aen.c | 37 | ||||
| -rw-r--r-- | net/ncsi/ncsi-cmd.c | 2 | ||||
| -rw-r--r-- | net/ncsi/ncsi-manage.c | 198 | ||||
| -rw-r--r-- | net/ncsi/ncsi-rsp.c | 4 | 
7 files changed, 180 insertions, 90 deletions
| diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 90f9c5481290..262587240c86 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -1190,6 +1190,8 @@ static int ftgmac100_stop(struct net_device *netdev)  	napi_disable(&priv->napi);  	if (netdev->phydev)  		phy_stop(netdev->phydev); +	else if (priv->use_ncsi) +		ncsi_stop_dev(priv->ndev);  	ftgmac100_stop_hw(priv);  	free_irq(priv->irq, netdev); diff --git a/include/net/ncsi.h b/include/net/ncsi.h index 1dbf42f79750..68680baac0fd 100644 --- a/include/net/ncsi.h +++ b/include/net/ncsi.h @@ -31,6 +31,7 @@ struct ncsi_dev {  struct ncsi_dev *ncsi_register_dev(struct net_device *dev,  				   void (*notifier)(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);  #else /* !CONFIG_NET_NCSI */  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;  } +static void ncsi_stop_dev(struct ncsi_dev *nd) +{ +} +  static inline void ncsi_unregister_dev(struct ncsi_dev *nd)  {  } diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h index 33738c060547..13290a70fa71 100644 --- a/net/ncsi/internal.h +++ b/net/ncsi/internal.h @@ -170,6 +170,7 @@ struct ncsi_package;  #define NCSI_PACKAGE_SHIFT	5  #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_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_filter  *filters[NCSI_FILTER_MAX];  	struct ncsi_channel_stats   stats; -	struct timer_list           timer;	/* Link monitor timer  */ -	bool                        enabled;	/* Timer is enabled    */ -	unsigned int                timeout;	/* Times of timeout    */ +	struct { +		struct timer_list   timer; +		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            link;  }; @@ -206,7 +213,8 @@ struct ncsi_package {  struct ncsi_request {  	unsigned char        id;      /* Request ID - 0 to 255           */  	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 sk_buff       *cmd;    /* Associated NCSI command 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 ncsi_request requests[256];   /* Request table              */  	unsigned int        request_id;      /* Last used request ID       */ +#define NCSI_REQ_START_IDX	1  	unsigned int        pending_req_num; /* Number of pending requests */  	struct ncsi_package *active_package; /* Currently handled package  */  	struct ncsi_channel *active_channel; /* Currently handled channel  */ @@ -274,7 +283,7 @@ struct ncsi_cmd_arg {  	unsigned char        package;     /* Destination package ID        */  	unsigned char        channel;     /* Detination channel ID or 0x1f */  	unsigned short       payload;     /* Command packet payload length */ -	bool                 driven;      /* Drive the state machine?      */ +	unsigned int         req_flags;   /* NCSI request properties       */  	union {  		unsigned char  bytes[16]; /* Command packet specific data  */  		unsigned short words[8]; @@ -313,7 +322,8 @@ void ncsi_find_package_and_channel(struct ncsi_dev_priv *ndp,  				   unsigned char id,  				   struct ncsi_package **np,  				   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);  struct ncsi_dev *ncsi_find_dev(struct net_device *dev);  int ncsi_process_next_channel(struct ncsi_dev_priv *ndp); diff --git a/net/ncsi/ncsi-aen.c b/net/ncsi/ncsi-aen.c index d463468442ae..b41a6617d498 100644 --- a/net/ncsi/ncsi-aen.c +++ b/net/ncsi/ncsi-aen.c @@ -53,7 +53,9 @@ static int ncsi_aen_handler_lsc(struct ncsi_dev_priv *ndp,  	struct ncsi_aen_lsc_pkt *lsc;  	struct ncsi_channel *nc;  	struct ncsi_channel_mode *ncm; -	unsigned long old_data; +	bool chained; +	int state; +	unsigned long old_data, data;  	unsigned long flags;  	/* Find the NCSI channel */ @@ -62,20 +64,27 @@ static int ncsi_aen_handler_lsc(struct ncsi_dev_priv *ndp,  		return -ENODEV;  	/* Update the link status */ -	ncm = &nc->modes[NCSI_MODE_LINK];  	lsc = (struct ncsi_aen_lsc_pkt *)h; + +	spin_lock_irqsave(&nc->lock, flags); +	ncm = &nc->modes[NCSI_MODE_LINK];  	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); -	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; -	if (!(nc->state == NCSI_CHANNEL_INACTIVE && (ncm->data[2] & 0x1)) && -	    !(nc->state == NCSI_CHANNEL_ACTIVE && !(ncm->data[2] & 0x1))) +	if (!(state == NCSI_CHANNEL_INACTIVE && (data & 0x1)) && +	    !(state == NCSI_CHANNEL_ACTIVE && !(data & 0x1)))  		return 0;  	if (!(ndp->flags & NCSI_DEV_HWA) && -	    nc->state == NCSI_CHANNEL_ACTIVE) +	    state == NCSI_CHANNEL_ACTIVE)  		ndp->flags |= NCSI_DEV_RESHUFFLE;  	ncsi_stop_channel_monitor(nc); @@ -97,13 +106,21 @@ static int ncsi_aen_handler_cr(struct ncsi_dev_priv *ndp,  	if (!nc)  		return -ENODEV; +	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);  		return 0; +	} +	spin_unlock_irqrestore(&nc->lock, flags);  	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); -	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); diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c index 21057a8ceeac..db7083bfd476 100644 --- a/net/ncsi/ncsi-cmd.c +++ b/net/ncsi/ncsi-cmd.c @@ -272,7 +272,7 @@ static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca)  	struct sk_buff *skb;  	struct ncsi_request *nr; -	nr = ncsi_alloc_request(ndp, nca->driven); +	nr = ncsi_alloc_request(ndp, nca->req_flags);  	if (!nr)  		return NULL; diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c index ef017b871857..5e509e547c2d 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)  	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); diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c index af84389a6bf1..087db775b3dc 100644 --- a/net/ncsi/ncsi-rsp.c +++ b/net/ncsi/ncsi-rsp.c @@ -317,12 +317,12 @@ static int ncsi_rsp_handler_gls(struct ncsi_request *nr)  	ncm->data[3] = ntohl(rsp->other);  	ncm->data[4] = ntohl(rsp->oem_status); -	if (nr->driven) +	if (nr->flags & NCSI_REQ_FLAG_EVENT_DRIVEN)  		return 0;  	/* Reset the channel monitor if it has been enabled */  	spin_lock_irqsave(&nc->lock, flags); -	nc->timeout = 0; +	nc->monitor.state = NCSI_CHANNEL_MONITOR_START;  	spin_unlock_irqrestore(&nc->lock, flags);  	return 0; | 
