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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
ae3877bce5
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
ndp->pending_req_num = 1;
|
||||
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
ret = ncsi_xmit_cmd(&nca);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
break;
|
||||
case ncsi_dev_state_suspend_deselect:
|
||||
ndp->pending_req_num = 1;
|
||||
|
||||
np = ndp->active_package;
|
||||
nc = ndp->active_channel;
|
||||
nca.type = NCSI_PKT_CMD_DP;
|
||||
nca.package = np->id;
|
||||
if (nd->state == ncsi_dev_state_suspend_select) {
|
||||
nca.type = NCSI_PKT_CMD_SP;
|
||||
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||
if (ndp->flags & NCSI_DEV_HWA)
|
||||
nca.bytes[0] = 0;
|
||||
else
|
||||
nca.bytes[0] = 1;
|
||||
nd->state = ncsi_dev_state_suspend_dcnt;
|
||||
} else if (nd->state == ncsi_dev_state_suspend_dcnt) {
|
||||
nca.type = NCSI_PKT_CMD_DCNT;
|
||||
nca.channel = nc->id;
|
||||
nd->state = ncsi_dev_state_suspend_dc;
|
||||
} else if (nd->state == ncsi_dev_state_suspend_dc) {
|
||||
nca.type = NCSI_PKT_CMD_DC;
|
||||
nca.channel = nc->id;
|
||||
nca.bytes[0] = 1;
|
||||
nd->state = ncsi_dev_state_suspend_deselect;
|
||||
} else if (nd->state == ncsi_dev_state_suspend_deselect) {
|
||||
nca.type = NCSI_PKT_CMD_DP;
|
||||
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||
nd->state = ncsi_dev_state_suspend_done;
|
||||
}
|
||||
nca.channel = NCSI_RESERVED_CHANNEL;
|
||||
|
||||
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 @@ error:
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user