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 <xiaoliang.yan...@nxp.com> --- 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