mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
Merge branch 'net-stmmac-refactor-fpe-as-a-separate-module'
Furong Xu says: ==================== net: stmmac: Refactor FPE as a separate module Refactor FPE implementation by moving common code for DWMAC4 and DWXGMAC into a separate FPE module. FPE implementation for DWMAC4 and DWXGMAC differs only for: 1) Offset address of MAC_FPE_CTRL_STS and MTL_FPE_CTRL_STS 2) FPRQ(Frame Preemption Residue Queue) field in MAC_RxQ_Ctrl1 3) Bit offset of Frame Preemption Interrupt Enable Tested on DWMAC CORE 5.20a and DWXGMAC CORE 3.20a ==================== Link: https://patch.msgid.link/cover.1730449003.git.0x1207@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
74a11428cb
|
|
@ -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_est.o \
|
||||
stmmac_xdp.o stmmac_est.o stmmac_fpe.o \
|
||||
$(stmmac-y)
|
||||
|
||||
stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@
|
|||
#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)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_fpe.h"
|
||||
#include "stmmac_pcs.h"
|
||||
#include "dwmac4.h"
|
||||
#include "dwmac5.h"
|
||||
|
|
@ -1261,11 +1262,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,
|
||||
.fpe_configure = dwmac5_fpe_configure,
|
||||
.fpe_send_mpacket = dwmac5_fpe_send_mpacket,
|
||||
.fpe_irq_status = dwmac5_fpe_irq_status,
|
||||
.fpe_get_add_frag_size = dwmac5_fpe_get_add_frag_size,
|
||||
.fpe_set_add_frag_size = dwmac5_fpe_set_add_frag_size,
|
||||
.fpe_map_preemption_class = dwmac5_fpe_map_preemption_class,
|
||||
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
|
||||
.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
|
||||
|
|
@ -1316,11 +1312,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,
|
||||
.fpe_configure = dwmac5_fpe_configure,
|
||||
.fpe_send_mpacket = dwmac5_fpe_send_mpacket,
|
||||
.fpe_irq_status = dwmac5_fpe_irq_status,
|
||||
.fpe_get_add_frag_size = dwmac5_fpe_get_add_frag_size,
|
||||
.fpe_set_add_frag_size = dwmac5_fpe_set_add_frag_size,
|
||||
.fpe_map_preemption_class = dwmac5_fpe_map_preemption_class,
|
||||
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
|
||||
.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
|
||||
|
|
|
|||
|
|
@ -572,153 +572,3 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
|
|||
writel(val, ioaddr + MAC_PPS_CONTROL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
u32 num_txq, u32 num_rxq,
|
||||
bool tx_enable, bool pmac_enable)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
if (tx_enable) {
|
||||
cfg->fpe_csr = EFPE;
|
||||
value = readl(ioaddr + GMAC_RXQ_CTRL1);
|
||||
value &= ~GMAC_RXQCTRL_FPRQ;
|
||||
value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
|
||||
writel(value, ioaddr + GMAC_RXQ_CTRL1);
|
||||
} else {
|
||||
cfg->fpe_csr = 0;
|
||||
}
|
||||
writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS);
|
||||
|
||||
value = readl(ioaddr + GMAC_INT_EN);
|
||||
|
||||
if (pmac_enable) {
|
||||
if (!(value & GMAC_INT_FPE_EN)) {
|
||||
/* Dummy read to clear any pending masked interrupts */
|
||||
readl(ioaddr + MAC_FPE_CTRL_STS);
|
||||
|
||||
value |= GMAC_INT_FPE_EN;
|
||||
}
|
||||
} else {
|
||||
value &= ~GMAC_INT_FPE_EN;
|
||||
}
|
||||
|
||||
writel(value, ioaddr + GMAC_INT_EN);
|
||||
}
|
||||
|
||||
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
|
||||
{
|
||||
u32 value;
|
||||
int status;
|
||||
|
||||
status = FPE_EVENT_UNKNOWN;
|
||||
|
||||
/* Reads from the MAC_FPE_CTRL_STS register should only be performed
|
||||
* here, since the status flags of MAC_FPE_CTRL_STS are "clear on read"
|
||||
*/
|
||||
value = readl(ioaddr + MAC_FPE_CTRL_STS);
|
||||
|
||||
if (value & TRSP) {
|
||||
status |= FPE_EVENT_TRSP;
|
||||
netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n");
|
||||
}
|
||||
|
||||
if (value & TVER) {
|
||||
status |= FPE_EVENT_TVER;
|
||||
netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n");
|
||||
}
|
||||
|
||||
if (value & RRSP) {
|
||||
status |= FPE_EVENT_RRSP;
|
||||
netdev_dbg(dev, "FPE: Respond mPacket is received\n");
|
||||
}
|
||||
|
||||
if (value & RVER) {
|
||||
status |= FPE_EVENT_RVER;
|
||||
netdev_dbg(dev, "FPE: Verify mPacket is received\n");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
enum stmmac_mpacket_type type)
|
||||
{
|
||||
u32 value = cfg->fpe_csr;
|
||||
|
||||
if (type == MPACKET_VERIFY)
|
||||
value |= SVER;
|
||||
else if (type == MPACKET_RESPONSE)
|
||||
value |= SRSP;
|
||||
|
||||
writel(value, ioaddr + MAC_FPE_CTRL_STS);
|
||||
}
|
||||
|
||||
int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr)
|
||||
{
|
||||
return FIELD_GET(DWMAC5_ADD_FRAG_SZ, readl(ioaddr + MTL_FPE_CTRL_STS));
|
||||
}
|
||||
|
||||
void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + MTL_FPE_CTRL_STS);
|
||||
writel(u32_replace_bits(value, add_frag_size, DWMAC5_ADD_FRAG_SZ),
|
||||
ioaddr + MTL_FPE_CTRL_STS);
|
||||
}
|
||||
|
||||
#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping"
|
||||
#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]"
|
||||
|
||||
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack, u32 pclass)
|
||||
{
|
||||
u32 val, offset, count, queue_weight, preemptible_txqs = 0;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
u32 num_tc = ndev->num_tc;
|
||||
|
||||
if (!pclass)
|
||||
goto update_mapping;
|
||||
|
||||
/* DWMAC CORE4+ can not program TC:TXQ mapping to hardware.
|
||||
*
|
||||
* Synopsys Databook:
|
||||
* "The number of Tx DMA channels is equal to the number of Tx queues,
|
||||
* and is direct one-to-one mapping."
|
||||
*/
|
||||
for (u32 tc = 0; tc < num_tc; tc++) {
|
||||
count = ndev->tc_to_txq[tc].count;
|
||||
offset = ndev->tc_to_txq[tc].offset;
|
||||
|
||||
if (pclass & BIT(tc))
|
||||
preemptible_txqs |= GENMASK(offset + count - 1, offset);
|
||||
|
||||
/* This is 1:1 mapping, go to next TC */
|
||||
if (count == 1)
|
||||
continue;
|
||||
|
||||
if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) {
|
||||
NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
queue_weight = priv->plat->tx_queues_cfg[offset].weight;
|
||||
|
||||
for (u32 i = 1; i < count; i++) {
|
||||
if (priv->plat->tx_queues_cfg[offset + i].weight !=
|
||||
queue_weight) {
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG,
|
||||
queue_weight, tc);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_mapping:
|
||||
val = readl(priv->ioaddr + MTL_FPE_CTRL_STS);
|
||||
writel(u32_replace_bits(val, preemptible_txqs, DWMAC5_PREEMPTION_CLASS),
|
||||
priv->ioaddr + MTL_FPE_CTRL_STS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,15 +11,6 @@
|
|||
#define PRTYEN BIT(1)
|
||||
#define TMOUTEN BIT(0)
|
||||
|
||||
#define MAC_FPE_CTRL_STS 0x00000234
|
||||
#define TRSP BIT(19)
|
||||
#define TVER BIT(18)
|
||||
#define RRSP BIT(17)
|
||||
#define RVER BIT(16)
|
||||
#define SRSP BIT(2)
|
||||
#define SVER BIT(1)
|
||||
#define EFPE BIT(0)
|
||||
|
||||
#define MAC_PPS_CONTROL 0x00000b70
|
||||
#define PPS_MAXIDX(x) ((((x) + 1) * 8) - 1)
|
||||
#define PPS_MINIDX(x) ((x) * 8)
|
||||
|
|
@ -39,12 +30,6 @@
|
|||
#define MAC_PPSx_INTERVAL(x) (0x00000b88 + ((x) * 0x10))
|
||||
#define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10))
|
||||
|
||||
#define MTL_FPE_CTRL_STS 0x00000c90
|
||||
/* Preemption Classification */
|
||||
#define DWMAC5_PREEMPTION_CLASS GENMASK(15, 8)
|
||||
/* Additional Fragment Size of preempted frames */
|
||||
#define DWMAC5_ADD_FRAG_SZ GENMASK(1, 0)
|
||||
|
||||
#define MTL_RXP_CONTROL_STATUS 0x00000ca0
|
||||
#define RXPI BIT(31)
|
||||
#define NPE GENMASK(23, 16)
|
||||
|
|
@ -108,16 +93,5 @@ 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);
|
||||
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
u32 num_txq, u32 num_rxq,
|
||||
bool tx_enable, bool pmac_enable);
|
||||
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
|
||||
struct stmmac_fpe_cfg *cfg,
|
||||
enum stmmac_mpacket_type type);
|
||||
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev);
|
||||
int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr);
|
||||
void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size);
|
||||
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack, u32 pclass);
|
||||
|
||||
#endif /* __DWMAC5_H__ */
|
||||
|
|
|
|||
|
|
@ -84,8 +84,7 @@
|
|||
#define XGMAC_MCBCQEN BIT(15)
|
||||
#define XGMAC_MCBCQ GENMASK(11, 8)
|
||||
#define XGMAC_MCBCQ_SHIFT 8
|
||||
#define XGMAC_RQ GENMASK(7, 4)
|
||||
#define XGMAC_RQ_SHIFT 4
|
||||
#define XGMAC_FPRQ GENMASK(7, 4)
|
||||
#define XGMAC_UPQ GENMASK(3, 0)
|
||||
#define XGMAC_UPQ_SHIFT 0
|
||||
#define XGMAC_RXQ_CTRL2 0x000000a8
|
||||
|
|
@ -96,6 +95,7 @@
|
|||
#define XGMAC_LPIIS BIT(5)
|
||||
#define XGMAC_PMTIS BIT(4)
|
||||
#define XGMAC_INT_EN 0x000000b4
|
||||
#define XGMAC_FPEIE BIT(15)
|
||||
#define XGMAC_TSIE BIT(12)
|
||||
#define XGMAC_LPIIE BIT(5)
|
||||
#define XGMAC_PMTIE BIT(4)
|
||||
|
|
@ -193,8 +193,6 @@
|
|||
#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)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/crc32.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_fpe.h"
|
||||
#include "stmmac_ptp.h"
|
||||
#include "dwxlgmac2.h"
|
||||
#include "dwxgmac2.h"
|
||||
|
|
@ -1504,32 +1505,6 @@ static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en,
|
|||
writel(value, ioaddr + XGMAC_RX_CONFIG);
|
||||
}
|
||||
|
||||
static void dwxgmac3_fpe_configure(void __iomem *ioaddr,
|
||||
struct stmmac_fpe_cfg *cfg,
|
||||
u32 num_txq, u32 num_rxq,
|
||||
bool tx_enable, bool pmac_enable)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
if (!tx_enable) {
|
||||
value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
|
||||
|
||||
value &= ~XGMAC_EFPE;
|
||||
|
||||
writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
|
||||
return;
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
@ -1570,7 +1545,7 @@ 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,
|
||||
.fpe_configure = dwxgmac3_fpe_configure,
|
||||
.fpe_map_preemption_class = dwxgmac3_fpe_map_preemption_class,
|
||||
};
|
||||
|
||||
static void dwxlgmac2_rx_queue_enable(struct mac_device_info *hw, u8 mode,
|
||||
|
|
@ -1627,7 +1602,7 @@ 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,
|
||||
.fpe_configure = dwxgmac3_fpe_configure,
|
||||
.fpe_map_preemption_class = dwxgmac3_fpe_map_preemption_class,
|
||||
};
|
||||
|
||||
int dwxgmac2_setup(struct stmmac_priv *priv)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "common.h"
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_fpe.h"
|
||||
#include "stmmac_ptp.h"
|
||||
#include "stmmac_est.h"
|
||||
|
||||
|
|
@ -185,6 +186,7 @@ static const struct stmmac_hwif_entry {
|
|||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
.fpe_reg = &dwmac5_fpe_reg,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac4_dma_ops,
|
||||
|
|
@ -205,6 +207,7 @@ static const struct stmmac_hwif_entry {
|
|||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
.fpe_reg = &dwmac5_fpe_reg,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac410_dma_ops,
|
||||
|
|
@ -225,6 +228,7 @@ static const struct stmmac_hwif_entry {
|
|||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
.fpe_reg = &dwmac5_fpe_reg,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac410_dma_ops,
|
||||
|
|
@ -246,6 +250,7 @@ static const struct stmmac_hwif_entry {
|
|||
.ptp_off = PTP_XGMAC_OFFSET,
|
||||
.mmc_off = MMC_XGMAC_OFFSET,
|
||||
.est_off = EST_XGMAC_OFFSET,
|
||||
.fpe_reg = &dwxgmac3_fpe_reg,
|
||||
},
|
||||
.desc = &dwxgmac210_desc_ops,
|
||||
.dma = &dwxgmac210_dma_ops,
|
||||
|
|
@ -267,6 +272,7 @@ static const struct stmmac_hwif_entry {
|
|||
.ptp_off = PTP_XGMAC_OFFSET,
|
||||
.mmc_off = MMC_XGMAC_OFFSET,
|
||||
.est_off = EST_XGMAC_OFFSET,
|
||||
.fpe_reg = &dwxgmac3_fpe_reg,
|
||||
},
|
||||
.desc = &dwxgmac210_desc_ops,
|
||||
.dma = &dwxgmac210_dma_ops,
|
||||
|
|
@ -353,6 +359,7 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
|
|||
mac->est = mac->est ? : entry->est;
|
||||
|
||||
priv->hw = mac;
|
||||
priv->fpe_cfg.reg = entry->regs.fpe_reg;
|
||||
priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
|
||||
priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
|
||||
if (entry->est)
|
||||
|
|
|
|||
|
|
@ -420,15 +420,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);
|
||||
void (*fpe_configure)(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
u32 num_txq, u32 num_rxq,
|
||||
bool tx_enable, bool pmac_enable);
|
||||
void (*fpe_send_mpacket)(void __iomem *ioaddr,
|
||||
struct stmmac_fpe_cfg *cfg,
|
||||
enum stmmac_mpacket_type type);
|
||||
int (*fpe_irq_status)(void __iomem *ioaddr, struct net_device *dev);
|
||||
int (*fpe_get_add_frag_size)(const void __iomem *ioaddr);
|
||||
void (*fpe_set_add_frag_size)(void __iomem *ioaddr, u32 add_frag_size);
|
||||
int (*fpe_map_preemption_class)(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack,
|
||||
u32 pclass);
|
||||
|
|
@ -530,16 +521,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_fpe_configure(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_configure, __args)
|
||||
#define stmmac_fpe_send_mpacket(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_send_mpacket, __args)
|
||||
#define stmmac_fpe_irq_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, fpe_irq_status, __args)
|
||||
#define stmmac_fpe_get_add_frag_size(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, fpe_get_add_frag_size, __args)
|
||||
#define stmmac_fpe_set_add_frag_size(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_set_add_frag_size, __args)
|
||||
#define stmmac_fpe_map_preemption_class(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_map_preemption_class, __args)
|
||||
|
||||
|
|
@ -678,6 +659,7 @@ struct stmmac_est_ops {
|
|||
stmmac_do_void_callback(__priv, est, irq_status, __args)
|
||||
|
||||
struct stmmac_regs_off {
|
||||
const struct stmmac_fpe_reg *fpe_reg;
|
||||
u32 ptp_off;
|
||||
u32 mmc_off;
|
||||
u32 est_off;
|
||||
|
|
|
|||
|
|
@ -146,21 +146,13 @@ struct stmmac_channel {
|
|||
u32 index;
|
||||
};
|
||||
|
||||
/* FPE link-partner hand-shaking mPacket type */
|
||||
enum stmmac_mpacket_type {
|
||||
MPACKET_VERIFY = 0,
|
||||
MPACKET_RESPONSE = 1,
|
||||
};
|
||||
|
||||
#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES 3
|
||||
#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS 128
|
||||
|
||||
struct stmmac_fpe_cfg {
|
||||
/* Serialize access to MAC Merge state between ethtool requests
|
||||
* and link state updates.
|
||||
*/
|
||||
spinlock_t lock;
|
||||
|
||||
const struct stmmac_fpe_reg *reg;
|
||||
u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */
|
||||
|
||||
enum ethtool_mm_verify_status status;
|
||||
|
|
@ -420,7 +412,6 @@ bool stmmac_eee_init(struct stmmac_priv *priv);
|
|||
int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
|
||||
int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size);
|
||||
int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled);
|
||||
void stmmac_fpe_apply(struct stmmac_priv *priv);
|
||||
|
||||
static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
#include <linux/net_tstamp.h>
|
||||
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_fpe.h"
|
||||
#include "dwmac_dma.h"
|
||||
#include "dwxgmac2.h"
|
||||
#include "dwmac5.h"
|
||||
|
||||
#define REG_SPACE_SIZE 0x1060
|
||||
#define GMAC4_REG_SPACE_SIZE 0x116C
|
||||
|
|
@ -1271,7 +1271,7 @@ static int stmmac_get_mm(struct net_device *ndev,
|
|||
unsigned long flags;
|
||||
u32 frag_size;
|
||||
|
||||
if (!priv->dma_cap.fpesel)
|
||||
if (!stmmac_fpe_supported(priv))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
|
||||
|
|
@ -1294,7 +1294,7 @@ static int stmmac_get_mm(struct net_device *ndev,
|
|||
else
|
||||
state->tx_active = false;
|
||||
|
||||
frag_size = stmmac_fpe_get_add_frag_size(priv, priv->ioaddr);
|
||||
frag_size = stmmac_fpe_get_add_frag_size(priv);
|
||||
state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(frag_size);
|
||||
|
||||
spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
|
||||
|
|
@ -1329,7 +1329,7 @@ static int stmmac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,
|
|||
if (!cfg->verify_enabled)
|
||||
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
|
||||
|
||||
stmmac_fpe_set_add_frag_size(priv, priv->ioaddr, frag_size);
|
||||
stmmac_fpe_set_add_frag_size(priv, frag_size);
|
||||
stmmac_fpe_apply(priv);
|
||||
|
||||
spin_unlock_irqrestore(&fpe_cfg->lock, flags);
|
||||
|
|
|
|||
413
drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
Normal file
413
drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
Normal file
|
|
@ -0,0 +1,413 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2024 Furong Xu <0x1207@gmail.com>
|
||||
* stmmac FPE(802.3 Qbu) handling
|
||||
*/
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_fpe.h"
|
||||
#include "dwmac4.h"
|
||||
#include "dwmac5.h"
|
||||
#include "dwxgmac2.h"
|
||||
|
||||
#define GMAC5_MAC_FPE_CTRL_STS 0x00000234
|
||||
#define XGMAC_MAC_FPE_CTRL_STS 0x00000280
|
||||
|
||||
#define GMAC5_MTL_FPE_CTRL_STS 0x00000c90
|
||||
#define XGMAC_MTL_FPE_CTRL_STS 0x00001090
|
||||
/* Preemption Classification */
|
||||
#define FPE_MTL_PREEMPTION_CLASS GENMASK(15, 8)
|
||||
/* Additional Fragment Size of preempted frames */
|
||||
#define FPE_MTL_ADD_FRAG_SZ GENMASK(1, 0)
|
||||
|
||||
#define STMMAC_MAC_FPE_CTRL_STS_TRSP BIT(19)
|
||||
#define STMMAC_MAC_FPE_CTRL_STS_TVER BIT(18)
|
||||
#define STMMAC_MAC_FPE_CTRL_STS_RRSP BIT(17)
|
||||
#define STMMAC_MAC_FPE_CTRL_STS_RVER BIT(16)
|
||||
#define STMMAC_MAC_FPE_CTRL_STS_SRSP BIT(2)
|
||||
#define STMMAC_MAC_FPE_CTRL_STS_SVER BIT(1)
|
||||
#define STMMAC_MAC_FPE_CTRL_STS_EFPE BIT(0)
|
||||
|
||||
/* FPE link-partner hand-shaking mPacket type */
|
||||
enum stmmac_mpacket_type {
|
||||
MPACKET_VERIFY = 0,
|
||||
MPACKET_RESPONSE = 1,
|
||||
};
|
||||
|
||||
struct stmmac_fpe_reg {
|
||||
const u32 mac_fpe_reg; /* offset of MAC_FPE_CTRL_STS */
|
||||
const u32 mtl_fpe_reg; /* offset of MTL_FPE_CTRL_STS */
|
||||
const u32 rxq_ctrl1_reg; /* offset of MAC_RxQ_Ctrl1 */
|
||||
const u32 fprq_mask; /* Frame Preemption Residue Queue */
|
||||
const u32 int_en_reg; /* offset of MAC_Interrupt_Enable */
|
||||
const u32 int_en_bit; /* Frame Preemption Interrupt Enable */
|
||||
};
|
||||
|
||||
bool stmmac_fpe_supported(struct stmmac_priv *priv)
|
||||
{
|
||||
return priv->dma_cap.fpesel && priv->fpe_cfg.reg &&
|
||||
priv->hw->mac->fpe_map_preemption_class;
|
||||
}
|
||||
|
||||
static void stmmac_fpe_configure(struct stmmac_priv *priv, bool tx_enable,
|
||||
bool pmac_enable)
|
||||
{
|
||||
struct stmmac_fpe_cfg *cfg = &priv->fpe_cfg;
|
||||
const struct stmmac_fpe_reg *reg = cfg->reg;
|
||||
u32 num_rxq = priv->plat->rx_queues_to_use;
|
||||
void __iomem *ioaddr = priv->ioaddr;
|
||||
u32 value;
|
||||
|
||||
if (tx_enable) {
|
||||
cfg->fpe_csr = STMMAC_MAC_FPE_CTRL_STS_EFPE;
|
||||
value = readl(ioaddr + reg->rxq_ctrl1_reg);
|
||||
value &= ~reg->fprq_mask;
|
||||
/* Keep this SHIFT, FIELD_PREP() expects a constant mask :-/ */
|
||||
value |= (num_rxq - 1) << __ffs(reg->fprq_mask);
|
||||
writel(value, ioaddr + reg->rxq_ctrl1_reg);
|
||||
} else {
|
||||
cfg->fpe_csr = 0;
|
||||
}
|
||||
writel(cfg->fpe_csr, ioaddr + reg->mac_fpe_reg);
|
||||
|
||||
value = readl(ioaddr + reg->int_en_reg);
|
||||
|
||||
if (pmac_enable) {
|
||||
if (!(value & reg->int_en_bit)) {
|
||||
/* Dummy read to clear any pending masked interrupts */
|
||||
readl(ioaddr + reg->mac_fpe_reg);
|
||||
|
||||
value |= reg->int_en_bit;
|
||||
}
|
||||
} else {
|
||||
value &= ~reg->int_en_bit;
|
||||
}
|
||||
|
||||
writel(value, ioaddr + reg->int_en_reg);
|
||||
}
|
||||
|
||||
static void stmmac_fpe_send_mpacket(struct stmmac_priv *priv,
|
||||
enum stmmac_mpacket_type type)
|
||||
{
|
||||
const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg;
|
||||
void __iomem *ioaddr = priv->ioaddr;
|
||||
u32 value = priv->fpe_cfg.fpe_csr;
|
||||
|
||||
if (type == MPACKET_VERIFY)
|
||||
value |= STMMAC_MAC_FPE_CTRL_STS_SVER;
|
||||
else if (type == MPACKET_RESPONSE)
|
||||
value |= STMMAC_MAC_FPE_CTRL_STS_SRSP;
|
||||
|
||||
writel(value, ioaddr + reg->mac_fpe_reg);
|
||||
}
|
||||
|
||||
static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status)
|
||||
{
|
||||
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
|
||||
|
||||
/* This is interrupt context, just spin_lock() */
|
||||
spin_lock(&fpe_cfg->lock);
|
||||
|
||||
if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN)
|
||||
goto unlock_out;
|
||||
|
||||
/* LP has sent verify mPacket */
|
||||
if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER)
|
||||
stmmac_fpe_send_mpacket(priv, MPACKET_RESPONSE);
|
||||
|
||||
/* Local has sent verify mPacket */
|
||||
if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER &&
|
||||
fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED)
|
||||
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING;
|
||||
|
||||
/* LP has sent response mPacket */
|
||||
if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP &&
|
||||
fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING)
|
||||
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
|
||||
|
||||
unlock_out:
|
||||
spin_unlock(&fpe_cfg->lock);
|
||||
}
|
||||
|
||||
void stmmac_fpe_irq_status(struct stmmac_priv *priv)
|
||||
{
|
||||
const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg;
|
||||
void __iomem *ioaddr = priv->ioaddr;
|
||||
struct net_device *dev = priv->dev;
|
||||
int status = FPE_EVENT_UNKNOWN;
|
||||
u32 value;
|
||||
|
||||
/* Reads from the MAC_FPE_CTRL_STS register should only be performed
|
||||
* here, since the status flags of MAC_FPE_CTRL_STS are "clear on read"
|
||||
*/
|
||||
value = readl(ioaddr + reg->mac_fpe_reg);
|
||||
|
||||
if (value & STMMAC_MAC_FPE_CTRL_STS_TRSP) {
|
||||
status |= FPE_EVENT_TRSP;
|
||||
netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n");
|
||||
}
|
||||
|
||||
if (value & STMMAC_MAC_FPE_CTRL_STS_TVER) {
|
||||
status |= FPE_EVENT_TVER;
|
||||
netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n");
|
||||
}
|
||||
|
||||
if (value & STMMAC_MAC_FPE_CTRL_STS_RRSP) {
|
||||
status |= FPE_EVENT_RRSP;
|
||||
netdev_dbg(dev, "FPE: Respond mPacket is received\n");
|
||||
}
|
||||
|
||||
if (value & STMMAC_MAC_FPE_CTRL_STS_RVER) {
|
||||
status |= FPE_EVENT_RVER;
|
||||
netdev_dbg(dev, "FPE: Verify mPacket is received\n");
|
||||
}
|
||||
|
||||
stmmac_fpe_event_status(priv, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_fpe_verify_timer - Timer for MAC Merge verification
|
||||
* @t: timer_list struct containing private info
|
||||
*
|
||||
* Verify the MAC Merge capability in the local TX direction, by
|
||||
* transmitting Verify mPackets up to 3 times. Wait until link
|
||||
* partner responds with a Response mPacket, otherwise fail.
|
||||
*/
|
||||
static void stmmac_fpe_verify_timer(struct timer_list *t)
|
||||
{
|
||||
struct stmmac_fpe_cfg *fpe_cfg = from_timer(fpe_cfg, t, verify_timer);
|
||||
struct stmmac_priv *priv = container_of(fpe_cfg, struct stmmac_priv,
|
||||
fpe_cfg);
|
||||
unsigned long flags;
|
||||
bool rearm = false;
|
||||
|
||||
spin_lock_irqsave(&fpe_cfg->lock, flags);
|
||||
|
||||
switch (fpe_cfg->status) {
|
||||
case ETHTOOL_MM_VERIFY_STATUS_INITIAL:
|
||||
case ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
|
||||
if (fpe_cfg->verify_retries != 0) {
|
||||
stmmac_fpe_send_mpacket(priv, MPACKET_VERIFY);
|
||||
rearm = true;
|
||||
} else {
|
||||
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
|
||||
}
|
||||
|
||||
fpe_cfg->verify_retries--;
|
||||
break;
|
||||
|
||||
case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED:
|
||||
stmmac_fpe_configure(priv, true, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (rearm) {
|
||||
mod_timer(&fpe_cfg->verify_timer,
|
||||
jiffies + msecs_to_jiffies(fpe_cfg->verify_time));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&fpe_cfg->lock, flags);
|
||||
}
|
||||
|
||||
static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg)
|
||||
{
|
||||
if (fpe_cfg->pmac_enabled && fpe_cfg->tx_enabled &&
|
||||
fpe_cfg->verify_enabled &&
|
||||
fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_FAILED &&
|
||||
fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) {
|
||||
timer_setup(&fpe_cfg->verify_timer, stmmac_fpe_verify_timer, 0);
|
||||
mod_timer(&fpe_cfg->verify_timer, jiffies);
|
||||
}
|
||||
}
|
||||
|
||||
void stmmac_fpe_init(struct stmmac_priv *priv)
|
||||
{
|
||||
priv->fpe_cfg.verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
|
||||
priv->fpe_cfg.verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS;
|
||||
priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
|
||||
timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0);
|
||||
spin_lock_init(&priv->fpe_cfg.lock);
|
||||
|
||||
if ((!priv->fpe_cfg.reg || !priv->hw->mac->fpe_map_preemption_class) &&
|
||||
priv->dma_cap.fpesel)
|
||||
dev_info(priv->device, "FPE is not supported by driver.\n");
|
||||
}
|
||||
|
||||
void stmmac_fpe_apply(struct stmmac_priv *priv)
|
||||
{
|
||||
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
|
||||
|
||||
/* If verification is disabled, configure FPE right away.
|
||||
* Otherwise let the timer code do it.
|
||||
*/
|
||||
if (!fpe_cfg->verify_enabled) {
|
||||
stmmac_fpe_configure(priv, fpe_cfg->tx_enabled,
|
||||
fpe_cfg->pmac_enabled);
|
||||
} else {
|
||||
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL;
|
||||
fpe_cfg->verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
|
||||
|
||||
if (netif_running(priv->dev))
|
||||
stmmac_fpe_verify_timer_arm(fpe_cfg);
|
||||
}
|
||||
}
|
||||
|
||||
void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
|
||||
{
|
||||
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
|
||||
unsigned long flags;
|
||||
|
||||
timer_shutdown_sync(&fpe_cfg->verify_timer);
|
||||
|
||||
spin_lock_irqsave(&fpe_cfg->lock, flags);
|
||||
|
||||
if (is_up && fpe_cfg->pmac_enabled) {
|
||||
/* VERIFY process requires pmac enabled when NIC comes up */
|
||||
stmmac_fpe_configure(priv, false, true);
|
||||
|
||||
/* New link => maybe new partner => new verification process */
|
||||
stmmac_fpe_apply(priv);
|
||||
} else {
|
||||
/* No link => turn off EFPE */
|
||||
stmmac_fpe_configure(priv, false, false);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&fpe_cfg->lock, flags);
|
||||
}
|
||||
|
||||
int stmmac_fpe_get_add_frag_size(struct stmmac_priv *priv)
|
||||
{
|
||||
const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg;
|
||||
void __iomem *ioaddr = priv->ioaddr;
|
||||
|
||||
return FIELD_GET(FPE_MTL_ADD_FRAG_SZ, readl(ioaddr + reg->mtl_fpe_reg));
|
||||
}
|
||||
|
||||
void stmmac_fpe_set_add_frag_size(struct stmmac_priv *priv, u32 add_frag_size)
|
||||
{
|
||||
const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg;
|
||||
void __iomem *ioaddr = priv->ioaddr;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + reg->mtl_fpe_reg);
|
||||
writel(u32_replace_bits(value, add_frag_size, FPE_MTL_ADD_FRAG_SZ),
|
||||
ioaddr + reg->mtl_fpe_reg);
|
||||
}
|
||||
|
||||
#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping"
|
||||
#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]"
|
||||
|
||||
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack, u32 pclass)
|
||||
{
|
||||
u32 val, offset, count, queue_weight, preemptible_txqs = 0;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
int num_tc = netdev_get_num_tc(ndev);
|
||||
|
||||
if (!pclass)
|
||||
goto update_mapping;
|
||||
|
||||
/* DWMAC CORE4+ can not program TC:TXQ mapping to hardware.
|
||||
*
|
||||
* Synopsys Databook:
|
||||
* "The number of Tx DMA channels is equal to the number of Tx queues,
|
||||
* and is direct one-to-one mapping."
|
||||
*/
|
||||
for (u32 tc = 0; tc < num_tc; tc++) {
|
||||
count = ndev->tc_to_txq[tc].count;
|
||||
offset = ndev->tc_to_txq[tc].offset;
|
||||
|
||||
if (pclass & BIT(tc))
|
||||
preemptible_txqs |= GENMASK(offset + count - 1, offset);
|
||||
|
||||
/* This is 1:1 mapping, go to next TC */
|
||||
if (count == 1)
|
||||
continue;
|
||||
|
||||
if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) {
|
||||
NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
queue_weight = priv->plat->tx_queues_cfg[offset].weight;
|
||||
|
||||
for (u32 i = 1; i < count; i++) {
|
||||
if (priv->plat->tx_queues_cfg[offset + i].weight !=
|
||||
queue_weight) {
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG,
|
||||
queue_weight, tc);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_mapping:
|
||||
val = readl(priv->ioaddr + GMAC5_MTL_FPE_CTRL_STS);
|
||||
writel(u32_replace_bits(val, preemptible_txqs, FPE_MTL_PREEMPTION_CLASS),
|
||||
priv->ioaddr + GMAC5_MTL_FPE_CTRL_STS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dwxgmac3_fpe_map_preemption_class(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack, u32 pclass)
|
||||
{
|
||||
u32 val, offset, count, preemptible_txqs = 0;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
int num_tc = netdev_get_num_tc(ndev);
|
||||
|
||||
if (!num_tc) {
|
||||
/* Restore default TC:Queue mapping */
|
||||
for (u32 i = 0; i < priv->plat->tx_queues_to_use; i++) {
|
||||
val = readl(priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(i));
|
||||
writel(u32_replace_bits(val, i, XGMAC_Q2TCMAP),
|
||||
priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(i));
|
||||
}
|
||||
}
|
||||
|
||||
/* Synopsys Databook:
|
||||
* "All Queues within a traffic class are selected in a round robin
|
||||
* fashion (when packets are available) when the traffic class is
|
||||
* selected by the scheduler for packet transmission. This is true for
|
||||
* any of the scheduling algorithms."
|
||||
*/
|
||||
for (u32 tc = 0; tc < num_tc; tc++) {
|
||||
count = ndev->tc_to_txq[tc].count;
|
||||
offset = ndev->tc_to_txq[tc].offset;
|
||||
|
||||
if (pclass & BIT(tc))
|
||||
preemptible_txqs |= GENMASK(offset + count - 1, offset);
|
||||
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
val = readl(priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(offset + i));
|
||||
writel(u32_replace_bits(val, tc, XGMAC_Q2TCMAP),
|
||||
priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(offset + i));
|
||||
}
|
||||
}
|
||||
|
||||
val = readl(priv->ioaddr + XGMAC_MTL_FPE_CTRL_STS);
|
||||
writel(u32_replace_bits(val, preemptible_txqs, FPE_MTL_PREEMPTION_CLASS),
|
||||
priv->ioaddr + XGMAC_MTL_FPE_CTRL_STS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct stmmac_fpe_reg dwmac5_fpe_reg = {
|
||||
.mac_fpe_reg = GMAC5_MAC_FPE_CTRL_STS,
|
||||
.mtl_fpe_reg = GMAC5_MTL_FPE_CTRL_STS,
|
||||
.rxq_ctrl1_reg = GMAC_RXQ_CTRL1,
|
||||
.fprq_mask = GMAC_RXQCTRL_FPRQ,
|
||||
.int_en_reg = GMAC_INT_EN,
|
||||
.int_en_bit = GMAC_INT_FPE_EN,
|
||||
};
|
||||
|
||||
const struct stmmac_fpe_reg dwxgmac3_fpe_reg = {
|
||||
.mac_fpe_reg = XGMAC_MAC_FPE_CTRL_STS,
|
||||
.mtl_fpe_reg = XGMAC_MTL_FPE_CTRL_STS,
|
||||
.rxq_ctrl1_reg = XGMAC_RXQ_CTRL1,
|
||||
.fprq_mask = XGMAC_FPRQ,
|
||||
.int_en_reg = XGMAC_INT_EN,
|
||||
.int_en_bit = XGMAC_FPEIE,
|
||||
};
|
||||
33
drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h
Normal file
33
drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2024 Furong Xu <0x1207@gmail.com>
|
||||
* stmmac FPE(802.3 Qbu) handling
|
||||
*/
|
||||
#ifndef _STMMAC_FPE_H_
|
||||
#define _STMMAC_FPE_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES 3
|
||||
#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS 128
|
||||
|
||||
struct stmmac_priv;
|
||||
|
||||
void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up);
|
||||
bool stmmac_fpe_supported(struct stmmac_priv *priv);
|
||||
void stmmac_fpe_init(struct stmmac_priv *priv);
|
||||
void stmmac_fpe_apply(struct stmmac_priv *priv);
|
||||
void stmmac_fpe_irq_status(struct stmmac_priv *priv);
|
||||
int stmmac_fpe_get_add_frag_size(struct stmmac_priv *priv);
|
||||
void stmmac_fpe_set_add_frag_size(struct stmmac_priv *priv, u32 add_frag_size);
|
||||
|
||||
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack, u32 pclass);
|
||||
int dwxgmac3_fpe_map_preemption_class(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack, u32 pclass);
|
||||
|
||||
extern const struct stmmac_fpe_reg dwmac5_fpe_reg;
|
||||
extern const struct stmmac_fpe_reg dwxgmac3_fpe_reg;
|
||||
|
||||
#endif
|
||||
|
|
@ -43,6 +43,7 @@
|
|||
#include <net/pkt_cls.h>
|
||||
#include <net/xdp_sock_drv.h>
|
||||
#include "stmmac_ptp.h"
|
||||
#include "stmmac_fpe.h"
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_xdp.h"
|
||||
#include <linux/reset.h>
|
||||
|
|
@ -966,35 +967,6 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
|
|||
/* Nothing to do, xpcs_config() handles everything */
|
||||
}
|
||||
|
||||
static void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
|
||||
{
|
||||
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
|
||||
unsigned long flags;
|
||||
|
||||
timer_shutdown_sync(&fpe_cfg->verify_timer);
|
||||
|
||||
spin_lock_irqsave(&fpe_cfg->lock, flags);
|
||||
|
||||
if (is_up && fpe_cfg->pmac_enabled) {
|
||||
/* VERIFY process requires pmac enabled when NIC comes up */
|
||||
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
|
||||
priv->plat->tx_queues_to_use,
|
||||
priv->plat->rx_queues_to_use,
|
||||
false, true);
|
||||
|
||||
/* New link => maybe new partner => new verification process */
|
||||
stmmac_fpe_apply(priv);
|
||||
} else {
|
||||
/* No link => turn off EFPE */
|
||||
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
|
||||
priv->plat->tx_queues_to_use,
|
||||
priv->plat->rx_queues_to_use,
|
||||
false, false);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&fpe_cfg->lock, flags);
|
||||
}
|
||||
|
||||
static void stmmac_mac_link_down(struct phylink_config *config,
|
||||
unsigned int mode, phy_interface_t interface)
|
||||
{
|
||||
|
|
@ -1006,7 +978,7 @@ static void stmmac_mac_link_down(struct phylink_config *config,
|
|||
priv->eee_enabled = stmmac_eee_init(priv);
|
||||
stmmac_set_eee_pls(priv, priv->hw, false);
|
||||
|
||||
if (priv->dma_cap.fpesel)
|
||||
if (stmmac_fpe_supported(priv))
|
||||
stmmac_fpe_link_state_handle(priv, false);
|
||||
}
|
||||
|
||||
|
|
@ -1120,7 +1092,7 @@ static void stmmac_mac_link_up(struct phylink_config *config,
|
|||
stmmac_set_eee_pls(priv, priv->hw, true);
|
||||
}
|
||||
|
||||
if (priv->dma_cap.fpesel)
|
||||
if (stmmac_fpe_supported(priv))
|
||||
stmmac_fpe_link_state_handle(priv, true);
|
||||
|
||||
if (priv->plat->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY)
|
||||
|
|
@ -4068,7 +4040,7 @@ static int stmmac_release(struct net_device *dev)
|
|||
|
||||
stmmac_release_ptp(priv);
|
||||
|
||||
if (priv->dma_cap.fpesel)
|
||||
if (stmmac_fpe_supported(priv))
|
||||
timer_shutdown_sync(&priv->fpe_cfg.verify_timer);
|
||||
|
||||
pm_runtime_put(priv->device);
|
||||
|
|
@ -5965,35 +5937,6 @@ static int stmmac_set_features(struct net_device *netdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status)
|
||||
{
|
||||
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
|
||||
|
||||
/* This is interrupt context, just spin_lock() */
|
||||
spin_lock(&fpe_cfg->lock);
|
||||
|
||||
if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN)
|
||||
goto unlock_out;
|
||||
|
||||
/* LP has sent verify mPacket */
|
||||
if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER)
|
||||
stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
|
||||
MPACKET_RESPONSE);
|
||||
|
||||
/* Local has sent verify mPacket */
|
||||
if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER &&
|
||||
fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED)
|
||||
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING;
|
||||
|
||||
/* LP has sent response mPacket */
|
||||
if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP &&
|
||||
fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING)
|
||||
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
|
||||
|
||||
unlock_out:
|
||||
spin_unlock(&fpe_cfg->lock);
|
||||
}
|
||||
|
||||
static void stmmac_common_interrupt(struct stmmac_priv *priv)
|
||||
{
|
||||
u32 rx_cnt = priv->plat->rx_queues_to_use;
|
||||
|
|
@ -6012,12 +5955,8 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv)
|
|||
stmmac_est_irq_status(priv, priv, priv->dev,
|
||||
&priv->xstats, tx_cnt);
|
||||
|
||||
if (priv->dma_cap.fpesel) {
|
||||
int status = stmmac_fpe_irq_status(priv, priv->ioaddr,
|
||||
priv->dev);
|
||||
|
||||
stmmac_fpe_event_status(priv, status);
|
||||
}
|
||||
if (stmmac_fpe_supported(priv))
|
||||
stmmac_fpe_irq_status(priv);
|
||||
|
||||
/* To handle GMAC own interrupts */
|
||||
if ((priv->plat->has_gmac) || xmac) {
|
||||
|
|
@ -7349,90 +7288,6 @@ int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_fpe_verify_timer - Timer for MAC Merge verification
|
||||
* @t: timer_list struct containing private info
|
||||
*
|
||||
* Verify the MAC Merge capability in the local TX direction, by
|
||||
* transmitting Verify mPackets up to 3 times. Wait until link
|
||||
* partner responds with a Response mPacket, otherwise fail.
|
||||
*/
|
||||
static void stmmac_fpe_verify_timer(struct timer_list *t)
|
||||
{
|
||||
struct stmmac_fpe_cfg *fpe_cfg = from_timer(fpe_cfg, t, verify_timer);
|
||||
struct stmmac_priv *priv = container_of(fpe_cfg, struct stmmac_priv,
|
||||
fpe_cfg);
|
||||
unsigned long flags;
|
||||
bool rearm = false;
|
||||
|
||||
spin_lock_irqsave(&fpe_cfg->lock, flags);
|
||||
|
||||
switch (fpe_cfg->status) {
|
||||
case ETHTOOL_MM_VERIFY_STATUS_INITIAL:
|
||||
case ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
|
||||
if (fpe_cfg->verify_retries != 0) {
|
||||
stmmac_fpe_send_mpacket(priv, priv->ioaddr,
|
||||
fpe_cfg, MPACKET_VERIFY);
|
||||
rearm = true;
|
||||
} else {
|
||||
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
|
||||
}
|
||||
|
||||
fpe_cfg->verify_retries--;
|
||||
break;
|
||||
|
||||
case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED:
|
||||
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
|
||||
priv->plat->tx_queues_to_use,
|
||||
priv->plat->rx_queues_to_use,
|
||||
true, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (rearm) {
|
||||
mod_timer(&fpe_cfg->verify_timer,
|
||||
jiffies + msecs_to_jiffies(fpe_cfg->verify_time));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&fpe_cfg->lock, flags);
|
||||
}
|
||||
|
||||
static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg)
|
||||
{
|
||||
if (fpe_cfg->pmac_enabled && fpe_cfg->tx_enabled &&
|
||||
fpe_cfg->verify_enabled &&
|
||||
fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_FAILED &&
|
||||
fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) {
|
||||
timer_setup(&fpe_cfg->verify_timer, stmmac_fpe_verify_timer, 0);
|
||||
mod_timer(&fpe_cfg->verify_timer, jiffies);
|
||||
}
|
||||
}
|
||||
|
||||
void stmmac_fpe_apply(struct stmmac_priv *priv)
|
||||
{
|
||||
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
|
||||
|
||||
/* If verification is disabled, configure FPE right away.
|
||||
* Otherwise let the timer code do it.
|
||||
*/
|
||||
if (!fpe_cfg->verify_enabled) {
|
||||
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
|
||||
priv->plat->tx_queues_to_use,
|
||||
priv->plat->rx_queues_to_use,
|
||||
fpe_cfg->tx_enabled,
|
||||
fpe_cfg->pmac_enabled);
|
||||
} else {
|
||||
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL;
|
||||
fpe_cfg->verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
|
||||
|
||||
if (netif_running(priv->dev))
|
||||
stmmac_fpe_verify_timer_arm(fpe_cfg);
|
||||
}
|
||||
}
|
||||
|
||||
static int stmmac_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp)
|
||||
{
|
||||
const struct stmmac_xdp_buff *ctx = (void *)_ctx;
|
||||
|
|
@ -7711,11 +7566,7 @@ int stmmac_dvr_probe(struct device *device,
|
|||
|
||||
mutex_init(&priv->lock);
|
||||
|
||||
priv->fpe_cfg.verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
|
||||
priv->fpe_cfg.verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS;
|
||||
priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
|
||||
timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0);
|
||||
spin_lock_init(&priv->fpe_cfg.lock);
|
||||
stmmac_fpe_init(priv);
|
||||
|
||||
/* If a specific clk_csr value is passed from the platform
|
||||
* this means that the CSR Clock Range selection cannot be
|
||||
|
|
@ -7890,7 +7741,7 @@ int stmmac_suspend(struct device *dev)
|
|||
}
|
||||
rtnl_unlock();
|
||||
|
||||
if (priv->dma_cap.fpesel)
|
||||
if (stmmac_fpe_supported(priv))
|
||||
timer_shutdown_sync(&priv->fpe_cfg.verify_timer);
|
||||
|
||||
priv->speed = SPEED_UNKNOWN;
|
||||
|
|
|
|||
|
|
@ -1290,8 +1290,8 @@ const struct stmmac_tc_ops dwxgmac_tc_ops = {
|
|||
.setup_cls_u32 = tc_setup_cls_u32,
|
||||
.setup_cbs = tc_setup_cbs,
|
||||
.setup_cls = tc_setup_cls,
|
||||
.setup_taprio = tc_setup_taprio_without_fpe,
|
||||
.setup_taprio = tc_setup_taprio,
|
||||
.setup_etf = tc_setup_etf,
|
||||
.query_caps = tc_query_caps,
|
||||
.setup_mqprio = tc_setup_mqprio_unimplemented,
|
||||
.setup_mqprio = tc_setup_dwmac510_mqprio,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user