Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

Merge branch 'ncsi-fixes'



Gavin Shan says:

====================
net/ncsi: More bug fixes

This series fixes 2 issues that were found during NCSI's availability
testing on BCM5718 and improves HNCDSC AEN handler:

   * PATCH[1] refactors the code so that minimal code change is put
     to PATCH[2].
   * PATCH[2] fixes the NCSI channel's stale link state before doing
     failover.
   * PATCH[3] chooses the hot channel, which was ever chosen as active
     channel, when the available channels are all in link-down state.
   * PATCH[4] improves Host Network Controller Driver Status Change
     (HNCDSC) AEN handler

Changelog
=========
v2:
   * Merged PATCH[v1 1/2] to PATCH[v2 1].
   * Avoid if/else statements in ncsi_suspend_channel() as Joel suggested.
   * Added comments to explain why we need retrieve last link states in
     ncsi_suspend_channel().
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5712bf9c 22d8aa93
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -246,6 +246,7 @@ enum {
	ncsi_dev_state_config_gls,
	ncsi_dev_state_config_done,
	ncsi_dev_state_suspend_select	= 0x0401,
	ncsi_dev_state_suspend_gls,
	ncsi_dev_state_suspend_dcnt,
	ncsi_dev_state_suspend_dc,
	ncsi_dev_state_suspend_deselect,
@@ -264,6 +265,7 @@ struct ncsi_dev_priv {
#endif
	unsigned int        package_num;     /* Number of packages         */
	struct list_head    packages;        /* List of packages           */
	struct ncsi_channel *hot_channel;    /* Channel was ever active    */
	struct ncsi_request requests[256];   /* Request table              */
	unsigned int        request_id;      /* Last used request ID       */
#define NCSI_REQ_START_IDX	1
+15 −3
Original line number Diff line number Diff line
@@ -141,23 +141,35 @@ static int ncsi_aen_handler_hncdsc(struct ncsi_dev_priv *ndp,
		return -ENODEV;

	/* If the channel is active one, we need reconfigure it */
	spin_lock_irqsave(&nc->lock, flags);
	ncm = &nc->modes[NCSI_MODE_LINK];
	hncdsc = (struct ncsi_aen_hncdsc_pkt *)h;
	ncm->data[3] = ntohl(hncdsc->status);
	if (!list_empty(&nc->link) ||
	    nc->state != NCSI_CHANNEL_ACTIVE ||
	    (ncm->data[3] & 0x1))
	    nc->state != NCSI_CHANNEL_ACTIVE) {
		spin_unlock_irqrestore(&nc->lock, flags);
		return 0;
	}

	if (ndp->flags & NCSI_DEV_HWA)
	spin_unlock_irqrestore(&nc->lock, flags);
	if (!(ndp->flags & NCSI_DEV_HWA) && !(ncm->data[3] & 0x1))
		ndp->flags |= NCSI_DEV_RESHUFFLE;

	/* If this channel is the active one and the link doesn't
	 * work, we have to choose another channel to be active one.
	 * The logic here is exactly similar to what we do when link
	 * is down on the active channel.
	 *
	 * On the other hand, we need configure it when host driver
	 * state on the active channel becomes ready.
	 */
	ncsi_stop_channel_monitor(nc);

	spin_lock_irqsave(&nc->lock, flags);
	nc->state = (ncm->data[3] & 0x1) ? NCSI_CHANNEL_INACTIVE :
					   NCSI_CHANNEL_ACTIVE;
	spin_unlock_irqrestore(&nc->lock, flags);

	spin_lock_irqsave(&ndp->lock, flags);
	list_add_tail_rcu(&nc->link, &ndp->channel_queue);
	spin_unlock_irqrestore(&ndp->lock, flags);
+95 −31
Original line number Diff line number Diff line
@@ -540,42 +540,86 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
		nd->state = ncsi_dev_state_suspend_select;
		/* Fall through */
	case ncsi_dev_state_suspend_select:
	case ncsi_dev_state_suspend_dcnt:
	case ncsi_dev_state_suspend_dc:
	case ncsi_dev_state_suspend_deselect:
		ndp->pending_req_num = 1;

		np = ndp->active_package;
		nc = ndp->active_channel;
		nca.package = np->id;
		if (nd->state == ncsi_dev_state_suspend_select) {
		nca.type = NCSI_PKT_CMD_SP;
		nca.package = np->id;
		nca.channel = NCSI_RESERVED_CHANNEL;
		if (ndp->flags & NCSI_DEV_HWA)
			nca.bytes[0] = 0;
		else
			nca.bytes[0] = 1;

		/* To retrieve the last link states of channels in current
		 * package when current active channel needs fail over to
		 * another one. It means we will possibly select another
		 * channel as next active one. The link states of channels
		 * are most important factor of the selection. So we need
		 * accurate link states. Unfortunately, the link states on
		 * inactive channels can't be updated with LSC AEN in time.
		 */
		if (ndp->flags & NCSI_DEV_RESHUFFLE)
			nd->state = ncsi_dev_state_suspend_gls;
		else
			nd->state = ncsi_dev_state_suspend_dcnt;
		} else if (nd->state == ncsi_dev_state_suspend_dcnt) {
		ret = ncsi_xmit_cmd(&nca);
		if (ret)
			goto error;

		break;
	case ncsi_dev_state_suspend_gls:
		ndp->pending_req_num = np->channel_num;

		nca.type = NCSI_PKT_CMD_GLS;
		nca.package = np->id;

		nd->state = ncsi_dev_state_suspend_dcnt;
		NCSI_FOR_EACH_CHANNEL(np, nc) {
			nca.channel = nc->id;
			ret = ncsi_xmit_cmd(&nca);
			if (ret)
				goto error;
		}

		break;
	case ncsi_dev_state_suspend_dcnt:
		ndp->pending_req_num = 1;

		nca.type = NCSI_PKT_CMD_DCNT;
		nca.package = np->id;
		nca.channel = nc->id;

		nd->state = ncsi_dev_state_suspend_dc;
		} else if (nd->state == ncsi_dev_state_suspend_dc) {
		ret = ncsi_xmit_cmd(&nca);
		if (ret)
			goto error;

		break;
	case ncsi_dev_state_suspend_dc:
		ndp->pending_req_num = 1;

		nca.type = NCSI_PKT_CMD_DC;
		nca.package = np->id;
		nca.channel = nc->id;
		nca.bytes[0] = 1;

		nd->state = ncsi_dev_state_suspend_deselect;
		} else if (nd->state == ncsi_dev_state_suspend_deselect) {
		ret = ncsi_xmit_cmd(&nca);
		if (ret)
			goto error;

		break;
	case ncsi_dev_state_suspend_deselect:
		ndp->pending_req_num = 1;

		nca.type = NCSI_PKT_CMD_DP;
		nca.package = np->id;
		nca.channel = NCSI_RESERVED_CHANNEL;
			nd->state = ncsi_dev_state_suspend_done;
		}

		nd->state = ncsi_dev_state_suspend_done;
		ret = ncsi_xmit_cmd(&nca);
		if (ret) {
			nd->state = ncsi_dev_state_functional;
			return;
		}
		if (ret)
			goto error;

		break;
	case ncsi_dev_state_suspend_done:
@@ -589,6 +633,10 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
		netdev_warn(nd->dev, "Wrong NCSI state 0x%x in suspend\n",
			    nd->state);
	}

	return;
error:
	nd->state = ncsi_dev_state_functional;
}

static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
@@ -597,6 +645,7 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
	struct net_device *dev = nd->dev;
	struct ncsi_package *np = ndp->active_package;
	struct ncsi_channel *nc = ndp->active_channel;
	struct ncsi_channel *hot_nc = NULL;
	struct ncsi_cmd_arg nca;
	unsigned char index;
	unsigned long flags;
@@ -702,12 +751,20 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
		break;
	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) {
			hot_nc = nc;
			nc->state = NCSI_CHANNEL_ACTIVE;
		else
		} else {
			hot_nc = NULL;
			nc->state = NCSI_CHANNEL_INACTIVE;
		}
		spin_unlock_irqrestore(&nc->lock, flags);

		/* Update the hot channel */
		spin_lock_irqsave(&ndp->lock, flags);
		ndp->hot_channel = hot_nc;
		spin_unlock_irqrestore(&ndp->lock, flags);

		ncsi_start_channel_monitor(nc);
		ncsi_process_next_channel(ndp);
		break;
@@ -725,10 +782,14 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
{
	struct ncsi_package *np;
	struct ncsi_channel *nc, *found;
	struct ncsi_channel *nc, *found, *hot_nc;
	struct ncsi_channel_mode *ncm;
	unsigned long flags;

	spin_lock_irqsave(&ndp->lock, flags);
	hot_nc = ndp->hot_channel;
	spin_unlock_irqrestore(&ndp->lock, flags);

	/* The search is done once an inactive channel with up
	 * link is found.
	 */
@@ -746,6 +807,9 @@ static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
			if (!found)
				found = nc;

			if (nc == hot_nc)
				found = nc;

			ncm = &nc->modes[NCSI_MODE_LINK];
			if (ncm->data[2] & 0x1) {
				spin_unlock_irqrestore(&nc->lock, flags);