Merge branch 'net-stmmac-est-implementation'
Rohan G Thomas says: ==================== net: stmmac: EST implementation This patchset extends EST interrupt handling support to DWXGMAC IP followed by refactoring of EST implementation. Added a separate module for EST and moved all EST related functions to the new module. Also added support for EST cycle-time-extension. ==================== Link: https://lore.kernel.org/r/20231201055252.1302-1-rohan.g.thomas@intel.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
36638d372a
@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
|
||||
mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o \
|
||||
dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
|
||||
stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
|
||||
stmmac_xdp.o \
|
||||
stmmac_xdp.o stmmac_est.o \
|
||||
$(stmmac-y)
|
||||
|
||||
stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
|
||||
|
@ -563,6 +563,7 @@ struct mac_device_info {
|
||||
const struct stmmac_hwtimestamp *ptp;
|
||||
const struct stmmac_tc_ops *tc;
|
||||
const struct stmmac_mmc_ops *mmc;
|
||||
const struct stmmac_est_ops *est;
|
||||
struct dw_xpcs *xpcs;
|
||||
struct phylink_pcs *lynx_pcs; /* Lynx external PCS */
|
||||
struct mii_regs mii; /* MII register Addresses */
|
||||
|
@ -1247,8 +1247,6 @@ 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,
|
||||
.est_irq_status = dwmac5_est_irq_status,
|
||||
.fpe_configure = dwmac5_fpe_configure,
|
||||
.fpe_send_mpacket = dwmac5_fpe_send_mpacket,
|
||||
.fpe_irq_status = dwmac5_fpe_irq_status,
|
||||
@ -1302,8 +1300,6 @@ 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,
|
||||
.est_irq_status = dwmac5_est_irq_status,
|
||||
.fpe_configure = dwmac5_fpe_configure,
|
||||
.fpe_send_mpacket = dwmac5_fpe_send_mpacket,
|
||||
.fpe_irq_status = dwmac5_fpe_irq_status,
|
||||
|
@ -573,143 +573,6 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
|
||||
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)
|
||||
{
|
||||
int i, ret = 0x0;
|
||||
u32 ctrl;
|
||||
|
||||
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);
|
||||
ret |= dwmac5_est_write(ioaddr, CTR_LOW, cfg->ctr[0], false);
|
||||
ret |= dwmac5_est_write(ioaddr, CTR_HIGH, cfg->ctr[1], false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < cfg->gcl_size; i++) {
|
||||
ret = dwmac5_est_write(ioaddr, i, cfg->gcl[i], true);
|
||||
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);
|
||||
|
||||
/* Configure EST interrupt */
|
||||
if (cfg->enable)
|
||||
ctrl = (IECGCE | IEHS | IEHF | IEBE | IECC);
|
||||
else
|
||||
ctrl = 0;
|
||||
|
||||
writel(ctrl, ioaddr + MTL_EST_INT_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
|
||||
struct stmmac_extra_stats *x, u32 txqcnt)
|
||||
{
|
||||
u32 status, value, feqn, hbfq, hbfs, btrl;
|
||||
u32 txqcnt_mask = (1 << txqcnt) - 1;
|
||||
|
||||
status = readl(ioaddr + MTL_EST_STATUS);
|
||||
|
||||
value = (CGCE | HLBS | HLBF | BTRE | SWLC);
|
||||
|
||||
/* Return if there is no error */
|
||||
if (!(status & value))
|
||||
return;
|
||||
|
||||
if (status & CGCE) {
|
||||
/* Clear Interrupt */
|
||||
writel(CGCE, ioaddr + MTL_EST_STATUS);
|
||||
|
||||
x->mtl_est_cgce++;
|
||||
}
|
||||
|
||||
if (status & HLBS) {
|
||||
value = readl(ioaddr + MTL_EST_SCH_ERR);
|
||||
value &= txqcnt_mask;
|
||||
|
||||
x->mtl_est_hlbs++;
|
||||
|
||||
/* Clear Interrupt */
|
||||
writel(value, ioaddr + MTL_EST_SCH_ERR);
|
||||
|
||||
/* Collecting info to shows all the queues that has HLBS
|
||||
* issue. The only way to clear this is to clear the
|
||||
* statistic
|
||||
*/
|
||||
if (net_ratelimit())
|
||||
netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value);
|
||||
}
|
||||
|
||||
if (status & HLBF) {
|
||||
value = readl(ioaddr + MTL_EST_FRM_SZ_ERR);
|
||||
feqn = value & txqcnt_mask;
|
||||
|
||||
value = readl(ioaddr + MTL_EST_FRM_SZ_CAP);
|
||||
hbfq = (value & SZ_CAP_HBFQ_MASK(txqcnt)) >> SZ_CAP_HBFQ_SHIFT;
|
||||
hbfs = value & SZ_CAP_HBFS_MASK;
|
||||
|
||||
x->mtl_est_hlbf++;
|
||||
|
||||
/* Clear Interrupt */
|
||||
writel(feqn, ioaddr + MTL_EST_FRM_SZ_ERR);
|
||||
|
||||
if (net_ratelimit())
|
||||
netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n",
|
||||
hbfq, hbfs);
|
||||
}
|
||||
|
||||
if (status & BTRE) {
|
||||
if ((status & BTRL) == BTRL_MAX)
|
||||
x->mtl_est_btrlm++;
|
||||
else
|
||||
x->mtl_est_btre++;
|
||||
|
||||
btrl = (status & BTRL) >> BTRL_SHIFT;
|
||||
|
||||
if (net_ratelimit())
|
||||
netdev_info(dev, "EST: BTR Error Loop Count %u\n",
|
||||
btrl);
|
||||
|
||||
writel(BTRE, ioaddr + MTL_EST_STATUS);
|
||||
}
|
||||
|
||||
if (status & SWLC) {
|
||||
writel(SWLC, ioaddr + MTL_EST_STATUS);
|
||||
netdev_info(dev, "EST: SWOL has been switched\n");
|
||||
}
|
||||
}
|
||||
|
||||
void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
|
||||
bool enable)
|
||||
{
|
||||
|
@ -39,53 +39,6 @@
|
||||
#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_STATUS 0x00000c58
|
||||
#define BTRL GENMASK(11, 8)
|
||||
#define BTRL_SHIFT 8
|
||||
#define BTRL_MAX (0xF << BTRL_SHIFT)
|
||||
#define SWOL BIT(7)
|
||||
#define SWOL_SHIFT 7
|
||||
#define CGCE BIT(4)
|
||||
#define HLBS BIT(3)
|
||||
#define HLBF BIT(2)
|
||||
#define BTRE BIT(1)
|
||||
#define SWLC BIT(0)
|
||||
|
||||
#define MTL_EST_SCH_ERR 0x00000c60
|
||||
#define MTL_EST_FRM_SZ_ERR 0x00000c64
|
||||
#define MTL_EST_FRM_SZ_CAP 0x00000c68
|
||||
#define SZ_CAP_HBFS_MASK GENMASK(14, 0)
|
||||
#define SZ_CAP_HBFQ_SHIFT 16
|
||||
#define SZ_CAP_HBFQ_MASK(_val) ({ typeof(_val) (val) = (_val); \
|
||||
((val) > 4 ? GENMASK(18, 16) : \
|
||||
(val) > 2 ? GENMASK(17, 16) : \
|
||||
BIT(16)); })
|
||||
|
||||
#define MTL_EST_INT_EN 0x00000c70
|
||||
#define IECGCE CGCE
|
||||
#define IEHS HLBS
|
||||
#define IEHF HLBF
|
||||
#define IEBE BTRE
|
||||
#define IECC SWLC
|
||||
|
||||
#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)
|
||||
@ -149,10 +102,6 @@ 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_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
|
||||
struct stmmac_extra_stats *x, u32 txqcnt);
|
||||
void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
|
||||
bool enable);
|
||||
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
|
||||
|
@ -284,22 +284,6 @@
|
||||
#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)
|
||||
|
@ -1433,57 +1433,6 @@ 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)
|
||||
{
|
||||
@ -1552,7 +1501,6 @@ 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,
|
||||
};
|
||||
|
||||
@ -1614,7 +1562,6 @@ const struct stmmac_ops dwxlgmac2_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,
|
||||
};
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "common.h"
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_ptp.h"
|
||||
#include "stmmac_est.h"
|
||||
|
||||
static u32 stmmac_get_id(struct stmmac_priv *priv, u32 id_reg)
|
||||
{
|
||||
@ -114,6 +115,7 @@ static const struct stmmac_hwif_entry {
|
||||
const void *mode;
|
||||
const void *tc;
|
||||
const void *mmc;
|
||||
const void *est;
|
||||
int (*setup)(struct stmmac_priv *priv);
|
||||
int (*quirks)(struct stmmac_priv *priv);
|
||||
} stmmac_hw[] = {
|
||||
@ -162,6 +164,7 @@ static const struct stmmac_hwif_entry {
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac4_dma_ops,
|
||||
@ -170,6 +173,7 @@ static const struct stmmac_hwif_entry {
|
||||
.mode = NULL,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
.quirks = stmmac_dwmac4_quirks,
|
||||
}, {
|
||||
@ -180,6 +184,7 @@ static const struct stmmac_hwif_entry {
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac4_dma_ops,
|
||||
@ -188,6 +193,7 @@ static const struct stmmac_hwif_entry {
|
||||
.mode = &dwmac4_ring_mode_ops,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
.quirks = NULL,
|
||||
}, {
|
||||
@ -198,6 +204,7 @@ static const struct stmmac_hwif_entry {
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac410_dma_ops,
|
||||
@ -206,6 +213,7 @@ static const struct stmmac_hwif_entry {
|
||||
.mode = &dwmac4_ring_mode_ops,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
.quirks = NULL,
|
||||
}, {
|
||||
@ -216,6 +224,7 @@ static const struct stmmac_hwif_entry {
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_XGMAC_OFFSET,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac410_dma_ops,
|
||||
@ -224,6 +233,7 @@ static const struct stmmac_hwif_entry {
|
||||
.mode = &dwmac4_ring_mode_ops,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
.quirks = NULL,
|
||||
}, {
|
||||
@ -235,6 +245,7 @@ static const struct stmmac_hwif_entry {
|
||||
.regs = {
|
||||
.ptp_off = PTP_XGMAC_OFFSET,
|
||||
.mmc_off = MMC_XGMAC_OFFSET,
|
||||
.est_off = EST_XGMAC_OFFSET,
|
||||
},
|
||||
.desc = &dwxgmac210_desc_ops,
|
||||
.dma = &dwxgmac210_dma_ops,
|
||||
@ -243,6 +254,7 @@ static const struct stmmac_hwif_entry {
|
||||
.mode = NULL,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.mmc = &dwxgmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwxgmac2_setup,
|
||||
.quirks = NULL,
|
||||
}, {
|
||||
@ -254,6 +266,7 @@ static const struct stmmac_hwif_entry {
|
||||
.regs = {
|
||||
.ptp_off = PTP_XGMAC_OFFSET,
|
||||
.mmc_off = MMC_XGMAC_OFFSET,
|
||||
.est_off = EST_XGMAC_OFFSET,
|
||||
},
|
||||
.desc = &dwxgmac210_desc_ops,
|
||||
.dma = &dwxgmac210_dma_ops,
|
||||
@ -262,6 +275,7 @@ static const struct stmmac_hwif_entry {
|
||||
.mode = NULL,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.mmc = &dwxgmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwxlgmac2_setup,
|
||||
.quirks = stmmac_dwxlgmac_quirks,
|
||||
},
|
||||
@ -296,6 +310,10 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
|
||||
(needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET);
|
||||
priv->mmcaddr = priv->ioaddr +
|
||||
(needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET);
|
||||
if (needs_gmac4)
|
||||
priv->estaddr = priv->ioaddr + EST_GMAC4_OFFSET;
|
||||
else if (needs_xgmac)
|
||||
priv->estaddr = priv->ioaddr + EST_XGMAC_OFFSET;
|
||||
|
||||
/* Check for HW specific setup first */
|
||||
if (priv->plat->setup) {
|
||||
@ -332,10 +350,13 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
|
||||
mac->mode = mac->mode ? : entry->mode;
|
||||
mac->tc = mac->tc ? : entry->tc;
|
||||
mac->mmc = mac->mmc ? : entry->mmc;
|
||||
mac->est = mac->est ? : entry->est;
|
||||
|
||||
priv->hw = mac;
|
||||
priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
|
||||
priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
|
||||
if (entry->est)
|
||||
priv->estaddr = priv->ioaddr + entry->regs.est_off;
|
||||
|
||||
/* Entry found */
|
||||
if (needs_setup) {
|
||||
|
@ -419,10 +419,6 @@ 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 (*est_irq_status)(void __iomem *ioaddr, struct net_device *dev,
|
||||
struct stmmac_extra_stats *x, u32 txqcnt);
|
||||
void (*fpe_configure)(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
|
||||
bool enable);
|
||||
void (*fpe_send_mpacket)(void __iomem *ioaddr,
|
||||
@ -528,10 +524,6 @@ 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_est_irq_status(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, est_irq_status, __args)
|
||||
#define stmmac_fpe_configure(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_configure, __args)
|
||||
#define stmmac_fpe_send_mpacket(__priv, __args...) \
|
||||
@ -657,9 +649,22 @@ struct stmmac_mmc_ops {
|
||||
#define stmmac_mmc_read(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mmc, read, __args)
|
||||
|
||||
struct stmmac_est_ops {
|
||||
int (*configure)(struct stmmac_priv *priv, struct stmmac_est *cfg,
|
||||
unsigned int ptp_rate);
|
||||
void (*irq_status)(struct stmmac_priv *priv, struct net_device *dev,
|
||||
struct stmmac_extra_stats *x, u32 txqcnt);
|
||||
};
|
||||
|
||||
#define stmmac_est_configure(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, est, configure, __args)
|
||||
#define stmmac_est_irq_status(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, est, irq_status, __args)
|
||||
|
||||
struct stmmac_regs_off {
|
||||
u32 ptp_off;
|
||||
u32 mmc_off;
|
||||
u32 est_off;
|
||||
};
|
||||
|
||||
extern const struct stmmac_ops dwmac100_ops;
|
||||
@ -678,6 +683,7 @@ extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
|
||||
extern const struct stmmac_desc_ops dwxgmac210_desc_ops;
|
||||
extern const struct stmmac_mmc_ops dwmac_mmc_ops;
|
||||
extern const struct stmmac_mmc_ops dwxgmac_mmc_ops;
|
||||
extern const struct stmmac_est_ops dwmac510_est_ops;
|
||||
|
||||
#define GMAC_VERSION 0x00000020 /* GMAC CORE Version */
|
||||
#define GMAC4_VERSION 0x00000110 /* GMAC4+ CORE Version */
|
||||
|
@ -295,6 +295,7 @@ struct stmmac_priv {
|
||||
|
||||
void __iomem *mmcaddr;
|
||||
void __iomem *ptpaddr;
|
||||
void __iomem *estaddr;
|
||||
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
|
||||
int sfty_ce_irq;
|
||||
int sfty_ue_irq;
|
||||
|
165
drivers/net/ethernet/stmicro/stmmac/stmmac_est.c
Normal file
165
drivers/net/ethernet/stmicro/stmmac/stmmac_est.c
Normal file
@ -0,0 +1,165 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2023, Intel Corporation
|
||||
* stmmac EST(802.3 Qbv) handling
|
||||
*/
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/types.h>
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_est.h"
|
||||
|
||||
static int est_write(void __iomem *est_addr, u32 reg, u32 val, bool gcl)
|
||||
{
|
||||
u32 ctrl;
|
||||
|
||||
writel(val, est_addr + EST_GCL_DATA);
|
||||
|
||||
ctrl = (reg << EST_ADDR_SHIFT);
|
||||
ctrl |= gcl ? 0 : EST_GCRR;
|
||||
writel(ctrl, est_addr + EST_GCL_CONTROL);
|
||||
|
||||
ctrl |= EST_SRWO;
|
||||
writel(ctrl, est_addr + EST_GCL_CONTROL);
|
||||
|
||||
return readl_poll_timeout(est_addr + EST_GCL_CONTROL, ctrl,
|
||||
!(ctrl & EST_SRWO), 100, 5000);
|
||||
}
|
||||
|
||||
static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
|
||||
unsigned int ptp_rate)
|
||||
{
|
||||
void __iomem *est_addr = priv->estaddr;
|
||||
int i, ret = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ret |= est_write(est_addr, EST_BTR_LOW, cfg->btr[0], false);
|
||||
ret |= est_write(est_addr, EST_BTR_HIGH, cfg->btr[1], false);
|
||||
ret |= est_write(est_addr, EST_TER, cfg->ter, false);
|
||||
ret |= est_write(est_addr, EST_LLR, cfg->gcl_size, false);
|
||||
ret |= est_write(est_addr, EST_CTR_LOW, cfg->ctr[0], false);
|
||||
ret |= est_write(est_addr, EST_CTR_HIGH, cfg->ctr[1], false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < cfg->gcl_size; i++) {
|
||||
ret = est_write(est_addr, i, cfg->gcl[i], true);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctrl = readl(est_addr + EST_CONTROL);
|
||||
if (priv->plat->has_xgmac) {
|
||||
ctrl &= ~EST_XGMAC_PTOV;
|
||||
ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_XGMAC_PTOV_MUL) <<
|
||||
EST_XGMAC_PTOV_SHIFT;
|
||||
} else {
|
||||
ctrl &= ~EST_GMAC5_PTOV;
|
||||
ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_GMAC5_PTOV_MUL) <<
|
||||
EST_GMAC5_PTOV_SHIFT;
|
||||
}
|
||||
if (cfg->enable)
|
||||
ctrl |= EST_EEST | EST_SSWL;
|
||||
else
|
||||
ctrl &= ~EST_EEST;
|
||||
|
||||
writel(ctrl, est_addr + EST_CONTROL);
|
||||
|
||||
/* Configure EST interrupt */
|
||||
if (cfg->enable)
|
||||
ctrl = EST_IECGCE | EST_IEHS | EST_IEHF | EST_IEBE | EST_IECC;
|
||||
else
|
||||
ctrl = 0;
|
||||
|
||||
writel(ctrl, est_addr + EST_INT_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev,
|
||||
struct stmmac_extra_stats *x, u32 txqcnt)
|
||||
{
|
||||
u32 status, value, feqn, hbfq, hbfs, btrl, btrl_max;
|
||||
void __iomem *est_addr = priv->estaddr;
|
||||
u32 txqcnt_mask = BIT(txqcnt) - 1;
|
||||
|
||||
status = readl(est_addr + EST_STATUS);
|
||||
|
||||
value = EST_CGCE | EST_HLBS | EST_HLBF | EST_BTRE | EST_SWLC;
|
||||
|
||||
/* Return if there is no error */
|
||||
if (!(status & value))
|
||||
return;
|
||||
|
||||
if (status & EST_CGCE) {
|
||||
/* Clear Interrupt */
|
||||
writel(EST_CGCE, est_addr + EST_STATUS);
|
||||
|
||||
x->mtl_est_cgce++;
|
||||
}
|
||||
|
||||
if (status & EST_HLBS) {
|
||||
value = readl(est_addr + EST_SCH_ERR);
|
||||
value &= txqcnt_mask;
|
||||
|
||||
x->mtl_est_hlbs++;
|
||||
|
||||
/* Clear Interrupt */
|
||||
writel(value, est_addr + EST_SCH_ERR);
|
||||
|
||||
/* Collecting info to shows all the queues that has HLBS
|
||||
* issue. The only way to clear this is to clear the
|
||||
* statistic
|
||||
*/
|
||||
if (net_ratelimit())
|
||||
netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value);
|
||||
}
|
||||
|
||||
if (status & EST_HLBF) {
|
||||
value = readl(est_addr + EST_FRM_SZ_ERR);
|
||||
feqn = value & txqcnt_mask;
|
||||
|
||||
value = readl(est_addr + EST_FRM_SZ_CAP);
|
||||
hbfq = (value & EST_SZ_CAP_HBFQ_MASK(txqcnt)) >>
|
||||
EST_SZ_CAP_HBFQ_SHIFT;
|
||||
hbfs = value & EST_SZ_CAP_HBFS_MASK;
|
||||
|
||||
x->mtl_est_hlbf++;
|
||||
|
||||
/* Clear Interrupt */
|
||||
writel(feqn, est_addr + EST_FRM_SZ_ERR);
|
||||
|
||||
if (net_ratelimit())
|
||||
netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n",
|
||||
hbfq, hbfs);
|
||||
}
|
||||
|
||||
if (status & EST_BTRE) {
|
||||
if (priv->plat->has_xgmac) {
|
||||
btrl = FIELD_GET(EST_XGMAC_BTRL, status);
|
||||
btrl_max = FIELD_MAX(EST_XGMAC_BTRL);
|
||||
} else {
|
||||
btrl = FIELD_GET(EST_GMAC5_BTRL, status);
|
||||
btrl_max = FIELD_MAX(EST_GMAC5_BTRL);
|
||||
}
|
||||
if (btrl == btrl_max)
|
||||
x->mtl_est_btrlm++;
|
||||
else
|
||||
x->mtl_est_btre++;
|
||||
|
||||
if (net_ratelimit())
|
||||
netdev_info(dev, "EST: BTR Error Loop Count %u\n",
|
||||
btrl);
|
||||
|
||||
writel(EST_BTRE, est_addr + EST_STATUS);
|
||||
}
|
||||
|
||||
if (status & EST_SWLC) {
|
||||
writel(EST_SWLC, est_addr + EST_STATUS);
|
||||
netdev_info(dev, "EST: SWOL has been switched\n");
|
||||
}
|
||||
}
|
||||
|
||||
const struct stmmac_est_ops dwmac510_est_ops = {
|
||||
.configure = est_configure,
|
||||
.irq_status = est_irq_status,
|
||||
};
|
64
drivers/net/ethernet/stmicro/stmmac/stmmac_est.h
Normal file
64
drivers/net/ethernet/stmicro/stmmac/stmmac_est.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2023, Intel Corporation
|
||||
* stmmac EST(802.3 Qbv) handling
|
||||
*/
|
||||
|
||||
#define EST_GMAC4_OFFSET 0x00000c50
|
||||
#define EST_XGMAC_OFFSET 0x00001050
|
||||
|
||||
#define EST_CONTROL 0x00000000
|
||||
#define EST_GMAC5_PTOV GENMASK(31, 24)
|
||||
#define EST_GMAC5_PTOV_SHIFT 24
|
||||
#define EST_GMAC5_PTOV_MUL 6
|
||||
#define EST_XGMAC_PTOV GENMASK(31, 23)
|
||||
#define EST_XGMAC_PTOV_SHIFT 23
|
||||
#define EST_XGMAC_PTOV_MUL 9
|
||||
#define EST_SSWL BIT(1)
|
||||
#define EST_EEST BIT(0)
|
||||
|
||||
#define EST_STATUS 0x00000008
|
||||
#define EST_GMAC5_BTRL GENMASK(11, 8)
|
||||
#define EST_XGMAC_BTRL GENMASK(15, 8)
|
||||
#define EST_SWOL BIT(7)
|
||||
#define EST_SWOL_SHIFT 7
|
||||
#define EST_CGCE BIT(4)
|
||||
#define EST_HLBS BIT(3)
|
||||
#define EST_HLBF BIT(2)
|
||||
#define EST_BTRE BIT(1)
|
||||
#define EST_SWLC BIT(0)
|
||||
|
||||
#define EST_SCH_ERR 0x00000010
|
||||
|
||||
#define EST_FRM_SZ_ERR 0x00000014
|
||||
|
||||
#define EST_FRM_SZ_CAP 0x00000018
|
||||
#define EST_SZ_CAP_HBFS_MASK GENMASK(14, 0)
|
||||
#define EST_SZ_CAP_HBFQ_SHIFT 16
|
||||
#define EST_SZ_CAP_HBFQ_MASK(val) \
|
||||
({ \
|
||||
typeof(val) _val = (val); \
|
||||
(_val > 4 ? GENMASK(18, 16) : \
|
||||
_val > 2 ? GENMASK(17, 16) : \
|
||||
BIT(16)); \
|
||||
})
|
||||
|
||||
#define EST_INT_EN 0x00000020
|
||||
#define EST_IECGCE EST_CGCE
|
||||
#define EST_IEHS EST_HLBS
|
||||
#define EST_IEHF EST_HLBF
|
||||
#define EST_IEBE EST_BTRE
|
||||
#define EST_IECC EST_SWLC
|
||||
|
||||
#define EST_GCL_CONTROL 0x00000030
|
||||
#define EST_BTR_LOW 0x0
|
||||
#define EST_BTR_HIGH 0x1
|
||||
#define EST_CTR_LOW 0x2
|
||||
#define EST_CTR_HIGH 0x3
|
||||
#define EST_TER 0x4
|
||||
#define EST_LLR 0x5
|
||||
#define EST_ADDR_SHIFT 8
|
||||
#define EST_GCRR BIT(2)
|
||||
#define EST_SRWO BIT(0)
|
||||
|
||||
#define EST_GCL_DATA 0x00000034
|
@ -5960,7 +5960,7 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv)
|
||||
pm_wakeup_event(priv->device, 0);
|
||||
|
||||
if (priv->dma_cap.estsel)
|
||||
stmmac_est_irq_status(priv, priv->ioaddr, priv->dev,
|
||||
stmmac_est_irq_status(priv, priv, priv->dev,
|
||||
&priv->xstats, tx_cnt);
|
||||
|
||||
if (priv->dma_cap.fpesel) {
|
||||
|
@ -72,7 +72,7 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
|
||||
est_rst = true;
|
||||
mutex_lock(&priv->plat->est->lock);
|
||||
priv->plat->est->enable = false;
|
||||
stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
|
||||
stmmac_est_configure(priv, priv, priv->plat->est,
|
||||
priv->plat->clk_ptp_rate);
|
||||
mutex_unlock(&priv->plat->est->lock);
|
||||
}
|
||||
@ -102,7 +102,7 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
|
||||
priv->plat->est->btr[0] = (u32)time.tv_nsec;
|
||||
priv->plat->est->btr[1] = (u32)time.tv_sec;
|
||||
priv->plat->est->enable = true;
|
||||
ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
|
||||
ret = stmmac_est_configure(priv, priv, priv->plat->est,
|
||||
priv->plat->clk_ptp_rate);
|
||||
mutex_unlock(&priv->plat->est->lock);
|
||||
if (ret)
|
||||
|
@ -975,6 +975,8 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
|
||||
return -EINVAL;
|
||||
if (!qopt->cycle_time)
|
||||
return -ERANGE;
|
||||
if (qopt->cycle_time_extension >= BIT(wid + 7))
|
||||
return -ERANGE;
|
||||
|
||||
if (!plat->est) {
|
||||
plat->est = devm_kzalloc(priv->device, sizeof(*plat->est),
|
||||
@ -1041,6 +1043,8 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
|
||||
priv->plat->est->ctr[0] = do_div(ctr, NSEC_PER_SEC);
|
||||
priv->plat->est->ctr[1] = (u32)ctr;
|
||||
|
||||
priv->plat->est->ter = qopt->cycle_time_extension;
|
||||
|
||||
if (fpe && !priv->dma_cap.fpesel) {
|
||||
mutex_unlock(&priv->plat->est->lock);
|
||||
return -EOPNOTSUPP;
|
||||
@ -1051,7 +1055,7 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
|
||||
*/
|
||||
priv->plat->fpe_cfg->enable = fpe;
|
||||
|
||||
ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
|
||||
ret = stmmac_est_configure(priv, priv, priv->plat->est,
|
||||
priv->plat->clk_ptp_rate);
|
||||
mutex_unlock(&priv->plat->est->lock);
|
||||
if (ret) {
|
||||
@ -1072,7 +1076,7 @@ disable:
|
||||
if (priv->plat->est) {
|
||||
mutex_lock(&priv->plat->est->lock);
|
||||
priv->plat->est->enable = false;
|
||||
stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
|
||||
stmmac_est_configure(priv, priv, priv->plat->est,
|
||||
priv->plat->clk_ptp_rate);
|
||||
mutex_unlock(&priv->plat->est->lock);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user