]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'stmmac-taprio'
authorDavid S. Miller <davem@davemloft.net>
Wed, 18 Dec 2019 20:17:11 +0000 (12:17 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 18 Dec 2019 20:17:11 +0000 (12:17 -0800)
Jose Abreu says:

====================
net: stmmac: TSN support using TAPRIO API

This series adds TSN support (EST and Frame Preemption) for stmmac driver.

1) Adds the HW specific support for EST in GMAC5+ cores.

2) Adds the HW specific support for EST in XGMAC3+ cores.

3) Integrates EST HW specific support with TAPRIO scheduler API.

4) Adds the Frame Preemption suppor on stmmac TAPRIO implementation.

5) Adds the HW specific support for Frame Preemption in GMAC5+ cores.

6) Adds the HW specific support for Frame Preemption in XGMAC3+ cores.

7) Adds support for HW debug counters for Frame Preemption available in
GMAC5+ cores.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
14 files changed:
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/dwmac4.h
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
drivers/net/ethernet/stmicro/stmmac/dwmac5.c
drivers/net/ethernet/stmicro/stmmac/dwmac5.h
drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
drivers/net/ethernet/stmicro/stmmac/hwif.h
drivers/net/ethernet/stmicro/stmmac/mmc_core.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
include/linux/stmmac.h

index b210e987a1dbd3675d91cb9043b90e7e2a73498d..09c72025ed3e27b4407bb18b5518db9af76ff2bd 100644 (file)
@@ -363,6 +363,11 @@ struct dma_features {
        unsigned int dvlan;
        unsigned int l3l4fnum;
        unsigned int arpoffsel;
+       /* TSN Features */
+       unsigned int estwid;
+       unsigned int estdep;
+       unsigned int estsel;
+       unsigned int fpesel;
 };
 
 /* GMAC TX FIFO is 8K, Rx FIFO is 16K */
index 2dc70d104161316cfb0285918c5dcabd73cfa5cf..2e6b60a476c6878c8d3da0592fe4b546fa944729 100644 (file)
@@ -64,6 +64,8 @@
 #define GMAC_RXQCTRL_MCBCQEN_SHIFT     20
 #define GMAC_RXQCTRL_TACPQE            BIT(21)
 #define GMAC_RXQCTRL_TACPQE_SHIFT      21
+#define GMAC_RXQCTRL_FPRQ              GENMASK(26, 24)
+#define GMAC_RXQCTRL_FPRQ_SHIFT                24
 
 /* MAC Packet Filtering */
 #define GMAC_PACKET_FILTER_PR          BIT(0)
@@ -176,6 +178,8 @@ enum power_event {
 #define GMAC_CONFIG_SARC               GENMASK(30, 28)
 #define GMAC_CONFIG_SARC_SHIFT         28
 #define GMAC_CONFIG_IPC                        BIT(27)
+#define GMAC_CONFIG_IPG                        GENMASK(26, 24)
+#define GMAC_CONFIG_IPG_SHIFT          24
 #define GMAC_CONFIG_2K                 BIT(22)
 #define GMAC_CONFIG_ACS                        BIT(20)
 #define GMAC_CONFIG_BE                 BIT(18)
@@ -183,6 +187,7 @@ enum power_event {
 #define GMAC_CONFIG_JE                 BIT(16)
 #define GMAC_CONFIG_PS                 BIT(15)
 #define GMAC_CONFIG_FES                        BIT(14)
+#define GMAC_CONFIG_FES_SHIFT          14
 #define GMAC_CONFIG_DM                 BIT(13)
 #define GMAC_CONFIG_LM                 BIT(12)
 #define GMAC_CONFIG_DCRS               BIT(9)
@@ -190,6 +195,9 @@ enum power_event {
 #define GMAC_CONFIG_RE                 BIT(0)
 
 /* MAC extended config */
+#define GMAC_CONFIG_EIPG               GENMASK(29, 25)
+#define GMAC_CONFIG_EIPG_SHIFT         25
+#define GMAC_CONFIG_EIPG_EN            BIT(24)
 #define GMAC_CONFIG_HDSMS              GENMASK(22, 20)
 #define GMAC_CONFIG_HDSMS_SHIFT                20
 #define GMAC_CONFIG_HDSMS_256          (0x2 << GMAC_CONFIG_HDSMS_SHIFT)
@@ -231,6 +239,10 @@ enum power_event {
 
 /* MAC HW features3 bitmap */
 #define GMAC_HW_FEAT_ASP               GENMASK(29, 28)
+#define GMAC_HW_FEAT_FPESEL            BIT(26)
+#define GMAC_HW_FEAT_ESTWID            GENMASK(21, 20)
+#define GMAC_HW_FEAT_ESTDEP            GENMASK(19, 17)
+#define GMAC_HW_FEAT_ESTSEL            BIT(16)
 #define GMAC_HW_FEAT_FRPES             GENMASK(14, 13)
 #define GMAC_HW_FEAT_FRPBS             GENMASK(12, 11)
 #define GMAC_HW_FEAT_FRPSEL            BIT(10)
index 40ca00e596dd7c8594c446dd9a53dd412be2200b..f0c0ea616032bf6c35692028706feb474381deb3 100644 (file)
@@ -984,6 +984,8 @@ const struct stmmac_ops dwmac410_ops = {
        .set_arp_offload = dwmac4_set_arp_offload,
        .config_l3_filter = dwmac4_config_l3_filter,
        .config_l4_filter = dwmac4_config_l4_filter,
+       .est_configure = dwmac5_est_configure,
+       .fpe_configure = dwmac5_fpe_configure,
 };
 
 const struct stmmac_ops dwmac510_ops = {
@@ -1027,6 +1029,8 @@ const struct stmmac_ops dwmac510_ops = {
        .set_arp_offload = dwmac4_set_arp_offload,
        .config_l3_filter = dwmac4_config_l3_filter,
        .config_l4_filter = dwmac4_config_l4_filter,
+       .est_configure = dwmac5_est_configure,
+       .fpe_configure = dwmac5_fpe_configure,
 };
 
 int dwmac4_setup(struct stmmac_priv *priv)
index c15409030710949e35de9d9d54cdab65345fc1de..213d44482ffa14718a0073d8b3b944c71a4216a9 100644 (file)
@@ -404,6 +404,10 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr,
 
        /* 5.10 Features */
        dma_cap->asp = (hw_cap & GMAC_HW_FEAT_ASP) >> 28;
+       dma_cap->fpesel = (hw_cap & GMAC_HW_FEAT_FPESEL) >> 26;
+       dma_cap->estwid = (hw_cap & GMAC_HW_FEAT_ESTWID) >> 20;
+       dma_cap->estdep = (hw_cap & GMAC_HW_FEAT_ESTDEP) >> 17;
+       dma_cap->estsel = (hw_cap & GMAC_HW_FEAT_ESTSEL) >> 16;
        dma_cap->frpes = (hw_cap & GMAC_HW_FEAT_FRPES) >> 13;
        dma_cap->frpbs = (hw_cap & GMAC_HW_FEAT_FRPBS) >> 11;
        dma_cap->frpsel = (hw_cap & GMAC_HW_FEAT_FRPSEL) >> 10;
index e436fa160c7d6a473f46f68c0facc1a31b0dc69a..5d4a3c2458eab4e592d9061456d60dff211914c7 100644 (file)
@@ -550,3 +550,121 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
        writel(val, ioaddr + MAC_PPS_CONTROL);
        return 0;
 }
+
+static int dwmac5_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
+{
+       u32 ctrl;
+
+       writel(val, ioaddr + MTL_EST_GCL_DATA);
+
+       ctrl = (reg << ADDR_SHIFT);
+       ctrl |= gcl ? 0 : GCRR;
+
+       writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
+
+       ctrl |= SRWO;
+       writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
+
+       return readl_poll_timeout(ioaddr + MTL_EST_GCL_CONTROL,
+                                 ctrl, !(ctrl & SRWO), 100, 5000);
+}
+
+int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
+                        unsigned int ptp_rate)
+{
+       u32 speed, total_offset, offset, ctrl, ctr_low;
+       u32 extcfg = readl(ioaddr + GMAC_EXT_CONFIG);
+       u32 mac_cfg = readl(ioaddr + GMAC_CONFIG);
+       int i, ret = 0x0;
+       u64 total_ctr;
+
+       if (extcfg & GMAC_CONFIG_EIPG_EN) {
+               offset = (extcfg & GMAC_CONFIG_EIPG) >> GMAC_CONFIG_EIPG_SHIFT;
+               offset = 104 + (offset * 8);
+       } else {
+               offset = (mac_cfg & GMAC_CONFIG_IPG) >> GMAC_CONFIG_IPG_SHIFT;
+               offset = 96 - (offset * 8);
+       }
+
+       speed = mac_cfg & (GMAC_CONFIG_PS | GMAC_CONFIG_FES);
+       speed = speed >> GMAC_CONFIG_FES_SHIFT;
+
+       switch (speed) {
+       case 0x0:
+               offset = offset * 1000; /* 1G */
+               break;
+       case 0x1:
+               offset = offset * 400; /* 2.5G */
+               break;
+       case 0x2:
+               offset = offset * 100000; /* 10M */
+               break;
+       case 0x3:
+               offset = offset * 10000; /* 100M */
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       offset = offset / 1000;
+
+       ret |= dwmac5_est_write(ioaddr, BTR_LOW, cfg->btr[0], false);
+       ret |= dwmac5_est_write(ioaddr, BTR_HIGH, cfg->btr[1], false);
+       ret |= dwmac5_est_write(ioaddr, TER, cfg->ter, false);
+       ret |= dwmac5_est_write(ioaddr, LLR, cfg->gcl_size, false);
+       if (ret)
+               return ret;
+
+       total_offset = 0;
+       for (i = 0; i < cfg->gcl_size; i++) {
+               ret = dwmac5_est_write(ioaddr, i, cfg->gcl[i] + offset, true);
+               if (ret)
+                       return ret;
+
+               total_offset += offset;
+       }
+
+       total_ctr = cfg->ctr[0] + cfg->ctr[1] * 1000000000;
+       total_ctr += total_offset;
+
+       ctr_low = do_div(total_ctr, 1000000000);
+
+       ret |= dwmac5_est_write(ioaddr, CTR_LOW, ctr_low, false);
+       ret |= dwmac5_est_write(ioaddr, CTR_HIGH, total_ctr, false);
+       if (ret)
+               return ret;
+
+       ctrl = readl(ioaddr + MTL_EST_CONTROL);
+       ctrl &= ~PTOV;
+       ctrl |= ((1000000000 / ptp_rate) * 6) << PTOV_SHIFT;
+       if (cfg->enable)
+               ctrl |= EEST | SSWL;
+       else
+               ctrl &= ~EEST;
+
+       writel(ctrl, ioaddr + MTL_EST_CONTROL);
+       return 0;
+}
+
+void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
+                         bool enable)
+{
+       u32 value;
+
+       if (!enable) {
+               value = readl(ioaddr + MAC_FPE_CTRL_STS);
+
+               value &= ~EFPE;
+
+               writel(value, ioaddr + MAC_FPE_CTRL_STS);
+       }
+
+       value = readl(ioaddr + GMAC_RXQ_CTRL1);
+       value &= ~GMAC_RXQCTRL_FPRQ;
+       value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
+       writel(value, ioaddr + GMAC_RXQ_CTRL1);
+
+       value = readl(ioaddr + MAC_FPE_CTRL_STS);
+       value |= EFPE;
+       writel(value, ioaddr + MAC_FPE_CTRL_STS);
+}
index 23fecf68f781e1c86cb4b67e72cd71573261dd42..3e8faa96b4d4051317514daf6182bd579a23d6fb 100644 (file)
@@ -11,6 +11,9 @@
 #define PRTYEN                         BIT(1)
 #define TMOUTEN                                BIT(0)
 
+#define MAC_FPE_CTRL_STS               0x00000234
+#define EFPE                           BIT(0)
+
 #define MAC_PPS_CONTROL                        0x00000b70
 #define PPS_MAXIDX(x)                  ((((x) + 1) * 8) - 1)
 #define PPS_MINIDX(x)                  ((x) * 8)
 #define MAC_PPSx_INTERVAL(x)           (0x00000b88 + ((x) * 0x10))
 #define MAC_PPSx_WIDTH(x)              (0x00000b8c + ((x) * 0x10))
 
+#define MTL_EST_CONTROL                        0x00000c50
+#define PTOV                           GENMASK(31, 24)
+#define PTOV_SHIFT                     24
+#define SSWL                           BIT(1)
+#define EEST                           BIT(0)
+#define MTL_EST_GCL_CONTROL            0x00000c80
+#define BTR_LOW                                0x0
+#define BTR_HIGH                       0x1
+#define CTR_LOW                                0x2
+#define CTR_HIGH                       0x3
+#define TER                            0x4
+#define LLR                            0x5
+#define ADDR_SHIFT                     8
+#define GCRR                           BIT(2)
+#define SRWO                           BIT(0)
+#define MTL_EST_GCL_DATA               0x00000c84
+
 #define MTL_RXP_CONTROL_STATUS         0x00000ca0
 #define RXPI                           BIT(31)
 #define NPE                            GENMASK(23, 16)
@@ -83,5 +103,9 @@ int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
 int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
                           struct stmmac_pps_cfg *cfg, bool enable,
                           u32 sub_second_inc, u32 systime_flags);
+int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
+                        unsigned int ptp_rate);
+void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
+                         bool enable);
 
 #endif /* __DWMAC5_H__ */
index 158cf4ad1596f7e72374c8aac95cb2f5a93f1a46..174b903a82114700a5e9a03beb091cb9bafe5d3a 100644 (file)
@@ -73,6 +73,9 @@
 #define XGMAC_RXQ_CTRL0                        0x000000a0
 #define XGMAC_RXQEN(x)                 GENMASK((x) * 2 + 1, (x) * 2)
 #define XGMAC_RXQEN_SHIFT(x)           ((x) * 2)
+#define XGMAC_RXQ_CTRL1                        0x000000a4
+#define XGMAC_RQ                       GENMASK(7, 4)
+#define XGMAC_RQ_SHIFT                 4
 #define XGMAC_RXQ_CTRL2                        0x000000a8
 #define XGMAC_RXQ_CTRL3                        0x000000ac
 #define XGMAC_PSRQ(x)                  GENMASK((x) * 8 + 7, (x) * 8)
 #define XGMAC_HWFEAT_TXQCNT            GENMASK(9, 6)
 #define XGMAC_HWFEAT_RXQCNT            GENMASK(3, 0)
 #define XGMAC_HW_FEATURE3              0x00000128
+#define XGMAC_HWFEAT_FPESEL            BIT(26)
+#define XGMAC_HWFEAT_ESTWID            GENMASK(24, 23)
+#define XGMAC_HWFEAT_ESTDEP            GENMASK(22, 20)
+#define XGMAC_HWFEAT_ESTSEL            BIT(19)
 #define XGMAC_HWFEAT_ASP               GENMASK(15, 14)
 #define XGMAC_HWFEAT_DVLAN             BIT(13)
 #define XGMAC_HWFEAT_FRPES             GENMASK(12, 11)
 #define XGMAC_MDIO_ADDR                        0x00000200
 #define XGMAC_MDIO_DATA                        0x00000204
 #define XGMAC_MDIO_C22P                        0x00000220
+#define XGMAC_FPE_CTRL_STS             0x00000280
+#define XGMAC_EFPE                     BIT(0)
 #define XGMAC_ADDRx_HIGH(x)            (0x00000300 + (x) * 0x8)
 #define XGMAC_ADDR_MAX                 32
 #define XGMAC_AE                       BIT(31)
 #define XGMAC_TC_PRTY_MAP1             0x00001044
 #define XGMAC_PSTC(x)                  GENMASK((x) * 8 + 7, (x) * 8)
 #define XGMAC_PSTC_SHIFT(x)            ((x) * 8)
+#define XGMAC_MTL_EST_CONTROL          0x00001050
+#define XGMAC_PTOV                     GENMASK(31, 23)
+#define XGMAC_PTOV_SHIFT               23
+#define XGMAC_SSWL                     BIT(1)
+#define XGMAC_EEST                     BIT(0)
+#define XGMAC_MTL_EST_GCL_CONTROL      0x00001080
+#define XGMAC_BTR_LOW                  0x0
+#define XGMAC_BTR_HIGH                 0x1
+#define XGMAC_CTR_LOW                  0x2
+#define XGMAC_CTR_HIGH                 0x3
+#define XGMAC_TER                      0x4
+#define XGMAC_LLR                      0x5
+#define XGMAC_ADDR_SHIFT               8
+#define XGMAC_GCRR                     BIT(2)
+#define XGMAC_SRWO                     BIT(0)
+#define XGMAC_MTL_EST_GCL_DATA         0x00001084
 #define XGMAC_MTL_RXP_CONTROL_STATUS   0x000010a0
 #define XGMAC_RXPI                     BIT(31)
 #define XGMAC_NPE                      GENMASK(23, 16)
index 082f5ee9e52566ae06fca10463fe69cd7af37257..307105e8dea035a078ed8432d29244f5aa3e807c 100644 (file)
@@ -1359,6 +1359,80 @@ static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en,
        writel(value, ioaddr + XGMAC_RX_CONFIG);
 }
 
+static int dwxgmac3_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
+{
+       u32 ctrl;
+
+       writel(val, ioaddr + XGMAC_MTL_EST_GCL_DATA);
+
+       ctrl = (reg << XGMAC_ADDR_SHIFT);
+       ctrl |= gcl ? 0 : XGMAC_GCRR;
+
+       writel(ctrl, ioaddr + XGMAC_MTL_EST_GCL_CONTROL);
+
+       ctrl |= XGMAC_SRWO;
+       writel(ctrl, ioaddr + XGMAC_MTL_EST_GCL_CONTROL);
+
+       return readl_poll_timeout_atomic(ioaddr + XGMAC_MTL_EST_GCL_CONTROL,
+                                        ctrl, !(ctrl & XGMAC_SRWO), 100, 5000);
+}
+
+static int dwxgmac3_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
+                                 unsigned int ptp_rate)
+{
+       int i, ret = 0x0;
+       u32 ctrl;
+
+       ret |= dwxgmac3_est_write(ioaddr, XGMAC_BTR_LOW, cfg->btr[0], false);
+       ret |= dwxgmac3_est_write(ioaddr, XGMAC_BTR_HIGH, cfg->btr[1], false);
+       ret |= dwxgmac3_est_write(ioaddr, XGMAC_TER, cfg->ter, false);
+       ret |= dwxgmac3_est_write(ioaddr, XGMAC_LLR, cfg->gcl_size, false);
+       ret |= dwxgmac3_est_write(ioaddr, XGMAC_CTR_LOW, cfg->ctr[0], false);
+       ret |= dwxgmac3_est_write(ioaddr, XGMAC_CTR_HIGH, cfg->ctr[1], false);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < cfg->gcl_size; i++) {
+               ret = dwxgmac3_est_write(ioaddr, i, cfg->gcl[i], true);
+               if (ret)
+                       return ret;
+       }
+
+       ctrl = readl(ioaddr + XGMAC_MTL_EST_CONTROL);
+       ctrl &= ~XGMAC_PTOV;
+       ctrl |= ((1000000000 / ptp_rate) * 9) << XGMAC_PTOV_SHIFT;
+       if (cfg->enable)
+               ctrl |= XGMAC_EEST | XGMAC_SSWL;
+       else
+               ctrl &= ~XGMAC_EEST;
+
+       writel(ctrl, ioaddr + XGMAC_MTL_EST_CONTROL);
+       return 0;
+}
+
+static void dwxgmac3_fpe_configure(void __iomem *ioaddr, u32 num_txq,
+                                  u32 num_rxq, bool enable)
+{
+       u32 value;
+
+       if (!enable) {
+               value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
+
+               value &= ~XGMAC_EFPE;
+
+               writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
+       }
+
+       value = readl(ioaddr + XGMAC_RXQ_CTRL1);
+       value &= ~XGMAC_RQ;
+       value |= (num_rxq - 1) << XGMAC_RQ_SHIFT;
+       writel(value, ioaddr + XGMAC_RXQ_CTRL1);
+
+       value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
+       value |= XGMAC_EFPE;
+       writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
+}
+
 const struct stmmac_ops dwxgmac210_ops = {
        .core_init = dwxgmac2_core_init,
        .set_mac = dwxgmac2_set_mac,
@@ -1402,6 +1476,8 @@ const struct stmmac_ops dwxgmac210_ops = {
        .config_l3_filter = dwxgmac2_config_l3_filter,
        .config_l4_filter = dwxgmac2_config_l4_filter,
        .set_arp_offload = dwxgmac2_set_arp_offload,
+       .est_configure = dwxgmac3_est_configure,
+       .fpe_configure = dwxgmac3_fpe_configure,
 };
 
 int dwxgmac2_setup(struct stmmac_priv *priv)
index ae066f4e99a81b9654e5d91a74f5dd46f2916914..c1ca73ebb0e7b312f67e28f0e13d23d39cf0c49b 100644 (file)
@@ -429,6 +429,10 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
 
        /* MAC HW feature 3 */
        hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3);
+       dma_cap->fpesel = (hw_cap & XGMAC_HWFEAT_FPESEL) >> 26;
+       dma_cap->estwid = (hw_cap & XGMAC_HWFEAT_ESTWID) >> 23;
+       dma_cap->estdep = (hw_cap & XGMAC_HWFEAT_ESTDEP) >> 20;
+       dma_cap->estsel = (hw_cap & XGMAC_HWFEAT_ESTSEL) >> 19;
        dma_cap->asp = (hw_cap & XGMAC_HWFEAT_ASP) >> 14;
        dma_cap->dvlan = (hw_cap & XGMAC_HWFEAT_DVLAN) >> 13;
        dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11;
index 098fbe7a58623caa3502c5b022fd178ce699f40d..905a6f0edacab7039fbfd9501b58bce0a19b4717 100644 (file)
@@ -276,6 +276,7 @@ struct stmmac_safety_stats;
 struct stmmac_tc_entry;
 struct stmmac_pps_cfg;
 struct stmmac_rss;
+struct stmmac_est;
 
 /* Helpers to program the MAC core */
 struct stmmac_ops {
@@ -373,6 +374,10 @@ struct stmmac_ops {
                                bool en, bool udp, bool sa, bool inv,
                                u32 match);
        void (*set_arp_offload)(struct mac_device_info *hw, bool en, u32 addr);
+       int (*est_configure)(void __iomem *ioaddr, struct stmmac_est *cfg,
+                            unsigned int ptp_rate);
+       void (*fpe_configure)(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
+                             bool enable);
 };
 
 #define stmmac_core_init(__priv, __args...) \
@@ -459,6 +464,10 @@ struct stmmac_ops {
        stmmac_do_callback(__priv, mac, config_l4_filter, __args)
 #define stmmac_set_arp_offload(__priv, __args...) \
        stmmac_do_void_callback(__priv, mac, set_arp_offload, __args)
+#define stmmac_est_configure(__priv, __args...) \
+       stmmac_do_callback(__priv, mac, est_configure, __args)
+#define stmmac_fpe_configure(__priv, __args...) \
+       stmmac_do_void_callback(__priv, mac, fpe_configure, __args)
 
 /* PTP and HW Timer helpers */
 struct stmmac_hwtimestamp {
@@ -516,6 +525,7 @@ struct stmmac_priv;
 struct tc_cls_u32_offload;
 struct tc_cbs_qopt_offload;
 struct flow_cls_offload;
+struct tc_taprio_qopt_offload;
 
 struct stmmac_tc_ops {
        int (*init)(struct stmmac_priv *priv);
@@ -525,6 +535,8 @@ struct stmmac_tc_ops {
                         struct tc_cbs_qopt_offload *qopt);
        int (*setup_cls)(struct stmmac_priv *priv,
                         struct flow_cls_offload *cls);
+       int (*setup_taprio)(struct stmmac_priv *priv,
+                           struct tc_taprio_qopt_offload *qopt);
 };
 
 #define stmmac_tc_init(__priv, __args...) \
@@ -535,6 +547,8 @@ struct stmmac_tc_ops {
        stmmac_do_callback(__priv, tc, setup_cbs, __args)
 #define stmmac_tc_setup_cls(__priv, __args...) \
        stmmac_do_callback(__priv, tc, setup_cls, __args)
+#define stmmac_tc_setup_taprio(__priv, __args...) \
+       stmmac_do_callback(__priv, tc, setup_taprio, __args)
 
 struct stmmac_counters;
 
index 252cf48c581665ff99276672d840e01e42ff5e77..a57b0fa815abad896d6a485c4c17a7efe320291c 100644 (file)
 #define MMC_RX_ICMP_GD_OCTETS          0x180
 #define MMC_RX_ICMP_ERR_OCTETS         0x184
 
+#define MMC_TX_FPE_FRAG                        0x1a8
+#define MMC_TX_HOLD_REQ                        0x1ac
+#define MMC_RX_PKT_ASSEMBLY_ERR                0x1c8
+#define MMC_RX_PKT_SMD_ERR             0x1cc
+#define MMC_RX_PKT_ASSEMBLY_OK         0x1d0
+#define MMC_RX_FPE_FRAG                        0x1d4
+
 /* XGMAC MMC Registers */
 #define MMC_XGMAC_TX_OCTET_GB          0x14
 #define MMC_XGMAC_TX_PKT_GB            0x1c
@@ -315,6 +322,15 @@ static void dwmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc)
        mmc->mmc_rx_tcp_err_octets += readl(mmcaddr + MMC_RX_TCP_ERR_OCTETS);
        mmc->mmc_rx_icmp_gd_octets += readl(mmcaddr + MMC_RX_ICMP_GD_OCTETS);
        mmc->mmc_rx_icmp_err_octets += readl(mmcaddr + MMC_RX_ICMP_ERR_OCTETS);
+
+       mmc->mmc_tx_fpe_fragment_cntr += readl(mmcaddr + MMC_TX_FPE_FRAG);
+       mmc->mmc_tx_hold_req_cntr += readl(mmcaddr + MMC_TX_HOLD_REQ);
+       mmc->mmc_rx_packet_assembly_err_cntr +=
+               readl(mmcaddr + MMC_RX_PKT_ASSEMBLY_ERR);
+       mmc->mmc_rx_packet_smd_err_cntr += readl(mmcaddr + MMC_RX_PKT_SMD_ERR);
+       mmc->mmc_rx_packet_assembly_ok_cntr +=
+               readl(mmcaddr + MMC_RX_PKT_ASSEMBLY_OK);
+       mmc->mmc_rx_fpe_fragment_cntr += readl(mmcaddr + MMC_RX_FPE_FRAG);
 }
 
 const struct stmmac_mmc_ops dwmac_mmc_ops = {
index ecb89c609fb2029c67a64d448acf51e8fadd8426..18a959589cbcfa04c2ac3e4dff5e83452dc0d135 100644 (file)
@@ -4076,6 +4076,8 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
                                                  priv, priv, true);
        case TC_SETUP_QDISC_CBS:
                return stmmac_tc_setup_cbs(priv, priv, type_data);
+       case TC_SETUP_QDISC_TAPRIO:
+               return stmmac_tc_setup_taprio(priv, priv, type_data);
        default:
                return -EOPNOTSUPP;
        }
index 7d972e0fd2b04d8759a016b023e07b30381e3dd3..8ff8f9b9bb2251d8f999f2a9592e4269ebac87b1 100644 (file)
@@ -591,9 +591,144 @@ static int tc_setup_cls(struct stmmac_priv *priv,
        return ret;
 }
 
+static int tc_setup_taprio(struct stmmac_priv *priv,
+                          struct tc_taprio_qopt_offload *qopt)
+{
+       u32 size, wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep;
+       struct plat_stmmacenet_data *plat = priv->plat;
+       struct timespec64 time;
+       bool fpe = false;
+       int i, ret = 0;
+
+       if (!priv->dma_cap.estsel)
+               return -EOPNOTSUPP;
+
+       switch (wid) {
+       case 0x1:
+               wid = 16;
+               break;
+       case 0x2:
+               wid = 20;
+               break;
+       case 0x3:
+               wid = 24;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       switch (dep) {
+       case 0x1:
+               dep = 64;
+               break;
+       case 0x2:
+               dep = 128;
+               break;
+       case 0x3:
+               dep = 256;
+               break;
+       case 0x4:
+               dep = 512;
+               break;
+       case 0x5:
+               dep = 1024;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       if (!qopt->enable)
+               goto disable;
+       if (qopt->num_entries >= dep)
+               return -EINVAL;
+       if (!qopt->base_time)
+               return -ERANGE;
+       if (!qopt->cycle_time)
+               return -ERANGE;
+
+       if (!plat->est) {
+               plat->est = devm_kzalloc(priv->device, sizeof(*plat->est),
+                                        GFP_KERNEL);
+               if (!plat->est)
+                       return -ENOMEM;
+       } else {
+               memset(plat->est, 0, sizeof(*plat->est));
+       }
+
+       size = qopt->num_entries;
+
+       priv->plat->est->gcl_size = size;
+       priv->plat->est->enable = qopt->enable;
+
+       for (i = 0; i < size; i++) {
+               s64 delta_ns = qopt->entries[i].interval;
+               u32 gates = qopt->entries[i].gate_mask;
+
+               if (delta_ns > GENMASK(wid, 0))
+                       return -ERANGE;
+               if (gates > GENMASK(31 - wid, 0))
+                       return -ERANGE;
+
+               switch (qopt->entries[i].command) {
+               case TC_TAPRIO_CMD_SET_GATES:
+                       if (fpe)
+                               return -EINVAL;
+                       break;
+               case TC_TAPRIO_CMD_SET_AND_HOLD:
+                       gates |= BIT(0);
+                       fpe = true;
+                       break;
+               case TC_TAPRIO_CMD_SET_AND_RELEASE:
+                       gates &= ~BIT(0);
+                       fpe = true;
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
+
+               priv->plat->est->gcl[i] = delta_ns | (gates << wid);
+       }
+
+       /* Adjust for real system time */
+       time = ktime_to_timespec64(qopt->base_time);
+       priv->plat->est->btr[0] = (u32)time.tv_nsec;
+       priv->plat->est->btr[1] = (u32)time.tv_sec;
+
+       priv->plat->est->ctr[0] = (u32)(qopt->cycle_time % NSEC_PER_SEC);
+       priv->plat->est->ctr[1] = (u32)(qopt->cycle_time / NSEC_PER_SEC);
+
+       if (fpe && !priv->dma_cap.fpesel)
+               return -EOPNOTSUPP;
+
+       ret = stmmac_fpe_configure(priv, priv->ioaddr,
+                                  priv->plat->tx_queues_to_use,
+                                  priv->plat->rx_queues_to_use, fpe);
+       if (ret && fpe) {
+               netdev_err(priv->dev, "failed to enable Frame Preemption\n");
+               return ret;
+       }
+
+       ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
+                                  priv->plat->clk_ptp_rate);
+       if (ret) {
+               netdev_err(priv->dev, "failed to configure EST\n");
+               goto disable;
+       }
+
+       netdev_info(priv->dev, "configured EST\n");
+       return 0;
+
+disable:
+       priv->plat->est->enable = false;
+       stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
+                            priv->plat->clk_ptp_rate);
+       return ret;
+}
+
 const struct stmmac_tc_ops dwmac510_tc_ops = {
        .init = tc_init,
        .setup_cls_u32 = tc_setup_cls_u32,
        .setup_cbs = tc_setup_cbs,
        .setup_cls = tc_setup_cls,
+       .setup_taprio = tc_setup_taprio,
 };
index d4bcd9387136c6c7d804a244a0233398847e7a7f..0531afa9b21eaba94ee37315b0f35d456b8b9b59 100644 (file)
@@ -109,6 +109,18 @@ struct stmmac_axi {
        bool axi_rb;
 };
 
+#define EST_GCL                1024
+struct stmmac_est {
+       int enable;
+       u32 btr_offset[2];
+       u32 btr[2];
+       u32 ctr[2];
+       u32 ter;
+       u32 gcl_unaligned[EST_GCL];
+       u32 gcl[EST_GCL];
+       u32 gcl_size;
+};
+
 struct stmmac_rxq_cfg {
        u8 mode_to_use;
        u32 chan;
@@ -139,6 +151,7 @@ struct plat_stmmacenet_data {
        struct device_node *phylink_node;
        struct device_node *mdio_node;
        struct stmmac_dma_cfg *dma_cfg;
+       struct stmmac_est *est;
        int clk_csr;
        int has_gmac;
        int enh_desc;