diff options
Diffstat (limited to 'drivers/net/ethernet/stmicro/stmmac')
17 files changed, 278 insertions, 89 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 85dcda51df05..4ec61f1ee71a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -165,9 +165,9 @@ config DWMAC_STARFIVE help Support for ethernet controllers on StarFive RISC-V SoCs - This selects the StarFive platform specific glue layer support for - the stmmac device driver. This driver is used for StarFive JH7110 - ethernet controller. + This selects the StarFive platform specific glue layer support + for the stmmac device driver. This driver is used for the + StarFive JH7100 and JH7110 ethernet controllers. config DWMAC_STI tristate "STi GMAC support" diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 5ba606a596e7..a6fefe675ef1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -225,6 +225,8 @@ struct stmmac_extra_stats { unsigned long mtl_est_hlbf; unsigned long mtl_est_btre; unsigned long mtl_est_btrlm; + unsigned long max_sdu_txq_drop[MTL_MAX_TX_QUEUES]; + unsigned long mtl_est_txq_hlbf[MTL_MAX_TX_QUEUES]; /* per queue statistics */ struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES]; struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES]; @@ -369,6 +371,7 @@ enum request_irq_err { REQ_IRQ_ERR_ALL, REQ_IRQ_ERR_TX, REQ_IRQ_ERR_RX, + REQ_IRQ_ERR_SFTY, REQ_IRQ_ERR_SFTY_UE, REQ_IRQ_ERR_SFTY_CE, REQ_IRQ_ERR_LPI, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 31631e3f89d0..e254b21fdb59 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -106,6 +106,7 @@ struct qcom_ethqos { struct clk *link_clk; struct phy *serdes_phy; unsigned int speed; + int serdes_speed; phy_interface_t phy_mode; const struct ethqos_emac_por *por; @@ -169,6 +170,9 @@ static void rgmii_dump(void *priv) static void ethqos_update_link_clk(struct qcom_ethqos *ethqos, unsigned int speed) { + if (!phy_interface_mode_is_rgmii(ethqos->phy_mode)) + return; + switch (speed) { case SPEED_1000: ethqos->link_clk_rate = RGMII_1000_NOM_CLK_FREQ; @@ -606,19 +610,39 @@ static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos) */ static int ethqos_configure_sgmii(struct qcom_ethqos *ethqos) { + struct net_device *dev = platform_get_drvdata(ethqos->pdev); + struct stmmac_priv *priv = netdev_priv(dev); int val; val = readl(ethqos->mac_base + MAC_CTRL_REG); switch (ethqos->speed) { + case SPEED_2500: + val &= ~ETHQOS_MAC_CTRL_PORT_SEL; + rgmii_updatel(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, + RGMII_CONFIG2_RGMII_CLK_SEL_CFG, + RGMII_IO_MACRO_CONFIG2); + if (ethqos->serdes_speed != SPEED_2500) + phy_set_speed(ethqos->serdes_phy, SPEED_2500); + ethqos->serdes_speed = SPEED_2500; + stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 0, 0, 0); + break; case SPEED_1000: val &= ~ETHQOS_MAC_CTRL_PORT_SEL; rgmii_updatel(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, RGMII_IO_MACRO_CONFIG2); + if (ethqos->serdes_speed != SPEED_1000) + phy_set_speed(ethqos->serdes_phy, SPEED_1000); + ethqos->serdes_speed = SPEED_1000; + stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, 0, 0); break; case SPEED_100: val |= ETHQOS_MAC_CTRL_PORT_SEL | ETHQOS_MAC_CTRL_SPEED_MODE; + if (ethqos->serdes_speed != SPEED_1000) + phy_set_speed(ethqos->serdes_phy, SPEED_1000); + ethqos->serdes_speed = SPEED_1000; + stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, 0, 0); break; case SPEED_10: val |= ETHQOS_MAC_CTRL_PORT_SEL; @@ -627,6 +651,10 @@ static int ethqos_configure_sgmii(struct qcom_ethqos *ethqos) FIELD_PREP(RGMII_CONFIG_SGMII_CLK_DVDR, SGMII_10M_RX_CLK_DVDR), RGMII_IO_MACRO_CONFIG); + if (ethqos->serdes_speed != SPEED_1000) + phy_set_speed(ethqos->serdes_phy, ethqos->speed); + ethqos->serdes_speed = SPEED_1000; + stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, 0, 0); break; } @@ -728,7 +756,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) struct stmmac_resources stmmac_res; struct device *dev = &pdev->dev; struct qcom_ethqos *ethqos; - int ret; + int ret, i; ret = stmmac_get_platform_resources(pdev, &stmmac_res); if (ret) @@ -799,6 +827,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) "Failed to get serdes phy\n"); ethqos->speed = SPEED_1000; + ethqos->serdes_speed = SPEED_1000; ethqos_update_link_clk(ethqos, SPEED_1000); ethqos_set_func_clk_en(ethqos); @@ -822,6 +851,10 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->serdes_powerdown = qcom_ethqos_serdes_powerdown; } + /* Enable TSO on queue0 and enable TBS on rest of the queues */ + for (i = 1; i < plat_dat->tx_queues_to_use; i++) + plat_dat->tx_queues_cfg[i].tbs_en = 1; + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index ba2ce776bd4d..68f85e4605cb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -585,4 +585,5 @@ static struct platform_driver socfpga_dwmac_driver = { }; module_platform_driver(socfpga_dwmac_driver); +MODULE_DESCRIPTION("Altera SOC DWMAC Specific Glue layer"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c index 5d630affb4d1..4e1076faee0c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c @@ -15,13 +15,20 @@ #include "stmmac_platform.h" -#define STARFIVE_DWMAC_PHY_INFT_RGMII 0x1 -#define STARFIVE_DWMAC_PHY_INFT_RMII 0x4 -#define STARFIVE_DWMAC_PHY_INFT_FIELD 0x7U +#define STARFIVE_DWMAC_PHY_INFT_RGMII 0x1 +#define STARFIVE_DWMAC_PHY_INFT_RMII 0x4 +#define STARFIVE_DWMAC_PHY_INFT_FIELD 0x7U + +#define JH7100_SYSMAIN_REGISTER49_DLYCHAIN 0xc8 + +struct starfive_dwmac_data { + unsigned int gtxclk_dlychain; +}; struct starfive_dwmac { struct device *dev; struct clk *clk_tx; + const struct starfive_dwmac_data *data; }; static void starfive_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode) @@ -67,6 +74,8 @@ static int starfive_dwmac_set_mode(struct plat_stmmacenet_data *plat_dat) case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: mode = STARFIVE_DWMAC_PHY_INFT_RGMII; break; @@ -89,6 +98,14 @@ static int starfive_dwmac_set_mode(struct plat_stmmacenet_data *plat_dat) if (err) return dev_err_probe(dwmac->dev, err, "error setting phy mode\n"); + if (dwmac->data) { + err = regmap_write(regmap, JH7100_SYSMAIN_REGISTER49_DLYCHAIN, + dwmac->data->gtxclk_dlychain); + if (err) + return dev_err_probe(dwmac->dev, err, + "error selecting gtxclk delay chain\n"); + } + return 0; } @@ -114,6 +131,8 @@ static int starfive_dwmac_probe(struct platform_device *pdev) if (!dwmac) return -ENOMEM; + dwmac->data = device_get_match_data(&pdev->dev); + dwmac->clk_tx = devm_clk_get_enabled(&pdev->dev, "tx"); if (IS_ERR(dwmac->clk_tx)) return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->clk_tx), @@ -144,8 +163,13 @@ static int starfive_dwmac_probe(struct platform_device *pdev) return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); } +static const struct starfive_dwmac_data jh7100_data = { + .gtxclk_dlychain = 4, +}; + static const struct of_device_id starfive_dwmac_match[] = { - { .compatible = "starfive,jh7110-dwmac" }, + { .compatible = "starfive,jh7100-dwmac", .data = &jh7100_data }, + { .compatible = "starfive,jh7110-dwmac" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, starfive_dwmac_match); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h index 358e7dcb6a9a..17d9120db5fe 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h @@ -92,7 +92,7 @@ #define DMA_TBS_FTOV BIT(0) #define DMA_TBS_DEF_FTOS (DMA_TBS_FTOS | DMA_TBS_FTOV) -/* Following DMA defines are chanels oriented */ +/* Following DMA defines are channel-oriented */ #define DMA_CHAN_BASE_ADDR 0x00001100 #define DMA_CHAN_BASE_OFFSET 0x80 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 323c57f03c93..1af2f89a0504 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -830,41 +830,42 @@ static const struct dwxgmac3_error_desc dwxgmac3_dma_errors[32]= { { false, "UNKNOWN", "Unknown Error" }, /* 31 */ }; -static const char * const dpp_rx_err = "Read Rx Descriptor Parity checker Error"; -static const char * const dpp_tx_err = "Read Tx Descriptor Parity checker Error"; +#define DPP_RX_ERR "Read Rx Descriptor Parity checker Error" +#define DPP_TX_ERR "Read Tx Descriptor Parity checker Error" + static const struct dwxgmac3_error_desc dwxgmac3_dma_dpp_errors[32] = { - { true, "TDPES0", dpp_tx_err }, - { true, "TDPES1", dpp_tx_err }, - { true, "TDPES2", dpp_tx_err }, - { true, "TDPES3", dpp_tx_err }, - { true, "TDPES4", dpp_tx_err }, - { true, "TDPES5", dpp_tx_err }, - { true, "TDPES6", dpp_tx_err }, - { true, "TDPES7", dpp_tx_err }, - { true, "TDPES8", dpp_tx_err }, - { true, "TDPES9", dpp_tx_err }, - { true, "TDPES10", dpp_tx_err }, - { true, "TDPES11", dpp_tx_err }, - { true, "TDPES12", dpp_tx_err }, - { true, "TDPES13", dpp_tx_err }, - { true, "TDPES14", dpp_tx_err }, - { true, "TDPES15", dpp_tx_err }, - { true, "RDPES0", dpp_rx_err }, - { true, "RDPES1", dpp_rx_err }, - { true, "RDPES2", dpp_rx_err }, - { true, "RDPES3", dpp_rx_err }, - { true, "RDPES4", dpp_rx_err }, - { true, "RDPES5", dpp_rx_err }, - { true, "RDPES6", dpp_rx_err }, - { true, "RDPES7", dpp_rx_err }, - { true, "RDPES8", dpp_rx_err }, - { true, "RDPES9", dpp_rx_err }, - { true, "RDPES10", dpp_rx_err }, - { true, "RDPES11", dpp_rx_err }, - { true, "RDPES12", dpp_rx_err }, - { true, "RDPES13", dpp_rx_err }, - { true, "RDPES14", dpp_rx_err }, - { true, "RDPES15", dpp_rx_err }, + { true, "TDPES0", DPP_TX_ERR }, + { true, "TDPES1", DPP_TX_ERR }, + { true, "TDPES2", DPP_TX_ERR }, + { true, "TDPES3", DPP_TX_ERR }, + { true, "TDPES4", DPP_TX_ERR }, + { true, "TDPES5", DPP_TX_ERR }, + { true, "TDPES6", DPP_TX_ERR }, + { true, "TDPES7", DPP_TX_ERR }, + { true, "TDPES8", DPP_TX_ERR }, + { true, "TDPES9", DPP_TX_ERR }, + { true, "TDPES10", DPP_TX_ERR }, + { true, "TDPES11", DPP_TX_ERR }, + { true, "TDPES12", DPP_TX_ERR }, + { true, "TDPES13", DPP_TX_ERR }, + { true, "TDPES14", DPP_TX_ERR }, + { true, "TDPES15", DPP_TX_ERR }, + { true, "RDPES0", DPP_RX_ERR }, + { true, "RDPES1", DPP_RX_ERR }, + { true, "RDPES2", DPP_RX_ERR }, + { true, "RDPES3", DPP_RX_ERR }, + { true, "RDPES4", DPP_RX_ERR }, + { true, "RDPES5", DPP_RX_ERR }, + { true, "RDPES6", DPP_RX_ERR }, + { true, "RDPES7", DPP_RX_ERR }, + { true, "RDPES8", DPP_RX_ERR }, + { true, "RDPES9", DPP_RX_ERR }, + { true, "RDPES10", DPP_RX_ERR }, + { true, "RDPES11", DPP_RX_ERR }, + { true, "RDPES12", DPP_RX_ERR }, + { true, "RDPES13", DPP_RX_ERR }, + { true, "RDPES14", DPP_RX_ERR }, + { true, "RDPES15", DPP_RX_ERR }, }; static void dwxgmac3_handle_dma_err(struct net_device *ndev, diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c index 1bd34b2a47e8..29367105df54 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c @@ -224,7 +224,7 @@ static const struct stmmac_hwif_entry { .regs = { .ptp_off = PTP_GMAC4_OFFSET, .mmc_off = MMC_GMAC4_OFFSET, - .est_off = EST_XGMAC_OFFSET, + .est_off = EST_GMAC4_OFFSET, }, .desc = &dwmac4_desc_ops, .dma = &dwmac410_dma_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc.h b/drivers/net/ethernet/stmicro/stmmac/mmc.h index 14c9d2637dfe..dff02d75d519 100644 --- a/drivers/net/ethernet/stmicro/stmmac/mmc.h +++ b/drivers/net/ethernet/stmicro/stmmac/mmc.h @@ -86,10 +86,6 @@ struct stmmac_counters { unsigned int mmc_rx_discard_octets_gb; unsigned int mmc_rx_align_err_frames; - /* IPC */ - unsigned int mmc_rx_ipc_intr_mask; - unsigned int mmc_rx_ipc_intr; - /* IPv4 */ unsigned int mmc_rx_ipv4_gd; unsigned int mmc_rx_ipv4_hderr; diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c index 8597c6abae8d..7eb477faa75a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c @@ -316,9 +316,6 @@ static void dwmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc) mmc->mmc_rx_fifo_overflow += readl(mmcaddr + MMC_RX_FIFO_OVERFLOW); mmc->mmc_rx_vlan_frames_gb += readl(mmcaddr + MMC_RX_VLAN_FRAMES_GB); mmc->mmc_rx_watchdog_error += readl(mmcaddr + MMC_RX_WATCHDOG_ERROR); - /* IPC */ - mmc->mmc_rx_ipc_intr_mask += readl(mmcaddr + MMC_RX_IPC_INTR_MASK); - mmc->mmc_rx_ipc_intr += readl(mmcaddr + MMC_RX_IPC_INTR); /* IPv4 */ mmc->mmc_rx_ipv4_gd += readl(mmcaddr + MMC_RX_IPV4_GD); mmc->mmc_rx_ipv4_hderr += readl(mmcaddr + MMC_RX_IPV4_HDERR); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index f155e4841c62..dddcaa9220cc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -31,6 +31,7 @@ struct stmmac_resources { int wol_irq; int lpi_irq; int irq; + int sfty_irq; int sfty_ce_irq; int sfty_ue_irq; int rx_irq[MTL_MAX_RX_QUEUES]; @@ -298,6 +299,7 @@ struct stmmac_priv { void __iomem *ptpaddr; void __iomem *estaddr; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; + int sfty_irq; int sfty_ce_irq; int sfty_ue_irq; int rx_irq[MTL_MAX_RX_QUEUES]; @@ -306,6 +308,7 @@ struct stmmac_priv { char int_name_mac[IFNAMSIZ + 9]; char int_name_wol[IFNAMSIZ + 9]; char int_name_lpi[IFNAMSIZ + 9]; + char int_name_sfty[IFNAMSIZ + 10]; char int_name_sfty_ce[IFNAMSIZ + 10]; char int_name_sfty_ue[IFNAMSIZ + 10]; char int_name_rx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 14]; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c index 4da6ccc17c20..c9693f77e1f6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c @@ -81,6 +81,7 @@ static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev, u32 status, value, feqn, hbfq, hbfs, btrl, btrl_max; void __iomem *est_addr = priv->estaddr; u32 txqcnt_mask = BIT(txqcnt) - 1; + int i; status = readl(est_addr + EST_STATUS); @@ -125,6 +126,11 @@ static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev, x->mtl_est_hlbf++; + for (i = 0; i < txqcnt; i++) { + if (feqn & BIT(i)) + x->mtl_est_txq_hlbf[i]++; + } + /* Clear Interrupt */ writel(feqn, est_addr + EST_FRM_SZ_ERR); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index ec44becf0e2d..e1537a57815f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -243,8 +243,6 @@ static const struct stmmac_stats stmmac_mmc[] = { STMMAC_MMC_STAT(mmc_rx_discard_frames_gb), STMMAC_MMC_STAT(mmc_rx_discard_octets_gb), STMMAC_MMC_STAT(mmc_rx_align_err_frames), - STMMAC_MMC_STAT(mmc_rx_ipc_intr_mask), - STMMAC_MMC_STAT(mmc_rx_ipc_intr), STMMAC_MMC_STAT(mmc_rx_ipv4_gd), STMMAC_MMC_STAT(mmc_rx_ipv4_hderr), STMMAC_MMC_STAT(mmc_rx_ipv4_nopay), @@ -897,15 +895,13 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) } static int stmmac_ethtool_op_get_eee(struct net_device *dev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct stmmac_priv *priv = netdev_priv(dev); if (!priv->dma_cap.eee) return -EOPNOTSUPP; - edata->eee_enabled = priv->eee_enabled; - edata->eee_active = priv->eee_active; edata->tx_lpi_timer = priv->tx_lpi_timer; edata->tx_lpi_enabled = priv->tx_lpi_enabled; @@ -913,7 +909,7 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev, } static int stmmac_ethtool_op_set_eee(struct net_device *dev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct stmmac_priv *priv = netdev_priv(dev); int ret; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 75d029704503..24cd80490d19 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2506,6 +2506,13 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) if (!xsk_tx_peek_desc(pool, &xdp_desc)) break; + if (priv->plat->est && priv->plat->est->enable && + priv->plat->est->max_sdu[queue] && + xdp_desc.len > priv->plat->est->max_sdu[queue]) { + priv->xstats.max_sdu_txq_drop[queue]++; + continue; + } + if (likely(priv->extend_desc)) tx_desc = (struct dma_desc *)(tx_q->dma_etx + entry); else if (tx_q->tbs & STMMAC_TBS_AVAIL) @@ -2672,7 +2679,8 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue, } if (skb) { stmmac_get_tx_hwtstamp(priv, p, skb); - } else { + } else if (tx_q->xsk_pool && + xp_tx_metadata_enabled(tx_q->xsk_pool)) { struct stmmac_xsk_tx_complete tx_compl = { .priv = priv, .desc = p, @@ -3590,6 +3598,10 @@ static void stmmac_free_irq(struct net_device *dev, if (priv->wol_irq > 0 && priv->wol_irq != dev->irq) free_irq(priv->wol_irq, dev); fallthrough; + case REQ_IRQ_ERR_SFTY: + if (priv->sfty_irq > 0 && priv->sfty_irq != dev->irq) + free_irq(priv->sfty_irq, dev); + fallthrough; case REQ_IRQ_ERR_WOL: free_irq(dev->irq, dev); fallthrough; @@ -3660,6 +3672,23 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev) } } + /* Request the common Safety Feature Correctible/Uncorrectible + * Error line in case of another line is used + */ + if (priv->sfty_irq > 0 && priv->sfty_irq != dev->irq) { + int_name = priv->int_name_sfty; + sprintf(int_name, "%s:%s", dev->name, "safety"); + ret = request_irq(priv->sfty_irq, stmmac_safety_interrupt, + 0, int_name, dev); + if (unlikely(ret < 0)) { + netdev_err(priv->dev, + "%s: alloc sfty MSI %d (error: %d)\n", + __func__, priv->sfty_irq, ret); + irq_err = REQ_IRQ_ERR_SFTY; + goto irq_error; + } + } + /* Request the Safety Feature Correctible Error line in * case of another line is used */ @@ -3797,6 +3826,21 @@ static int stmmac_request_irq_single(struct net_device *dev) } } + /* Request the common Safety Feature Correctible/Uncorrectible + * Error line in case of another line is used + */ + if (priv->sfty_irq > 0 && priv->sfty_irq != dev->irq) { + ret = request_irq(priv->sfty_irq, stmmac_safety_interrupt, + IRQF_SHARED, dev->name, dev); + if (unlikely(ret < 0)) { + netdev_err(priv->dev, + "%s: ERROR: allocating the sfty IRQ %d (%d)\n", + __func__, priv->sfty_irq, ret); + irq_err = REQ_IRQ_ERR_SFTY; + goto irq_error; + } + } + return 0; irq_error: @@ -4005,8 +4049,10 @@ static void stmmac_fpe_stop_wq(struct stmmac_priv *priv) { set_bit(__FPE_REMOVING, &priv->fpe_task_state); - if (priv->fpe_wq) + if (priv->fpe_wq) { destroy_workqueue(priv->fpe_wq); + priv->fpe_wq = NULL; + } netdev_info(priv->dev, "FPE workqueue stop"); } @@ -4497,6 +4543,13 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) return stmmac_tso_xmit(skb, dev); } + if (priv->plat->est && priv->plat->est->enable && + priv->plat->est->max_sdu[queue] && + skb->len > priv->plat->est->max_sdu[queue]){ + priv->xstats.max_sdu_txq_drop[queue]++; + goto max_sdu_err; + } + if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) { if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, queue))) { netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, @@ -4714,6 +4767,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) dma_map_err: netdev_err(priv->dev, "Tx DMA map failed\n"); +max_sdu_err: dev_kfree_skb(skb); priv->xstats.tx_dropped++; return NETDEV_TX_OK; @@ -4870,6 +4924,13 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, if (stmmac_tx_avail(priv, queue) < STMMAC_TX_THRESH(priv)) return STMMAC_XDP_CONSUMED; + if (priv->plat->est && priv->plat->est->enable && + priv->plat->est->max_sdu[queue] && + xdpf->len > priv->plat->est->max_sdu[queue]) { + priv->xstats.max_sdu_txq_drop[queue]++; + return STMMAC_XDP_CONSUMED; + } + if (likely(priv->extend_desc)) tx_desc = (struct dma_desc *)(tx_q->dma_etx + entry); else if (tx_q->tbs & STMMAC_TBS_AVAIL) @@ -6003,10 +6064,8 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv) priv->tx_path_in_lpi_mode = false; } - for (queue = 0; queue < queues_count; queue++) { - status = stmmac_host_mtl_irq_status(priv, priv->hw, - queue); - } + for (queue = 0; queue < queues_count; queue++) + stmmac_host_mtl_irq_status(priv, priv->hw, queue); /* PCS link status */ if (priv->hw->pcs && @@ -6041,8 +6100,8 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) if (test_bit(STMMAC_DOWN, &priv->state)) return IRQ_HANDLED; - /* Check if a fatal error happened */ - if (stmmac_safety_feat_interrupt(priv)) + /* Check ASP error if it isn't delivered via an individual IRQ */ + if (priv->sfty_irq <= 0 && stmmac_safety_feat_interrupt(priv)) return IRQ_HANDLED; /* To handle Common interrupts */ @@ -6059,11 +6118,6 @@ static irqreturn_t stmmac_mac_interrupt(int irq, void *dev_id) struct net_device *dev = (struct net_device *)dev_id; struct stmmac_priv *priv = netdev_priv(dev); - if (unlikely(!dev)) { - netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__); - return IRQ_NONE; - } - /* Check if adapter is up */ if (test_bit(STMMAC_DOWN, &priv->state)) return IRQ_HANDLED; @@ -6079,11 +6133,6 @@ static irqreturn_t stmmac_safety_interrupt(int irq, void *dev_id) struct net_device *dev = (struct net_device *)dev_id; struct stmmac_priv *priv = netdev_priv(dev); - if (unlikely(!dev)) { - netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__); - return IRQ_NONE; - } - /* Check if adapter is up */ if (test_bit(STMMAC_DOWN, &priv->state)) return IRQ_HANDLED; @@ -6105,11 +6154,6 @@ static irqreturn_t stmmac_msi_intr_tx(int irq, void *data) dma_conf = container_of(tx_q, struct stmmac_dma_conf, tx_queue[chan]); priv = container_of(dma_conf, struct stmmac_priv, dma_conf); - if (unlikely(!data)) { - netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__); - return IRQ_NONE; - } - /* Check if adapter is up */ if (test_bit(STMMAC_DOWN, &priv->state)) return IRQ_HANDLED; @@ -6136,11 +6180,6 @@ static irqreturn_t stmmac_msi_intr_rx(int irq, void *data) dma_conf = container_of(rx_q, struct stmmac_dma_conf, rx_queue[chan]); priv = container_of(dma_conf, struct stmmac_priv, dma_conf); - if (unlikely(!data)) { - netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__); - return IRQ_NONE; - } - /* Check if adapter is up */ if (test_bit(STMMAC_DOWN, &priv->state)) return IRQ_HANDLED; @@ -7491,6 +7530,7 @@ int stmmac_dvr_probe(struct device *device, priv->dev->irq = res->irq; priv->wol_irq = res->wol_irq; priv->lpi_irq = res->lpi_irq; + priv->sfty_irq = res->sfty_irq; priv->sfty_ce_irq = res->sfty_ce_irq; priv->sfty_ue_irq = res->sfty_ue_irq; for (i = 0; i < MTL_MAX_RX_QUEUES; i++) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h index aefc121464b5..13a30e6df4c1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h @@ -110,6 +110,8 @@ static inline void dwmac_ctrl_ane(void __iomem *ioaddr, u32 reg, bool ane, /* Enable and restart the Auto-Negotiation */ if (ane) value |= GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_RAN; + else + value &= ~GMAC_AN_CTRL_ANE; /* In case of MAC-2-MAC connection, block is configured to operate * according to MAC conf register. diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 70eadc83ca68..54797edc9b38 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -743,6 +743,14 @@ int stmmac_get_platform_resources(struct platform_device *pdev, dev_info(&pdev->dev, "IRQ eth_lpi not found\n"); } + stmmac_res->sfty_irq = + platform_get_irq_byname_optional(pdev, "sfty"); + if (stmmac_res->sfty_irq < 0) { + if (stmmac_res->sfty_irq == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_info(&pdev->dev, "IRQ sfty not found\n"); + } + stmmac_res->addr = devm_platform_ioremap_resource(pdev, 0); return PTR_ERR_OR_ZERO(stmmac_res->addr); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 26fa33e5ec34..cce00719937d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -915,8 +915,30 @@ struct timespec64 stmmac_calc_tas_basetime(ktime_t old_base_time, return time; } -static int tc_setup_taprio(struct stmmac_priv *priv, - struct tc_taprio_qopt_offload *qopt) +static void tc_taprio_map_maxsdu_txq(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) +{ + struct plat_stmmacenet_data *plat = priv->plat; + u32 num_tc = qopt->mqprio.qopt.num_tc; + u32 offset, count, i, j; + + /* QueueMaxSDU received from the driver corresponds to the Linux traffic + * class. Map queueMaxSDU per Linux traffic class to DWMAC Tx queues. + */ + for (i = 0; i < num_tc; i++) { + if (!qopt->max_sdu[i]) + continue; + + offset = qopt->mqprio.qopt.offset[i]; + count = qopt->mqprio.qopt.count[i]; + + for (j = offset; j < offset + count; j++) + plat->est->max_sdu[j] = qopt->max_sdu[i] + ETH_HLEN - ETH_TLEN; + } +} + +static int tc_taprio_configure(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; @@ -968,8 +990,6 @@ static int tc_setup_taprio(struct stmmac_priv *priv, if (qopt->cmd == TAPRIO_CMD_DESTROY) goto disable; - else if (qopt->cmd != TAPRIO_CMD_REPLACE) - return -EOPNOTSUPP; if (qopt->num_entries >= dep) return -EINVAL; @@ -1045,6 +1065,8 @@ static int tc_setup_taprio(struct stmmac_priv *priv, priv->plat->est->ter = qopt->cycle_time_extension; + tc_taprio_map_maxsdu_txq(priv, qopt); + if (fpe && !priv->dma_cap.fpesel) { mutex_unlock(&priv->plat->est->lock); return -EOPNOTSUPP; @@ -1078,6 +1100,11 @@ disable: priv->plat->est->enable = false; stmmac_est_configure(priv, priv, priv->plat->est, priv->plat->clk_ptp_rate); + /* Reset taprio status */ + for (i = 0; i < priv->plat->tx_queues_to_use; i++) { + priv->xstats.max_sdu_txq_drop[i] = 0; + priv->xstats.mtl_est_txq_hlbf[i] = 0; + } mutex_unlock(&priv->plat->est->lock); } @@ -1095,6 +1122,57 @@ disable: return ret; } +static void tc_taprio_stats(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) +{ + u64 window_drops = 0; + int i = 0; + + for (i = 0; i < priv->plat->tx_queues_to_use; i++) + window_drops += priv->xstats.max_sdu_txq_drop[i] + + priv->xstats.mtl_est_txq_hlbf[i]; + qopt->stats.window_drops = window_drops; + + /* Transmission overrun doesn't happen for stmmac, hence always 0 */ + qopt->stats.tx_overruns = 0; +} + +static void tc_taprio_queue_stats(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) +{ + struct tc_taprio_qopt_queue_stats *q_stats = &qopt->queue_stats; + int queue = qopt->queue_stats.queue; + + q_stats->stats.window_drops = priv->xstats.max_sdu_txq_drop[queue] + + priv->xstats.mtl_est_txq_hlbf[queue]; + + /* Transmission overrun doesn't happen for stmmac, hence always 0 */ + q_stats->stats.tx_overruns = 0; +} + +static int tc_setup_taprio(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) +{ + int err = 0; + + switch (qopt->cmd) { + case TAPRIO_CMD_REPLACE: + case TAPRIO_CMD_DESTROY: + err = tc_taprio_configure(priv, qopt); + break; + case TAPRIO_CMD_STATS: + tc_taprio_stats(priv, qopt); + break; + case TAPRIO_CMD_QUEUE_STATS: + tc_taprio_queue_stats(priv, qopt); + break; + default: + err = -EOPNOTSUPP; + } + + return err; +} + static int tc_setup_etf(struct stmmac_priv *priv, struct tc_etf_qopt_offload *qopt) { @@ -1126,6 +1204,7 @@ static int tc_query_caps(struct stmmac_priv *priv, return -EOPNOTSUPP; caps->gate_mask_per_txq = true; + caps->supports_queue_max_sdu = true; return 0; } |