net: dsa: create a dsa_lag structure
The main purpose of this change is to create a data structure for a LAG as seen by DSA. This is similar to what we have for bridging - we pass a copy of this structure by value to ->port_lag_join and ->port_lag_leave. For now we keep the lag_dev, id and a reference count in it. Future patches will add a list of FDB entries for the LAG (these also need to be refcounted to work properly). The LAG structure is created using dsa_port_lag_create() and destroyed using dsa_port_lag_destroy(), just like we have for bridging. Because now, the dsa_lag itself is refcounted, we can simplify dsa_lag_map() and dsa_lag_unmap(). These functions need to keep a LAG in the dst->lags array only as long as at least one port uses it. The refcounting logic inside those functions can be removed now - they are called only when we should perform the operation. dsa_lag_dev() is renamed to dsa_lag_by_id() and now returns the dsa_lag structure instead of the lag_dev net_device. dsa_lag_foreach_port() now takes the dsa_lag structure as argument. dst->lags holds an array of dsa_lag structures. dsa_lag_map() now also saves the dsa_lag->id value, so that linear walking of dst->lags in drivers using dsa_lag_id() is no longer necessary. They can just look at lag.id. dsa_port_lag_id_get() is a helper, similar to dsa_port_bridge_num_get(), which can be used by drivers to get the LAG ID assigned by DSA to a given port. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
b99dbdf00b
commit
dedd6a009f
@@ -116,6 +116,12 @@ struct dsa_netdevice_ops {
|
||||
#define MODULE_ALIAS_DSA_TAG_DRIVER(__proto) \
|
||||
MODULE_ALIAS(DSA_TAG_DRIVER_ALIAS __stringify(__proto##_VALUE))
|
||||
|
||||
struct dsa_lag {
|
||||
struct net_device *dev;
|
||||
unsigned int id;
|
||||
refcount_t refcount;
|
||||
};
|
||||
|
||||
struct dsa_switch_tree {
|
||||
struct list_head list;
|
||||
|
||||
@@ -134,7 +140,7 @@ struct dsa_switch_tree {
|
||||
/* Maps offloaded LAG netdevs to a zero-based linear ID for
|
||||
* drivers that need it.
|
||||
*/
|
||||
struct net_device **lags;
|
||||
struct dsa_lag **lags;
|
||||
|
||||
/* Tagging protocol operations */
|
||||
const struct dsa_device_ops *tag_ops;
|
||||
@@ -170,14 +176,14 @@ struct dsa_switch_tree {
|
||||
|
||||
#define dsa_lag_foreach_port(_dp, _dst, _lag) \
|
||||
list_for_each_entry((_dp), &(_dst)->ports, list) \
|
||||
if ((_dp)->lag_dev == (_lag))
|
||||
if (dsa_port_offloads_lag((_dp), (_lag)))
|
||||
|
||||
#define dsa_hsr_foreach_port(_dp, _ds, _hsr) \
|
||||
list_for_each_entry((_dp), &(_ds)->dst->ports, list) \
|
||||
if ((_dp)->ds == (_ds) && (_dp)->hsr_dev == (_hsr))
|
||||
|
||||
static inline struct net_device *dsa_lag_dev(struct dsa_switch_tree *dst,
|
||||
unsigned int id)
|
||||
static inline struct dsa_lag *dsa_lag_by_id(struct dsa_switch_tree *dst,
|
||||
unsigned int id)
|
||||
{
|
||||
/* DSA LAG IDs are one-based, dst->lags is zero-based */
|
||||
return dst->lags[id - 1];
|
||||
@@ -189,8 +195,10 @@ static inline int dsa_lag_id(struct dsa_switch_tree *dst,
|
||||
unsigned int id;
|
||||
|
||||
dsa_lags_foreach_id(id, dst) {
|
||||
if (dsa_lag_dev(dst, id) == lag_dev)
|
||||
return id;
|
||||
struct dsa_lag *lag = dsa_lag_by_id(dst, id);
|
||||
|
||||
if (lag->dev == lag_dev)
|
||||
return lag->id;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
@@ -293,7 +301,7 @@ struct dsa_port {
|
||||
struct devlink_port devlink_port;
|
||||
struct phylink *pl;
|
||||
struct phylink_config pl_config;
|
||||
struct net_device *lag_dev;
|
||||
struct dsa_lag *lag;
|
||||
struct net_device *hsr_dev;
|
||||
|
||||
struct list_head list;
|
||||
@@ -643,14 +651,30 @@ static inline bool dsa_port_is_vlan_filtering(const struct dsa_port *dp)
|
||||
return dp->vlan_filtering;
|
||||
}
|
||||
|
||||
static inline unsigned int dsa_port_lag_id_get(struct dsa_port *dp)
|
||||
{
|
||||
return dp->lag ? dp->lag->id : 0;
|
||||
}
|
||||
|
||||
static inline struct net_device *dsa_port_lag_dev_get(struct dsa_port *dp)
|
||||
{
|
||||
return dp->lag ? dp->lag->dev : NULL;
|
||||
}
|
||||
|
||||
static inline bool dsa_port_offloads_lag(struct dsa_port *dp,
|
||||
const struct dsa_lag *lag)
|
||||
{
|
||||
return dsa_port_lag_dev_get(dp) == lag->dev;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct net_device *dsa_port_to_bridge_port(const struct dsa_port *dp)
|
||||
{
|
||||
if (!dp->bridge)
|
||||
return NULL;
|
||||
|
||||
if (dp->lag_dev)
|
||||
return dp->lag_dev;
|
||||
if (dp->lag)
|
||||
return dp->lag->dev;
|
||||
else if (dp->hsr_dev)
|
||||
return dp->hsr_dev;
|
||||
|
||||
@@ -968,10 +992,10 @@ struct dsa_switch_ops {
|
||||
int (*crosschip_lag_change)(struct dsa_switch *ds, int sw_index,
|
||||
int port);
|
||||
int (*crosschip_lag_join)(struct dsa_switch *ds, int sw_index,
|
||||
int port, struct net_device *lag_dev,
|
||||
int port, struct dsa_lag lag,
|
||||
struct netdev_lag_upper_info *info);
|
||||
int (*crosschip_lag_leave)(struct dsa_switch *ds, int sw_index,
|
||||
int port, struct net_device *lag_dev);
|
||||
int port, struct dsa_lag lag);
|
||||
|
||||
/*
|
||||
* PTP functionality
|
||||
@@ -1043,10 +1067,10 @@ struct dsa_switch_ops {
|
||||
*/
|
||||
int (*port_lag_change)(struct dsa_switch *ds, int port);
|
||||
int (*port_lag_join)(struct dsa_switch *ds, int port,
|
||||
struct net_device *lag_dev,
|
||||
struct dsa_lag lag,
|
||||
struct netdev_lag_upper_info *info);
|
||||
int (*port_lag_leave)(struct dsa_switch *ds, int port,
|
||||
struct net_device *lag_dev);
|
||||
struct dsa_lag lag);
|
||||
|
||||
/*
|
||||
* HSR integration
|
||||
|
||||
Reference in New Issue
Block a user