Commit 9a8dd213 authored by David S. Miller's avatar David S. Miller
Browse files

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 93409033 2c15f25b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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);
+5 −0
Original line number Diff line number Diff line
@@ -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)
{
}
+16 −6
Original line number Diff line number Diff line
@@ -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);
+27 −10
Original line number Diff line number Diff line
@@ -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);

+1 −1
Original line number Diff line number Diff line
@@ -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;

Loading