Commit e6f44ed6 authored by Gavin Shan's avatar Gavin Shan Committed by David S. Miller

net/ncsi: Package and channel management

This manages NCSI packages and channels:

 * The available packages and channels are enumerated in the first
   time of calling ncsi_start_dev(). The channels' capabilities are
   probed in the meanwhile. The NCSI network topology won't change
   until the NCSI device is destroyed.
 * There in a queue in every NCSI device. The element in the queue,
   channel, is waiting for configuration (bringup) or suspending
   (teardown). The channel's state (inactive/active) indicates the
   futher action (configuration or suspending) will be applied on the
   channel. Another channel's state (invisible) means the requested
   action is being applied.
 * The hardware arbitration will be enabled if all available packages
   and channels support it. All available channels try to provide
   service when hardware arbitration is enabled. Otherwise, one channel
   is selected as the active one at once.
 * When channel is in active state, meaning it's providing service, a
   timer started to retrieve the channe's link status. If the channel's
   link status fails to be updated in the determined period, the channel
   is going to be reconfigured. It's the error handling implementation
   as defined in NCSI spec.
Signed-off-by: default avatarGavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: default avatarJoel Stanley <joel@jms.id.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 138635cc
......@@ -30,6 +30,7 @@ struct ncsi_dev {
#ifdef CONFIG_NET_NCSI
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_unregister_dev(struct ncsi_dev *nd);
#else /* !CONFIG_NET_NCSI */
static inline struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
......@@ -38,6 +39,11 @@ static inline struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
return NULL;
}
static inline int ncsi_start_dev(struct ncsi_dev *nd)
{
return -ENOTTY;
}
static inline void ncsi_unregister_dev(struct ncsi_dev *nd)
{
}
......
......@@ -178,6 +178,7 @@ struct ncsi_channel {
int state;
#define NCSI_CHANNEL_INACTIVE 1
#define NCSI_CHANNEL_ACTIVE 2
#define NCSI_CHANNEL_INVISIBLE 3
spinlock_t lock; /* Protect filters etc */
struct ncsi_package *package;
struct ncsi_channel_version version;
......@@ -185,7 +186,11 @@ 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 list_head node;
struct list_head link;
};
struct ncsi_package {
......@@ -209,14 +214,56 @@ struct ncsi_request {
bool enabled; /* Time has been enabled or not */
};
enum {
ncsi_dev_state_major = 0xff00,
ncsi_dev_state_minor = 0x00ff,
ncsi_dev_state_probe_deselect = 0x0201,
ncsi_dev_state_probe_package,
ncsi_dev_state_probe_channel,
ncsi_dev_state_probe_cis,
ncsi_dev_state_probe_gvi,
ncsi_dev_state_probe_gc,
ncsi_dev_state_probe_gls,
ncsi_dev_state_probe_dp,
ncsi_dev_state_config_sp = 0x0301,
ncsi_dev_state_config_cis,
ncsi_dev_state_config_sma,
ncsi_dev_state_config_ebf,
#if IS_ENABLED(CONFIG_IPV6)
ncsi_dev_state_config_egmf,
#endif
ncsi_dev_state_config_ecnt,
ncsi_dev_state_config_ec,
ncsi_dev_state_config_ae,
ncsi_dev_state_config_gls,
ncsi_dev_state_config_done,
ncsi_dev_state_suspend_select = 0x0401,
ncsi_dev_state_suspend_dcnt,
ncsi_dev_state_suspend_dc,
ncsi_dev_state_suspend_deselect,
ncsi_dev_state_suspend_done
};
struct ncsi_dev_priv {
struct ncsi_dev ndev; /* Associated NCSI device */
unsigned int flags; /* NCSI device flags */
#define NCSI_DEV_PROBED 1 /* Finalized NCSI topology */
#define NCSI_DEV_HWA 2 /* Enabled HW arbitration */
#define NCSI_DEV_RESHUFFLE 4
spinlock_t lock; /* Protect the NCSI device */
#if IS_ENABLED(CONFIG_IPV6)
unsigned int inet6_addr_num; /* Number of IPv6 addresses */
#endif
unsigned int package_num; /* Number of packages */
struct list_head packages; /* List of packages */
struct ncsi_request requests[256]; /* Request table */
unsigned int request_id; /* Last used request ID */
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 */
struct list_head channel_queue; /* Config queue of channels */
struct work_struct work; /* For channel management */
struct packet_type ptype; /* NCSI packet Rx handler */
struct list_head node; /* Form NCSI device list */
};
......@@ -251,6 +298,8 @@ extern spinlock_t ncsi_dev_lock;
int ncsi_find_filter(struct ncsi_channel *nc, int table, void *data);
int ncsi_add_filter(struct ncsi_channel *nc, int table, void *data);
int ncsi_remove_filter(struct ncsi_channel *nc, int table, int index);
void ncsi_start_channel_monitor(struct ncsi_channel *nc);
void ncsi_stop_channel_monitor(struct ncsi_channel *nc);
struct ncsi_channel *ncsi_find_channel(struct ncsi_package *np,
unsigned char id);
struct ncsi_channel *ncsi_add_channel(struct ncsi_package *np,
......@@ -267,6 +316,7 @@ void ncsi_find_package_and_channel(struct ncsi_dev_priv *ndp,
struct ncsi_request *ncsi_alloc_request(struct ncsi_dev_priv *ndp, bool driven);
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);
/* Packet handlers */
u32 ncsi_calculate_checksum(unsigned char *data, int len);
......
This diff is collapsed.
......@@ -69,6 +69,9 @@ static int ncsi_rsp_handler_cis(struct ncsi_request *nr)
rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, &np, &nc);
if (!nc) {
if (ndp->flags & NCSI_DEV_PROBED)
return -ENXIO;
id = NCSI_CHANNEL_INDEX(rsp->rsp.common.channel);
nc = ncsi_add_channel(np, id);
}
......@@ -90,6 +93,9 @@ static int ncsi_rsp_handler_sp(struct ncsi_request *nr)
ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
&np, NULL);
if (!np) {
if (ndp->flags & NCSI_DEV_PROBED)
return -ENXIO;
id = NCSI_PACKAGE_INDEX(rsp->rsp.common.channel);
np = ncsi_add_package(ndp, id);
if (!np)
......@@ -297,6 +303,7 @@ static int ncsi_rsp_handler_gls(struct ncsi_request *nr)
struct ncsi_dev_priv *ndp = nr->ndp;
struct ncsi_channel *nc;
struct ncsi_channel_mode *ncm;
unsigned long flags;
/* Find the package and channel */
rsp = (struct ncsi_rsp_gls_pkt *)skb_network_header(nr->rsp);
......@@ -310,6 +317,14 @@ 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)
return 0;
/* Reset the channel monitor if it has been enabled */
spin_lock_irqsave(&nc->lock, flags);
nc->timeout = 0;
spin_unlock_irqrestore(&nc->lock, flags);
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment