[PATCH 4.7 3/4] net/ncsi: Choose hot channel as active one if necessary
Joel Stanley
joel at jms.id.au
Fri Oct 21 13:20:39 AEDT 2016
On Fri, Oct 21, 2016 at 9:41 AM, Gavin Shan <gwshan at linux.vnet.ibm.com> wrote:
> The issue was found on BCM5718 which has two NCSI channels in one
> package: C0 and C1. C0 is in link-up state while C1 is in link-down
> state. C0 is chosen as active channel until unplugging and plugging
> C0's cable: On unplugging C0's cable, LSC (Link State Change) AEN
> packet received on C0 to report link-down event. After that, C1 is
> chosen as active channel. LSC AEN for link-up event is lost on C0
> when plugging C0's cable back. We lose the network even C0 is usable.
>
> This resolves the issue by recording the (hot) channel that was ever
> chosen as active one. The hot channel is chosen to be active one
> if none of available channels in link-up state. With this, C0 is still
> the active one after unplugging C0's cable. LSC AEN packet received
> on C0 when plugging its cable back.
>
> Signed-off-by: Gavin Shan <gwshan at linux.vnet.ibm.com>
> ---
> net/ncsi/internal.h | 1 +
> net/ncsi/ncsi-manage.c | 22 +++++++++++++++++++---
> 2 files changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
> index eac4858..1308a56 100644
> --- a/net/ncsi/internal.h
> +++ b/net/ncsi/internal.h
> @@ -265,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
> diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
> index 4789f86..a3bd5fa 100644
> --- a/net/ncsi/ncsi-manage.c
> +++ b/net/ncsi/ncsi-manage.c
> @@ -645,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;
> @@ -750,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;
> @@ -773,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);
> +
Can you explain why we need to take a lock here?
> /* The search is done once an inactive channel with up
> * link is found.
> */
> @@ -794,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);
> --
> 2.1.0
>
More information about the openbmc
mailing list