diff options
author | Christian Marangi <ansuelsmth@gmail.com> | 2022-07-27 14:35:22 +0300 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2022-07-29 08:24:39 +0300 |
commit | e9bbf019af44b204b71ef8edf224002550aab641 (patch) | |
tree | 23a5827d8f02cda79baba1db7b513e609c9c9eb9 /drivers/net/dsa/qca/qca8k-8xxx.c | |
parent | c5290f636624b98e76a82bd63ffec0a8a9daa620 (diff) | |
download | linux-e9bbf019af44b204b71ef8edf224002550aab641.tar.xz |
net: dsa: qca8k: move port LAG functions to common code
The same port LAG functions are used by drivers based on qca8k family
switch. Move them to common code to make them accessible also by other
drivers.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers/net/dsa/qca/qca8k-8xxx.c')
-rw-r--r-- | drivers/net/dsa/qca/qca8k-8xxx.c | 168 |
1 files changed, 0 insertions, 168 deletions
diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index 545f86e3c6ed..4d6ea47a4469 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -1593,174 +1593,6 @@ qca8k_get_tag_protocol(struct dsa_switch *ds, int port, return DSA_TAG_PROTO_QCA; } -static bool -qca8k_lag_can_offload(struct dsa_switch *ds, struct dsa_lag lag, - struct netdev_lag_upper_info *info) -{ - struct dsa_port *dp; - int members = 0; - - if (!lag.id) - return false; - - dsa_lag_foreach_port(dp, ds->dst, &lag) - /* Includes the port joining the LAG */ - members++; - - if (members > QCA8K_NUM_PORTS_FOR_LAG) - return false; - - if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) - return false; - - if (info->hash_type != NETDEV_LAG_HASH_L2 && - info->hash_type != NETDEV_LAG_HASH_L23) - return false; - - return true; -} - -static int -qca8k_lag_setup_hash(struct dsa_switch *ds, struct dsa_lag lag, - struct netdev_lag_upper_info *info) -{ - struct net_device *lag_dev = lag.dev; - struct qca8k_priv *priv = ds->priv; - bool unique_lag = true; - unsigned int i; - u32 hash = 0; - - switch (info->hash_type) { - case NETDEV_LAG_HASH_L23: - hash |= QCA8K_TRUNK_HASH_SIP_EN; - hash |= QCA8K_TRUNK_HASH_DIP_EN; - fallthrough; - case NETDEV_LAG_HASH_L2: - hash |= QCA8K_TRUNK_HASH_SA_EN; - hash |= QCA8K_TRUNK_HASH_DA_EN; - break; - default: /* We should NEVER reach this */ - return -EOPNOTSUPP; - } - - /* Check if we are the unique configured LAG */ - dsa_lags_foreach_id(i, ds->dst) - if (i != lag.id && dsa_lag_by_id(ds->dst, i)) { - unique_lag = false; - break; - } - - /* Hash Mode is global. Make sure the same Hash Mode - * is set to all the 4 possible lag. - * If we are the unique LAG we can set whatever hash - * mode we want. - * To change hash mode it's needed to remove all LAG - * and change the mode with the latest. - */ - if (unique_lag) { - priv->lag_hash_mode = hash; - } else if (priv->lag_hash_mode != hash) { - netdev_err(lag_dev, "Error: Mismatched Hash Mode across different lag is not supported\n"); - return -EOPNOTSUPP; - } - - return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, - QCA8K_TRUNK_HASH_MASK, hash); -} - -static int -qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, - struct dsa_lag lag, bool delete) -{ - struct qca8k_priv *priv = ds->priv; - int ret, id, i; - u32 val; - - /* DSA LAG IDs are one-based, hardware is zero-based */ - id = lag.id - 1; - - /* Read current port member */ - ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); - if (ret) - return ret; - - /* Shift val to the correct trunk */ - val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); - val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; - if (delete) - val &= ~BIT(port); - else - val |= BIT(port); - - /* Update port member. With empty portmap disable trunk */ - ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, - QCA8K_REG_GOL_TRUNK_MEMBER(id) | - QCA8K_REG_GOL_TRUNK_EN(id), - !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | - val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); - - /* Search empty member if adding or port on deleting */ - for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { - ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); - if (ret) - return ret; - - val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); - val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; - - if (delete) { - /* If port flagged to be disabled assume this member is - * empty - */ - if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) - continue; - - val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; - if (val != port) - continue; - } else { - /* If port flagged to be enabled assume this member is - * already set - */ - if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) - continue; - } - - /* We have found the member to add/remove */ - break; - } - - /* Set port in the correct port mask or disable port if in delete mode */ - return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), - QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | - QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), - !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | - port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); -} - -static int -qca8k_port_lag_join(struct dsa_switch *ds, int port, struct dsa_lag lag, - struct netdev_lag_upper_info *info) -{ - int ret; - - if (!qca8k_lag_can_offload(ds, lag, info)) - return -EOPNOTSUPP; - - ret = qca8k_lag_setup_hash(ds, lag, info); - if (ret) - return ret; - - return qca8k_lag_refresh_portmap(ds, port, lag, false); -} - -static int -qca8k_port_lag_leave(struct dsa_switch *ds, int port, - struct dsa_lag lag) -{ - return qca8k_lag_refresh_portmap(ds, port, lag, true); -} - static void qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, bool operational) |