summaryrefslogtreecommitdiff
path: root/drivers/net/dsa/mv88e6xxx/chip.c
diff options
context:
space:
mode:
authorVladimir Oltean <vladimir.oltean@nxp.com>2022-02-23 16:00:49 +0200
committerJakub Kicinski <kuba@kernel.org>2022-02-24 21:31:43 -0800
commitdedd6a009f4191989bee83c1faf66728648a223f (patch)
tree125b63ccd396fec13f6a6874b3e6bbd3a6b10ac6 /drivers/net/dsa/mv88e6xxx/chip.c
parentb99dbdf00bc13ea6aff9c9bba8919a15c2a510df (diff)
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>
Diffstat (limited to 'drivers/net/dsa/mv88e6xxx/chip.c')
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c60
1 files changed, 29 insertions, 31 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 8868110fcc9c..1b9a20bf1bd6 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1625,7 +1625,7 @@ static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
ds = dsa_switch_find(dst->index, dev);
dp = ds ? dsa_to_port(ds, port) : NULL;
- if (dp && dp->lag_dev) {
+ if (dp && dp->lag) {
/* As the PVT is used to limit flooding of
* FORWARD frames, which use the LAG ID as the
* source port, we must translate dev/port to
@@ -1634,7 +1634,7 @@ static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
* (zero-based).
*/
dev = MV88E6XXX_G2_PVT_ADDR_DEV_TRUNK;
- port = dsa_lag_id(dst, dp->lag_dev) - 1;
+ port = dsa_port_lag_id_get(dp) - 1;
}
}
@@ -1672,7 +1672,7 @@ static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- if (dsa_to_port(ds, port)->lag_dev)
+ if (dsa_to_port(ds, port)->lag)
/* Hardware is incapable of fast-aging a LAG through a
* regular ATU move operation. Until we have something
* more fancy in place this is a no-op.
@@ -6176,21 +6176,20 @@ out:
}
static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds,
- struct net_device *lag_dev,
+ struct dsa_lag lag,
struct netdev_lag_upper_info *info)
{
struct mv88e6xxx_chip *chip = ds->priv;
struct dsa_port *dp;
- int id, members = 0;
+ int members = 0;
if (!mv88e6xxx_has_lag(chip))
return false;
- id = dsa_lag_id(ds->dst, lag_dev);
- if (id <= 0 || id > ds->num_lag_ids)
+ if (!lag.id)
return false;
- dsa_lag_foreach_port(dp, ds->dst, lag_dev)
+ dsa_lag_foreach_port(dp, ds->dst, &lag)
/* Includes the port joining the LAG */
members++;
@@ -6210,8 +6209,7 @@ static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds,
return true;
}
-static int mv88e6xxx_lag_sync_map(struct dsa_switch *ds,
- struct net_device *lag_dev)
+static int mv88e6xxx_lag_sync_map(struct dsa_switch *ds, struct dsa_lag lag)
{
struct mv88e6xxx_chip *chip = ds->priv;
struct dsa_port *dp;
@@ -6219,13 +6217,13 @@ static int mv88e6xxx_lag_sync_map(struct dsa_switch *ds,
int id;
/* DSA LAG IDs are one-based, hardware is zero-based */
- id = dsa_lag_id(ds->dst, lag_dev) - 1;
+ id = lag.id - 1;
/* Build the map of all ports to distribute flows destined for
* this LAG. This can be either a local user port, or a DSA
* port if the LAG port is on a remote chip.
*/
- dsa_lag_foreach_port(dp, ds->dst, lag_dev)
+ dsa_lag_foreach_port(dp, ds->dst, &lag)
map |= BIT(dsa_towards_port(ds, dp->ds->index, dp->index));
return mv88e6xxx_g2_trunk_mapping_write(chip, id, map);
@@ -6269,9 +6267,9 @@ static void mv88e6xxx_lag_set_port_mask(u16 *mask, int port,
static int mv88e6xxx_lag_sync_masks(struct dsa_switch *ds)
{
struct mv88e6xxx_chip *chip = ds->priv;
- struct net_device *lag_dev;
unsigned int id, num_tx;
struct dsa_port *dp;
+ struct dsa_lag *lag;
int i, err, nth;
u16 mask[8];
u16 ivec;
@@ -6281,7 +6279,7 @@ static int mv88e6xxx_lag_sync_masks(struct dsa_switch *ds)
/* Disable all masks for ports that _are_ members of a LAG. */
dsa_switch_for_each_port(dp, ds) {
- if (!dp->lag_dev)
+ if (!dp->lag)
continue;
ivec &= ~BIT(dp->index);
@@ -6294,12 +6292,12 @@ static int mv88e6xxx_lag_sync_masks(struct dsa_switch *ds)
* are in the Tx set.
*/
dsa_lags_foreach_id(id, ds->dst) {
- lag_dev = dsa_lag_dev(ds->dst, id);
- if (!lag_dev)
+ lag = dsa_lag_by_id(ds->dst, id);
+ if (!lag)
continue;
num_tx = 0;
- dsa_lag_foreach_port(dp, ds->dst, lag_dev) {
+ dsa_lag_foreach_port(dp, ds->dst, lag) {
if (dp->lag_tx_enabled)
num_tx++;
}
@@ -6308,7 +6306,7 @@ static int mv88e6xxx_lag_sync_masks(struct dsa_switch *ds)
continue;
nth = 0;
- dsa_lag_foreach_port(dp, ds->dst, lag_dev) {
+ dsa_lag_foreach_port(dp, ds->dst, lag) {
if (!dp->lag_tx_enabled)
continue;
@@ -6330,14 +6328,14 @@ static int mv88e6xxx_lag_sync_masks(struct dsa_switch *ds)
}
static int mv88e6xxx_lag_sync_masks_map(struct dsa_switch *ds,
- struct net_device *lag_dev)
+ struct dsa_lag lag)
{
int err;
err = mv88e6xxx_lag_sync_masks(ds);
if (!err)
- err = mv88e6xxx_lag_sync_map(ds, lag_dev);
+ err = mv88e6xxx_lag_sync_map(ds, lag);
return err;
}
@@ -6354,17 +6352,17 @@ static int mv88e6xxx_port_lag_change(struct dsa_switch *ds, int port)
}
static int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port,
- struct net_device *lag_dev,
+ struct dsa_lag lag,
struct netdev_lag_upper_info *info)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err, id;
- if (!mv88e6xxx_lag_can_offload(ds, lag_dev, info))
+ if (!mv88e6xxx_lag_can_offload(ds, lag, info))
return -EOPNOTSUPP;
/* DSA LAG IDs are one-based */
- id = dsa_lag_id(ds->dst, lag_dev) - 1;
+ id = lag.id - 1;
mv88e6xxx_reg_lock(chip);
@@ -6372,7 +6370,7 @@ static int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port,
if (err)
goto err_unlock;
- err = mv88e6xxx_lag_sync_masks_map(ds, lag_dev);
+ err = mv88e6xxx_lag_sync_masks_map(ds, lag);
if (err)
goto err_clear_trunk;
@@ -6387,13 +6385,13 @@ err_unlock:
}
static int mv88e6xxx_port_lag_leave(struct dsa_switch *ds, int port,
- struct net_device *lag_dev)
+ struct dsa_lag lag)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err_sync, err_trunk;
mv88e6xxx_reg_lock(chip);
- err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag_dev);
+ err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag);
err_trunk = mv88e6xxx_port_set_trunk(chip, port, false, 0);
mv88e6xxx_reg_unlock(chip);
return err_sync ? : err_trunk;
@@ -6412,18 +6410,18 @@ static int mv88e6xxx_crosschip_lag_change(struct dsa_switch *ds, int sw_index,
}
static int mv88e6xxx_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)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- if (!mv88e6xxx_lag_can_offload(ds, lag_dev, info))
+ if (!mv88e6xxx_lag_can_offload(ds, lag, info))
return -EOPNOTSUPP;
mv88e6xxx_reg_lock(chip);
- err = mv88e6xxx_lag_sync_masks_map(ds, lag_dev);
+ err = mv88e6xxx_lag_sync_masks_map(ds, lag);
if (err)
goto unlock;
@@ -6435,13 +6433,13 @@ unlock:
}
static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index,
- int port, struct net_device *lag_dev)
+ int port, struct dsa_lag lag)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err_sync, err_pvt;
mv88e6xxx_reg_lock(chip);
- err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag_dev);
+ err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag);
err_pvt = mv88e6xxx_pvt_map(chip, sw_index, port);
mv88e6xxx_reg_unlock(chip);
return err_sync ? : err_pvt;