2020-10-20 17:34:39

by Xiaoliang Yang

[permalink] [raw]
Subject: [RFC, net-next 2/3] net: dsa: felix: add preempt queues set support for vsc9959

VSC9959 support preempt queues according to 802.1qbu and 802.3br. This
patch add ethtool preempt set to configure preemption.

In user space, it can be set like this:
ethtool --set-frame-preemption swp0 enable min-frag-size 0

Signed-off-by: Xiaoliang Yang <[email protected]>
---
drivers/net/dsa/ocelot/felix.c | 26 ++++++++++++++
drivers/net/dsa/ocelot/felix.h | 4 +++
drivers/net/dsa/ocelot/felix_vsc9959.c | 49 ++++++++++++++++++++++++++
include/soc/mscc/ocelot.h | 11 ++++++
include/soc/mscc/ocelot_dev.h | 23 ++++++++++++
5 files changed, 113 insertions(+)

diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index f791860d495f..e08effbeb6bf 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -350,6 +350,30 @@ static int felix_get_ts_info(struct dsa_switch *ds, int port,
return ocelot_get_ts_info(ocelot, port, info);
}

+static int felix_set_preempt(struct dsa_switch *ds, int port,
+ struct ethtool_fp *fpcmd)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct felix *felix = ocelot_to_felix(ocelot);
+
+ if (felix->info->port_set_preempt)
+ return felix->info->port_set_preempt(ocelot, port, fpcmd);
+
+ return -EOPNOTSUPP;
+}
+
+static int felix_get_preempt(struct dsa_switch *ds, int port,
+ struct ethtool_fp *fpcmd)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct felix *felix = ocelot_to_felix(ocelot);
+
+ if (felix->info->port_get_preempt)
+ return felix->info->port_get_preempt(ocelot, port, fpcmd);
+
+ return -EOPNOTSUPP;
+}
+
static int felix_parse_ports_node(struct felix *felix,
struct device_node *ports_node,
phy_interface_t *port_phy_modes)
@@ -777,6 +801,8 @@ const struct dsa_switch_ops felix_switch_ops = {
.get_ethtool_stats = felix_get_ethtool_stats,
.get_sset_count = felix_get_sset_count,
.get_ts_info = felix_get_ts_info,
+ .set_preempt = felix_set_preempt,
+ .get_preempt = felix_get_preempt,
.phylink_validate = felix_phylink_validate,
.phylink_mac_config = felix_phylink_mac_config,
.phylink_mac_link_down = felix_phylink_mac_link_down,
diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
index 4c717324ac2f..e0c93d4a351d 100644
--- a/drivers/net/dsa/ocelot/felix.h
+++ b/drivers/net/dsa/ocelot/felix.h
@@ -37,6 +37,10 @@ struct felix_info {
void (*port_sched_speed_set)(struct ocelot *ocelot, int port,
u32 speed);
void (*xmit_template_populate)(struct ocelot *ocelot, int port);
+ int (*port_set_preempt)(struct ocelot *ocelot, int port,
+ struct ethtool_fp *fpcmd);
+ int (*port_get_preempt)(struct ocelot *ocelot, int port,
+ struct ethtool_fp *fpcmd);
};

extern const struct dsa_switch_ops felix_switch_ops;
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index 3e925b8d5306..c0e41d499639 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -5,6 +5,7 @@
#include <linux/fsl/enetc_mdio.h>
#include <soc/mscc/ocelot_qsys.h>
#include <soc/mscc/ocelot_vcap.h>
+#include <soc/mscc/ocelot_dev.h>
#include <soc/mscc/ocelot_ptp.h>
#include <soc/mscc/ocelot_sys.h>
#include <soc/mscc/ocelot.h>
@@ -340,6 +341,10 @@ static const u32 vsc9959_dev_gmii_regmap[] = {
REG(DEV_MAC_FC_MAC_LOW_CFG, 0x3c),
REG(DEV_MAC_FC_MAC_HIGH_CFG, 0x40),
REG(DEV_MAC_STICKY, 0x44),
+ REG(DEV_MM_ENABLE_CONFIG, 0x48),
+ REG(DEV_MM_VERIF_CONFIG, 0x4c),
+ REG(DEV_MM_STATUS, 0x50),
+
REG_RESERVED(PCS1G_CFG),
REG_RESERVED(PCS1G_MODE_CFG),
REG_RESERVED(PCS1G_SD_CFG),
@@ -1321,6 +1326,48 @@ static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port,
}
}

+static int vsc9959_port_set_preempt(struct ocelot *ocelot, int port,
+ struct ethtool_fp *fpcmd)
+{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ int mm_fragsize = fpcmd->min_frag_size_mult;
+
+ if (mm_fragsize > 3)
+ return -EINVAL;
+
+ ocelot_port_rmwl(ocelot_port,
+ (fpcmd->enabled ?
+ (DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA |
+ DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA) : 0),
+ DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA |
+ DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA,
+ DEV_MM_ENABLE_CONFIG);
+
+ ocelot_rmw_rix(ocelot,
+ QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE(mm_fragsize),
+ QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_M,
+ QSYS_PREEMPTION_CFG,
+ port);
+
+ return 0;
+}
+
+static int vsc9959_port_get_preempt(struct ocelot *ocelot, int port,
+ struct ethtool_fp *fpcmd)
+{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ u32 val;
+
+ val = ocelot_port_readl(ocelot_port, DEV_MM_VERIF_CONFIG);
+ val &= DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS;
+ fpcmd->enabled = (val ? 0 : 1);
+
+ val = ocelot_read(ocelot, QSYS_PREEMPTION_CFG);
+ fpcmd->min_frag_size_mult = QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_X(val);
+
+ return 0;
+}
+
static void vsc9959_xmit_template_populate(struct ocelot *ocelot, int port)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
@@ -1369,6 +1416,8 @@ static const struct felix_info felix_info_vsc9959 = {
.prevalidate_phy_mode = vsc9959_prevalidate_phy_mode,
.port_setup_tc = vsc9959_port_setup_tc,
.port_sched_speed_set = vsc9959_sched_speed_set,
+ .port_set_preempt = vsc9959_port_set_preempt,
+ .port_get_preempt = vsc9959_port_get_preempt,
.xmit_template_populate = vsc9959_xmit_template_populate,
};

diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 1e9db9577441..5ccfbf193ed9 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -426,6 +426,9 @@ enum ocelot_reg {
DEV_MAC_FC_MAC_LOW_CFG,
DEV_MAC_FC_MAC_HIGH_CFG,
DEV_MAC_STICKY,
+ DEV_MM_ENABLE_CONFIG,
+ DEV_MM_VERIF_CONFIG,
+ DEV_MM_STATUS,
PCS1G_CFG,
PCS1G_MODE_CFG,
PCS1G_SD_CFG,
@@ -709,6 +712,14 @@ u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target,
void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target,
u32 val, u32 reg, u32 offset);

+static inline void ocelot_port_rmwl(struct ocelot_port *port, u32 val,
+ u32 mask, u32 reg)
+{
+ u32 cur = ocelot_port_readl(port, reg);
+
+ ocelot_port_writel(port, (cur & (~mask)) | val, reg);
+};
+
/* Hardware initialization */
int ocelot_regfields_init(struct ocelot *ocelot,
const struct reg_field *const regfields);
diff --git a/include/soc/mscc/ocelot_dev.h b/include/soc/mscc/ocelot_dev.h
index 0c6021f02fee..cb1d8f5a62ee 100644
--- a/include/soc/mscc/ocelot_dev.h
+++ b/include/soc/mscc/ocelot_dev.h
@@ -93,6 +93,29 @@
#define DEV_MAC_STICKY_TX_FRM_LEN_OVR_STICKY BIT(1)
#define DEV_MAC_STICKY_TX_ABORT_STICKY BIT(0)

+#define DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA BIT(0)
+#define DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA BIT(4)
+#define DEV_MM_CONFIG_ENABLE_CONFIG_KEEP_S_AFTER_D BIT(8)
+
+#define DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS BIT(0)
+#define DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME(x) (((x) << 4) & GENMASK(11, 4))
+#define DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_M GENMASK(11, 4)
+#define DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_X(x) (((x) & GENMASK(11, 4)) >> 4)
+#define DEV_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS(x) (((x) << 12) & GENMASK(13, 12))
+#define DEV_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS_M GENMASK(13, 12)
+#define DEV_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS_X(x) (((x) & GENMASK(13, 12)) >> 12)
+
+#define DEV_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STATUS BIT(0)
+#define DEV_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STICKY BIT(4)
+#define DEV_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE(x) (((x) << 8) & GENMASK(10, 8))
+#define DEV_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE_M GENMASK(10, 8)
+#define DEV_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE_X(x) (((x) & GENMASK(10, 8)) >> 8)
+#define DEV_MM_STATISTICS_MM_STATUS_UNEXP_RX_PFRM_STICKY BIT(12)
+#define DEV_MM_STATISTICS_MM_STATUS_UNEXP_TX_PFRM_STICKY BIT(16)
+#define DEV_MM_STATISTICS_MM_STATUS_MM_RX_FRAME_STATUS BIT(20)
+#define DEV_MM_STATISTICS_MM_STATUS_MM_TX_FRAME_STATUS BIT(24)
+#define DEV_MM_STATISTICS_MM_STATUS_MM_TX_PRMPT_STATUS BIT(28)
+
#define PCS1G_CFG_LINK_STATUS_TYPE BIT(4)
#define PCS1G_CFG_AN_LINK_CTRL_ENA BIT(1)
#define PCS1G_CFG_PCS_ENA BIT(0)
--
2.18.4


2020-11-06 15:43:46

by Vladimir Oltean

[permalink] [raw]
Subject: Re: [RFC, net-next 2/3] net: dsa: felix: add preempt queues set support for vsc9959

On Tue, Oct 20, 2020 at 12:04:57PM +0800, Xiaoliang Yang wrote:
> +static int vsc9959_port_get_preempt(struct ocelot *ocelot, int port,
> + struct ethtool_fp *fpcmd)
> +{
> + struct ocelot_port *ocelot_port = ocelot->ports[port];
> + u32 val;
> +
> + val = ocelot_port_readl(ocelot_port, DEV_MM_VERIF_CONFIG);
> + val &= DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS;
> + fpcmd->enabled = (val ? 0 : 1);
> +
> + val = ocelot_read(ocelot, QSYS_PREEMPTION_CFG);

You have a bug here. This should be:

val = ocelot_read_rix(ocelot, QSYS_PREEMPTION_CFG, port);

otherwise you're always retrieving the frame preemption configuration of
port 0, regardless of the port passed as argument.

> + fpcmd->min_frag_size_mult = QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_X(val);
> +
> + return 0;
> +}