Message ID | 20210210010213.27553-5-george.mccollister@gmail.com (mailing list archive) |
---|---|
State | Accepted |
Commit | bd62e6f5e6a98f1657cf9c3b632bdb7a2e78d42c |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | add HSR offloading support for DSA switches | expand |
Context | Check | Description |
---|---|---|
netdev/cover_letter | success | Link |
netdev/fixes_present | success | Link |
netdev/patch_count | success | Link |
netdev/tree_selection | success | Clearly marked for net-next |
netdev/subject_prefix | success | Link |
netdev/cc_maintainers | warning | 1 maintainers not CCed: davem@davemloft.net |
netdev/source_inline | success | Was 0 now: 0 |
netdev/verify_signedoff | success | Link |
netdev/module_param | success | Was 0 now: 0 |
netdev/build_32bit | success | Errors and warnings before: 0 this patch: 0 |
netdev/kdoc | success | Errors and warnings before: 0 this patch: 0 |
netdev/verify_fixes | success | Link |
netdev/checkpatch | success | total: 0 errors, 0 warnings, 0 checks, 173 lines checked |
netdev/build_allmodconfig_warn | success | Errors and warnings before: 0 this patch: 0 |
netdev/header_inline | success | Link |
netdev/stable | success | Stable not CCed |
On 2/9/2021 5:02 PM, George McCollister wrote: > Add offloading for HSR/PRP (IEC 62439-3) tag insertion, tag removal > forwarding and duplication supported by the xrs7000 series switches. > > Only HSR v1 and PRP v1 are supported by the xrs7000 series switches (HSR > v0 is not). > > Signed-off-by: George McCollister <george.mccollister@gmail.com> > --- [snip] > + val &= ~BIT(dsa_upstream_port(ds, port)); > + regmap_write(priv->regmap, XRS_PORT_FWD_MASK(partner->index), val); > + regmap_write(priv->regmap, XRS_PORT_FWD_MASK(port), val); > + > + regmap_fields_write(priv->ps_forward, partner->index, > + XRS_PORT_FORWARDING); > + regmap_fields_write(priv->ps_forward, port, XRS_PORT_FORWARDING); > + > + hsr_pair[0] = port; > + hsr_pair[1] = partner->index; > + for (i = 0; i < ARRAY_SIZE(hsr_pair); i++) { > + slave = dsa_to_port(ds, hsr_pair[i])->slave; > + slave->features |= XRS7000X_SUPPORTED_HSR_FEATURES; It's a bit weird to change the supported features while joining, usually you set them ahead of time to indicate what you are capable of doing and those can get toggled by user-space to enable/disable said feature, I suppose the goal here is to influence the HSR data path's decisions to insert or not tags so this may be okay. This does beg several questions: - should slave->vlan_features also include that feature set somehow (can I have a VLAN upper?) - should there be a notifier running to advertise NETDEV_FEAT_CHANGE?
On Tue, Feb 09, 2021 at 08:11:15PM -0800, Florian Fainelli wrote: > > > On 2/9/2021 5:02 PM, George McCollister wrote: > > Add offloading for HSR/PRP (IEC 62439-3) tag insertion, tag removal > > forwarding and duplication supported by the xrs7000 series switches. > > > > Only HSR v1 and PRP v1 are supported by the xrs7000 series switches (HSR > > v0 is not). > > > > Signed-off-by: George McCollister <george.mccollister@gmail.com> > > --- > [snip] > > + val &= ~BIT(dsa_upstream_port(ds, port)); > > + regmap_write(priv->regmap, XRS_PORT_FWD_MASK(partner->index), val); > > + regmap_write(priv->regmap, XRS_PORT_FWD_MASK(port), val); > > + > > + regmap_fields_write(priv->ps_forward, partner->index, > > + XRS_PORT_FORWARDING); > > + regmap_fields_write(priv->ps_forward, port, XRS_PORT_FORWARDING); > > + > > + hsr_pair[0] = port; > > + hsr_pair[1] = partner->index; > > + for (i = 0; i < ARRAY_SIZE(hsr_pair); i++) { > > + slave = dsa_to_port(ds, hsr_pair[i])->slave; > > + slave->features |= XRS7000X_SUPPORTED_HSR_FEATURES; > > It's a bit weird to change the supported features while joining, usually > you set them ahead of time to indicate what you are capable of doing and > those can get toggled by user-space to enable/disable said feature, I > suppose the goal here is to influence the HSR data path's decisions to > insert or not tags so this may be okay. This does beg several questions: > > - should slave->vlan_features also include that feature set somehow (can > I have a VLAN upper?) hsr_check_dev_ok: if (is_vlan_dev(dev)) { NL_SET_ERR_MSG_MOD(extack, "HSR on top of VLAN is not yet supported in this driver."); return -EINVAL; } > - should there be a notifier running to advertise NETDEV_FEAT_CHANGE? I felt it's a bit weird too to toggle the netdev flags just like that instead of just enabling them at probe time or something (or have DSA set them in dsa_slave_create(), just as it currently checks ds->ops->port_vlan_add), but since there's no need for anyone to process that notification, and there don't appear to be any strict guidelines, I didn't say anything. I guess the current code is just fine for what is needed at the moment. Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
diff --git a/drivers/net/dsa/xrs700x/xrs700x.c b/drivers/net/dsa/xrs700x/xrs700x.c index 259f5e657c46..f025f968f96d 100644 --- a/drivers/net/dsa/xrs700x/xrs700x.c +++ b/drivers/net/dsa/xrs700x/xrs700x.c @@ -7,11 +7,17 @@ #include <net/dsa.h> #include <linux/if_bridge.h> #include <linux/of_device.h> +#include <linux/netdev_features.h> +#include <linux/if_hsr.h> #include "xrs700x.h" #include "xrs700x_reg.h" #define XRS700X_MIB_INTERVAL msecs_to_jiffies(3000) +#define XRS7000X_SUPPORTED_HSR_FEATURES \ + (NETIF_F_HW_HSR_TAG_INS | NETIF_F_HW_HSR_TAG_RM | \ + NETIF_F_HW_HSR_FWD | NETIF_F_HW_HSR_DUP) + #define XRS7003E_ID 0x100 #define XRS7003F_ID 0x101 #define XRS7004E_ID 0x200 @@ -496,6 +502,119 @@ static void xrs700x_bridge_leave(struct dsa_switch *ds, int port, xrs700x_bridge_common(ds, port, bridge, false); } +static int xrs700x_hsr_join(struct dsa_switch *ds, int port, + struct net_device *hsr) +{ + unsigned int val = XRS_HSR_CFG_HSR_PRP; + struct dsa_port *partner = NULL, *dp; + struct xrs700x *priv = ds->priv; + struct net_device *slave; + int ret, i, hsr_pair[2]; + enum hsr_version ver; + + ret = hsr_get_version(hsr, &ver); + if (ret) + return ret; + + /* Only ports 1 and 2 can be HSR/PRP redundant ports. */ + if (port != 1 && port != 2) + return -EOPNOTSUPP; + + if (ver == HSR_V1) + val |= XRS_HSR_CFG_HSR; + else if (ver == PRP_V1) + val |= XRS_HSR_CFG_PRP; + else + return -EOPNOTSUPP; + + dsa_hsr_foreach_port(dp, ds, hsr) { + partner = dp; + } + + /* We can't enable redundancy on the switch until both + * redundant ports have signed up. + */ + if (!partner) + return 0; + + regmap_fields_write(priv->ps_forward, partner->index, + XRS_PORT_DISABLED); + regmap_fields_write(priv->ps_forward, port, XRS_PORT_DISABLED); + + regmap_write(priv->regmap, XRS_HSR_CFG(partner->index), + val | XRS_HSR_CFG_LANID_A); + regmap_write(priv->regmap, XRS_HSR_CFG(port), + val | XRS_HSR_CFG_LANID_B); + + /* Clear bits for both redundant ports (HSR only) and the CPU port to + * enable forwarding. + */ + val = GENMASK(ds->num_ports - 1, 0); + if (ver == HSR_V1) { + val &= ~BIT(partner->index); + val &= ~BIT(port); + } + val &= ~BIT(dsa_upstream_port(ds, port)); + regmap_write(priv->regmap, XRS_PORT_FWD_MASK(partner->index), val); + regmap_write(priv->regmap, XRS_PORT_FWD_MASK(port), val); + + regmap_fields_write(priv->ps_forward, partner->index, + XRS_PORT_FORWARDING); + regmap_fields_write(priv->ps_forward, port, XRS_PORT_FORWARDING); + + hsr_pair[0] = port; + hsr_pair[1] = partner->index; + for (i = 0; i < ARRAY_SIZE(hsr_pair); i++) { + slave = dsa_to_port(ds, hsr_pair[i])->slave; + slave->features |= XRS7000X_SUPPORTED_HSR_FEATURES; + } + + return 0; +} + +static int xrs700x_hsr_leave(struct dsa_switch *ds, int port, + struct net_device *hsr) +{ + struct dsa_port *partner = NULL, *dp; + struct xrs700x *priv = ds->priv; + struct net_device *slave; + int i, hsr_pair[2]; + unsigned int val; + + dsa_hsr_foreach_port(dp, ds, hsr) { + partner = dp; + } + + if (!partner) + return 0; + + regmap_fields_write(priv->ps_forward, partner->index, + XRS_PORT_DISABLED); + regmap_fields_write(priv->ps_forward, port, XRS_PORT_DISABLED); + + regmap_write(priv->regmap, XRS_HSR_CFG(partner->index), 0); + regmap_write(priv->regmap, XRS_HSR_CFG(port), 0); + + /* Clear bit for the CPU port to enable forwarding. */ + val = GENMASK(ds->num_ports - 1, 0); + val &= ~BIT(dsa_upstream_port(ds, port)); + regmap_write(priv->regmap, XRS_PORT_FWD_MASK(partner->index), val); + regmap_write(priv->regmap, XRS_PORT_FWD_MASK(port), val); + + regmap_fields_write(priv->ps_forward, partner->index, + XRS_PORT_FORWARDING); + regmap_fields_write(priv->ps_forward, port, XRS_PORT_FORWARDING); + + hsr_pair[0] = port; + hsr_pair[1] = partner->index; + for (i = 0; i < ARRAY_SIZE(hsr_pair); i++) { + slave = dsa_to_port(ds, hsr_pair[i])->slave; + slave->features &= ~XRS7000X_SUPPORTED_HSR_FEATURES; + } + + return 0; +} + static const struct dsa_switch_ops xrs700x_ops = { .get_tag_protocol = xrs700x_get_tag_protocol, .setup = xrs700x_setup, @@ -509,6 +628,8 @@ static const struct dsa_switch_ops xrs700x_ops = { .get_stats64 = xrs700x_get_stats64, .port_bridge_join = xrs700x_bridge_join, .port_bridge_leave = xrs700x_bridge_leave, + .port_hsr_join = xrs700x_hsr_join, + .port_hsr_leave = xrs700x_hsr_leave, }; static int xrs700x_detect(struct xrs700x *priv) diff --git a/drivers/net/dsa/xrs700x/xrs700x_reg.h b/drivers/net/dsa/xrs700x/xrs700x_reg.h index a135d4d92b6d..470d00e07f15 100644 --- a/drivers/net/dsa/xrs700x/xrs700x_reg.h +++ b/drivers/net/dsa/xrs700x/xrs700x_reg.h @@ -49,6 +49,11 @@ /* Port Configuration Registers - HSR/PRP */ #define XRS_HSR_CFG(x) (XRS_PORT_HSR_BASE(x) + 0x0) +#define XRS_HSR_CFG_HSR_PRP BIT(0) +#define XRS_HSR_CFG_HSR 0 +#define XRS_HSR_CFG_PRP BIT(8) +#define XRS_HSR_CFG_LANID_A 0 +#define XRS_HSR_CFG_LANID_B BIT(10) /* Port Configuration Registers - PTP */ #define XRS_PTP_RX_SYNC_DELAY_NS_LO(x) (XRS_PORT_PTP_BASE(x) + 0x2) diff --git a/net/dsa/tag_xrs700x.c b/net/dsa/tag_xrs700x.c index db0ed1a5fcb7..858cdf9d2913 100644 --- a/net/dsa/tag_xrs700x.c +++ b/net/dsa/tag_xrs700x.c @@ -11,12 +11,17 @@ static struct sk_buff *xrs700x_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *partner, *dp = dsa_slave_to_port(dev); u8 *trailer; trailer = skb_put(skb, 1); trailer[0] = BIT(dp->index); + if (dp->hsr_dev) + dsa_hsr_foreach_port(partner, dp->ds, dp->hsr_dev) + if (partner != dp) + trailer[0] |= BIT(partner->index); + return skb; }
Add offloading for HSR/PRP (IEC 62439-3) tag insertion, tag removal forwarding and duplication supported by the xrs7000 series switches. Only HSR v1 and PRP v1 are supported by the xrs7000 series switches (HSR v0 is not). Signed-off-by: George McCollister <george.mccollister@gmail.com> --- drivers/net/dsa/xrs700x/xrs700x.c | 121 ++++++++++++++++++++++++++++++++++ drivers/net/dsa/xrs700x/xrs700x_reg.h | 5 ++ net/dsa/tag_xrs700x.c | 7 +- 3 files changed, 132 insertions(+), 1 deletion(-)