mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 11:37:06 +02:00
Merge branch 'net-stmmac-fpe-via-ethtool-tc'
Furong Xu says: ==================== net: stmmac: FPE via ethtool + tc Move the Frame Preemption(FPE) over to the new standard API which uses ethtool-mm/tc-mqprio/tc-taprio. ==================== Link: https://patch.msgid.link/cover.1725631883.git.0x1207@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
cce2991e7e
|
|
@ -58,10 +58,6 @@ static void dwmac4_core_init(struct mac_device_info *hw,
|
|||
if (hw->pcs)
|
||||
value |= GMAC_PCS_IRQ_DEFAULT;
|
||||
|
||||
/* Enable FPE interrupt */
|
||||
if ((GMAC_HW_FEAT_FPESEL & readl(ioaddr + GMAC_HW_FEATURE3)) >> 26)
|
||||
value |= GMAC_INT_FPE_EN;
|
||||
|
||||
writel(value, ioaddr + GMAC_INT_EN);
|
||||
|
||||
if (GMAC_INT_DEFAULT_ENABLE & GMAC_INT_TSIE)
|
||||
|
|
@ -1268,6 +1264,9 @@ const struct stmmac_ops dwmac410_ops = {
|
|||
.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,
|
||||
.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
|
||||
|
|
@ -1320,6 +1319,9 @@ const struct stmmac_ops dwmac510_ops = {
|
|||
.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,
|
||||
.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
|
||||
|
|
|
|||
|
|
@ -575,11 +575,11 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
|
|||
|
||||
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
u32 num_txq, u32 num_rxq,
|
||||
bool enable)
|
||||
bool tx_enable, bool pmac_enable)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
if (enable) {
|
||||
if (tx_enable) {
|
||||
cfg->fpe_csr = EFPE;
|
||||
value = readl(ioaddr + GMAC_RXQ_CTRL1);
|
||||
value &= ~GMAC_RXQCTRL_FPRQ;
|
||||
|
|
@ -589,6 +589,21 @@ void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
|||
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)
|
||||
|
|
@ -605,22 +620,22 @@ int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
|
|||
|
||||
if (value & TRSP) {
|
||||
status |= FPE_EVENT_TRSP;
|
||||
netdev_info(dev, "FPE: Respond mPacket is transmitted\n");
|
||||
netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n");
|
||||
}
|
||||
|
||||
if (value & TVER) {
|
||||
status |= FPE_EVENT_TVER;
|
||||
netdev_info(dev, "FPE: Verify mPacket is transmitted\n");
|
||||
netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n");
|
||||
}
|
||||
|
||||
if (value & RRSP) {
|
||||
status |= FPE_EVENT_RRSP;
|
||||
netdev_info(dev, "FPE: Respond mPacket is received\n");
|
||||
netdev_dbg(dev, "FPE: Respond mPacket is received\n");
|
||||
}
|
||||
|
||||
if (value & RVER) {
|
||||
status |= FPE_EVENT_RVER;
|
||||
netdev_info(dev, "FPE: Verify mPacket is received\n");
|
||||
netdev_dbg(dev, "FPE: Verify mPacket is received\n");
|
||||
}
|
||||
|
||||
return status;
|
||||
|
|
@ -638,3 +653,72 @@ void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@
|
|||
#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)
|
||||
|
|
@ -104,10 +110,14 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
|
|||
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 enable);
|
||||
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__ */
|
||||
|
|
|
|||
|
|
@ -1504,13 +1504,14 @@ 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 enable)
|
||||
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 (!enable) {
|
||||
if (!tx_enable) {
|
||||
value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
|
||||
|
||||
value &= ~XGMAC_EFPE;
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ static const struct stmmac_hwif_entry {
|
|||
.mac = &dwmac4_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.tc = &dwmac4_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
|
|
@ -252,7 +252,7 @@ static const struct stmmac_hwif_entry {
|
|||
.mac = &dwxgmac210_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.tc = &dwxgmac_tc_ops,
|
||||
.mmc = &dwxgmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwxgmac2_setup,
|
||||
|
|
@ -273,7 +273,7 @@ static const struct stmmac_hwif_entry {
|
|||
.mac = &dwxlgmac2_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.tc = &dwxgmac_tc_ops,
|
||||
.mmc = &dwxgmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwxlgmac2_setup,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/stmmac.h>
|
||||
#include <net/pkt_cls.h>
|
||||
|
||||
#define stmmac_do_void_callback(__priv, __module, __cname, __arg0, __args...) \
|
||||
({ \
|
||||
|
|
@ -28,6 +29,8 @@
|
|||
struct stmmac_extra_stats;
|
||||
struct stmmac_priv;
|
||||
struct stmmac_safety_stats;
|
||||
struct stmmac_fpe_cfg;
|
||||
enum stmmac_mpacket_type;
|
||||
struct dma_desc;
|
||||
struct dma_extended_desc;
|
||||
struct dma_edesc;
|
||||
|
|
@ -419,11 +422,16 @@ struct stmmac_ops {
|
|||
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 enable);
|
||||
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);
|
||||
};
|
||||
|
||||
#define stmmac_core_init(__priv, __args...) \
|
||||
|
|
@ -528,6 +536,12 @@ struct stmmac_ops {
|
|||
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)
|
||||
|
||||
/* PTP and HW Timer helpers */
|
||||
struct stmmac_hwtimestamp {
|
||||
|
|
@ -615,6 +629,8 @@ struct stmmac_tc_ops {
|
|||
struct tc_etf_qopt_offload *qopt);
|
||||
int (*query_caps)(struct stmmac_priv *priv,
|
||||
struct tc_query_caps_base *base);
|
||||
int (*setup_mqprio)(struct stmmac_priv *priv,
|
||||
struct tc_mqprio_qopt_offload *qopt);
|
||||
};
|
||||
|
||||
#define stmmac_tc_init(__priv, __args...) \
|
||||
|
|
@ -631,6 +647,8 @@ struct stmmac_tc_ops {
|
|||
stmmac_do_callback(__priv, tc, setup_etf, __args)
|
||||
#define stmmac_tc_query_caps(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, query_caps, __args)
|
||||
#define stmmac_tc_setup_mqprio(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_mqprio, __args)
|
||||
|
||||
struct stmmac_counters;
|
||||
|
||||
|
|
@ -674,7 +692,9 @@ extern const struct stmmac_dma_ops dwmac4_dma_ops;
|
|||
extern const struct stmmac_ops dwmac410_ops;
|
||||
extern const struct stmmac_dma_ops dwmac410_dma_ops;
|
||||
extern const struct stmmac_ops dwmac510_ops;
|
||||
extern const struct stmmac_tc_ops dwmac4_tc_ops;
|
||||
extern const struct stmmac_tc_ops dwmac510_tc_ops;
|
||||
extern const struct stmmac_tc_ops dwxgmac_tc_ops;
|
||||
extern const struct stmmac_ops dwxgmac210_ops;
|
||||
extern const struct stmmac_ops dwxlgmac2_ops;
|
||||
extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
|
||||
|
|
|
|||
|
|
@ -146,6 +146,32 @@ 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;
|
||||
|
||||
u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */
|
||||
|
||||
enum ethtool_mm_verify_status status;
|
||||
struct timer_list verify_timer;
|
||||
bool verify_enabled;
|
||||
int verify_retries;
|
||||
bool pmac_enabled;
|
||||
u32 verify_time;
|
||||
bool tx_enabled;
|
||||
};
|
||||
|
||||
struct stmmac_tc_entry {
|
||||
bool in_use;
|
||||
bool in_hw;
|
||||
|
|
@ -339,11 +365,8 @@ struct stmmac_priv {
|
|||
struct workqueue_struct *wq;
|
||||
struct work_struct service_task;
|
||||
|
||||
/* Workqueue for handling FPE hand-shaking */
|
||||
unsigned long fpe_task_state;
|
||||
struct workqueue_struct *fpe_wq;
|
||||
struct work_struct fpe_task;
|
||||
char wq_name[IFNAMSIZ + 4];
|
||||
/* Frame Preemption feature (FPE) */
|
||||
struct stmmac_fpe_cfg fpe_cfg;
|
||||
|
||||
/* TC Handling */
|
||||
unsigned int tc_entries_max;
|
||||
|
|
@ -397,7 +420,7 @@ 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_handshake(struct stmmac_priv *priv, bool enable);
|
||||
void stmmac_fpe_apply(struct stmmac_priv *priv);
|
||||
|
||||
static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "stmmac.h"
|
||||
#include "dwmac_dma.h"
|
||||
#include "dwxgmac2.h"
|
||||
#include "dwmac5.h"
|
||||
|
||||
#define REG_SPACE_SIZE 0x1060
|
||||
#define GMAC4_REG_SPACE_SIZE 0x116C
|
||||
|
|
@ -1263,6 +1264,98 @@ static int stmmac_set_tunable(struct net_device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int stmmac_get_mm(struct net_device *ndev,
|
||||
struct ethtool_mm_state *state)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
unsigned long flags;
|
||||
u32 frag_size;
|
||||
|
||||
if (!priv->dma_cap.fpesel)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
|
||||
|
||||
state->max_verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS;
|
||||
state->verify_enabled = priv->fpe_cfg.verify_enabled;
|
||||
state->pmac_enabled = priv->fpe_cfg.pmac_enabled;
|
||||
state->verify_time = priv->fpe_cfg.verify_time;
|
||||
state->tx_enabled = priv->fpe_cfg.tx_enabled;
|
||||
state->verify_status = priv->fpe_cfg.status;
|
||||
state->rx_min_frag_size = ETH_ZLEN;
|
||||
|
||||
/* FPE active if common tx_enabled and
|
||||
* (verification success or disabled(forced))
|
||||
*/
|
||||
if (state->tx_enabled &&
|
||||
(state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||
|
||||
state->verify_status == ETHTOOL_MM_VERIFY_STATUS_DISABLED))
|
||||
state->tx_active = true;
|
||||
else
|
||||
state->tx_active = false;
|
||||
|
||||
frag_size = stmmac_fpe_get_add_frag_size(priv, priv->ioaddr);
|
||||
state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(frag_size);
|
||||
|
||||
spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
|
||||
unsigned long flags;
|
||||
u32 frag_size;
|
||||
int err;
|
||||
|
||||
err = ethtool_mm_frag_size_min_to_add(cfg->tx_min_frag_size,
|
||||
&frag_size, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Wait for the verification that's currently in progress to finish */
|
||||
timer_shutdown_sync(&fpe_cfg->verify_timer);
|
||||
|
||||
spin_lock_irqsave(&fpe_cfg->lock, flags);
|
||||
|
||||
fpe_cfg->verify_enabled = cfg->verify_enabled;
|
||||
fpe_cfg->pmac_enabled = cfg->pmac_enabled;
|
||||
fpe_cfg->verify_time = cfg->verify_time;
|
||||
fpe_cfg->tx_enabled = cfg->tx_enabled;
|
||||
|
||||
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_apply(priv);
|
||||
|
||||
spin_unlock_irqrestore(&fpe_cfg->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stmmac_get_mm_stats(struct net_device *ndev,
|
||||
struct ethtool_mm_stats *s)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
struct stmmac_counters *mmc = &priv->mmc;
|
||||
|
||||
if (!priv->dma_cap.rmon)
|
||||
return;
|
||||
|
||||
stmmac_mmc_read(priv, priv->mmcaddr, mmc);
|
||||
|
||||
s->MACMergeFrameAssErrorCount = mmc->mmc_rx_packet_assembly_err_cntr;
|
||||
s->MACMergeFrameAssOkCount = mmc->mmc_rx_packet_assembly_ok_cntr;
|
||||
s->MACMergeFrameSmdErrorCount = mmc->mmc_rx_packet_smd_err_cntr;
|
||||
s->MACMergeFragCountRx = mmc->mmc_rx_fpe_fragment_cntr;
|
||||
s->MACMergeFragCountTx = mmc->mmc_tx_fpe_fragment_cntr;
|
||||
s->MACMergeHoldCount = mmc->mmc_tx_hold_req_cntr;
|
||||
}
|
||||
|
||||
static const struct ethtool_ops stmmac_ethtool_ops = {
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
||||
ETHTOOL_COALESCE_MAX_FRAMES,
|
||||
|
|
@ -1301,6 +1394,9 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
|
|||
.set_tunable = stmmac_set_tunable,
|
||||
.get_link_ksettings = stmmac_ethtool_get_link_ksettings,
|
||||
.set_link_ksettings = stmmac_ethtool_set_link_ksettings,
|
||||
.get_mm = stmmac_get_mm,
|
||||
.set_mm = stmmac_set_mm,
|
||||
.get_mm_stats = stmmac_get_mm_stats,
|
||||
};
|
||||
|
||||
void stmmac_set_ethtool_ops(struct net_device *netdev)
|
||||
|
|
|
|||
|
|
@ -968,18 +968,31 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
|
|||
|
||||
static void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
|
||||
{
|
||||
struct stmmac_fpe_cfg *fpe_cfg = priv->plat->fpe_cfg;
|
||||
enum stmmac_fpe_state *lo_state = &fpe_cfg->lo_fpe_state;
|
||||
enum stmmac_fpe_state *lp_state = &fpe_cfg->lp_fpe_state;
|
||||
bool *hs_enable = &fpe_cfg->hs_enable;
|
||||
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
|
||||
unsigned long flags;
|
||||
|
||||
if (is_up && *hs_enable) {
|
||||
stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
|
||||
MPACKET_VERIFY);
|
||||
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 {
|
||||
*lo_state = FPE_STATE_OFF;
|
||||
*lp_state = FPE_STATE_OFF;
|
||||
/* 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,
|
||||
|
|
@ -3358,27 +3371,6 @@ static void stmmac_safety_feat_configuration(struct stmmac_priv *priv)
|
|||
}
|
||||
}
|
||||
|
||||
static int stmmac_fpe_start_wq(struct stmmac_priv *priv)
|
||||
{
|
||||
char *name;
|
||||
|
||||
clear_bit(__FPE_TASK_SCHED, &priv->fpe_task_state);
|
||||
clear_bit(__FPE_REMOVING, &priv->fpe_task_state);
|
||||
|
||||
name = priv->wq_name;
|
||||
sprintf(name, "%s-fpe", priv->dev->name);
|
||||
|
||||
priv->fpe_wq = create_singlethread_workqueue(name);
|
||||
if (!priv->fpe_wq) {
|
||||
netdev_err(priv->dev, "%s: Failed to create workqueue\n", name);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
netdev_info(priv->dev, "FPE workqueue start");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_hw_setup - setup mac in a usable state.
|
||||
* @dev : pointer to the device structure.
|
||||
|
|
@ -3533,13 +3525,6 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)
|
|||
|
||||
stmmac_set_hw_vlan_mode(priv, priv->hw);
|
||||
|
||||
if (priv->dma_cap.fpesel) {
|
||||
stmmac_fpe_start_wq(priv);
|
||||
|
||||
if (priv->plat->fpe_cfg->enable)
|
||||
stmmac_fpe_handshake(priv, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4036,18 +4021,6 @@ static int stmmac_open(struct net_device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void stmmac_fpe_stop_wq(struct stmmac_priv *priv)
|
||||
{
|
||||
set_bit(__FPE_REMOVING, &priv->fpe_task_state);
|
||||
|
||||
if (priv->fpe_wq) {
|
||||
destroy_workqueue(priv->fpe_wq);
|
||||
priv->fpe_wq = NULL;
|
||||
}
|
||||
|
||||
netdev_info(priv->dev, "FPE workqueue stop");
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_release - close entry point of the driver
|
||||
* @dev : device pointer.
|
||||
|
|
@ -4095,10 +4068,10 @@ static int stmmac_release(struct net_device *dev)
|
|||
|
||||
stmmac_release_ptp(priv);
|
||||
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
if (priv->dma_cap.fpesel)
|
||||
stmmac_fpe_stop_wq(priv);
|
||||
timer_shutdown_sync(&priv->fpe_cfg.verify_timer);
|
||||
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -5982,45 +5955,31 @@ static int stmmac_set_features(struct net_device *netdev,
|
|||
|
||||
static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status)
|
||||
{
|
||||
struct stmmac_fpe_cfg *fpe_cfg = priv->plat->fpe_cfg;
|
||||
enum stmmac_fpe_state *lo_state = &fpe_cfg->lo_fpe_state;
|
||||
enum stmmac_fpe_state *lp_state = &fpe_cfg->lp_fpe_state;
|
||||
bool *hs_enable = &fpe_cfg->hs_enable;
|
||||
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
|
||||
|
||||
if (status == FPE_EVENT_UNKNOWN || !*hs_enable)
|
||||
return;
|
||||
/* This is interrupt context, just spin_lock() */
|
||||
spin_lock(&fpe_cfg->lock);
|
||||
|
||||
/* If LP has sent verify mPacket, LP is FPE capable */
|
||||
if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER) {
|
||||
if (*lp_state < FPE_STATE_CAPABLE)
|
||||
*lp_state = FPE_STATE_CAPABLE;
|
||||
if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN)
|
||||
goto unlock_out;
|
||||
|
||||
/* If user has requested FPE enable, quickly response */
|
||||
if (*hs_enable)
|
||||
stmmac_fpe_send_mpacket(priv, priv->ioaddr,
|
||||
fpe_cfg,
|
||||
MPACKET_RESPONSE);
|
||||
}
|
||||
/* LP has sent verify mPacket */
|
||||
if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER)
|
||||
stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
|
||||
MPACKET_RESPONSE);
|
||||
|
||||
/* If Local has sent verify mPacket, Local is FPE capable */
|
||||
if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER) {
|
||||
if (*lo_state < FPE_STATE_CAPABLE)
|
||||
*lo_state = FPE_STATE_CAPABLE;
|
||||
}
|
||||
/* 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;
|
||||
|
||||
/* If LP has sent response mPacket, LP is entering FPE ON */
|
||||
if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP)
|
||||
*lp_state = FPE_STATE_ENTERING_ON;
|
||||
/* 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;
|
||||
|
||||
/* If Local has sent response mPacket, Local is entering FPE ON */
|
||||
if ((status & FPE_EVENT_TRSP) == FPE_EVENT_TRSP)
|
||||
*lo_state = FPE_STATE_ENTERING_ON;
|
||||
|
||||
if (!test_bit(__FPE_REMOVING, &priv->fpe_task_state) &&
|
||||
!test_and_set_bit(__FPE_TASK_SCHED, &priv->fpe_task_state) &&
|
||||
priv->fpe_wq) {
|
||||
queue_work(priv->fpe_wq, &priv->fpe_task);
|
||||
}
|
||||
unlock_out:
|
||||
spin_unlock(&fpe_cfg->lock);
|
||||
}
|
||||
|
||||
static void stmmac_common_interrupt(struct stmmac_priv *priv)
|
||||
|
|
@ -6257,6 +6216,8 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
|
|||
switch (type) {
|
||||
case TC_QUERY_CAPS:
|
||||
return stmmac_tc_query_caps(priv, priv, type_data);
|
||||
case TC_SETUP_QDISC_MQPRIO:
|
||||
return stmmac_tc_setup_mqprio(priv, priv, type_data);
|
||||
case TC_SETUP_BLOCK:
|
||||
return flow_block_cb_setup_simple(type_data,
|
||||
&stmmac_block_cb_list,
|
||||
|
|
@ -7376,68 +7337,87 @@ int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define SEND_VERIFY_MPAKCET_FMT "Send Verify mPacket lo_state=%d lp_state=%d\n"
|
||||
static void stmmac_fpe_lp_task(struct work_struct *work)
|
||||
/**
|
||||
* 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_priv *priv = container_of(work, struct stmmac_priv,
|
||||
fpe_task);
|
||||
struct stmmac_fpe_cfg *fpe_cfg = priv->plat->fpe_cfg;
|
||||
enum stmmac_fpe_state *lo_state = &fpe_cfg->lo_fpe_state;
|
||||
enum stmmac_fpe_state *lp_state = &fpe_cfg->lp_fpe_state;
|
||||
bool *hs_enable = &fpe_cfg->hs_enable;
|
||||
bool *enable = &fpe_cfg->enable;
|
||||
int retries = 20;
|
||||
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;
|
||||
|
||||
while (retries-- > 0) {
|
||||
/* Bail out immediately if FPE handshake is OFF */
|
||||
if (*lo_state == FPE_STATE_OFF || !*hs_enable)
|
||||
break;
|
||||
spin_lock_irqsave(&fpe_cfg->lock, flags);
|
||||
|
||||
if (*lo_state == FPE_STATE_ENTERING_ON &&
|
||||
*lp_state == FPE_STATE_ENTERING_ON) {
|
||||
stmmac_fpe_configure(priv, priv->ioaddr,
|
||||
fpe_cfg,
|
||||
priv->plat->tx_queues_to_use,
|
||||
priv->plat->rx_queues_to_use,
|
||||
*enable);
|
||||
|
||||
netdev_info(priv->dev, "configured FPE\n");
|
||||
|
||||
*lo_state = FPE_STATE_ON;
|
||||
*lp_state = FPE_STATE_ON;
|
||||
netdev_info(priv->dev, "!!! BOTH FPE stations ON\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if ((*lo_state == FPE_STATE_CAPABLE ||
|
||||
*lo_state == FPE_STATE_ENTERING_ON) &&
|
||||
*lp_state != FPE_STATE_ON) {
|
||||
netdev_info(priv->dev, SEND_VERIFY_MPAKCET_FMT,
|
||||
*lo_state, *lp_state);
|
||||
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);
|
||||
fpe_cfg, MPACKET_VERIFY);
|
||||
rearm = true;
|
||||
} else {
|
||||
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
|
||||
}
|
||||
/* Sleep then retry */
|
||||
msleep(500);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
clear_bit(__FPE_TASK_SCHED, &priv->fpe_task_state);
|
||||
if (rearm) {
|
||||
mod_timer(&fpe_cfg->verify_timer,
|
||||
jiffies + msecs_to_jiffies(fpe_cfg->verify_time));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&fpe_cfg->lock, flags);
|
||||
}
|
||||
|
||||
void stmmac_fpe_handshake(struct stmmac_priv *priv, bool enable)
|
||||
static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg)
|
||||
{
|
||||
if (priv->plat->fpe_cfg->hs_enable != enable) {
|
||||
if (enable) {
|
||||
stmmac_fpe_send_mpacket(priv, priv->ioaddr,
|
||||
priv->plat->fpe_cfg,
|
||||
MPACKET_VERIFY);
|
||||
} else {
|
||||
priv->plat->fpe_cfg->lo_fpe_state = FPE_STATE_OFF;
|
||||
priv->plat->fpe_cfg->lp_fpe_state = FPE_STATE_OFF;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
priv->plat->fpe_cfg->hs_enable = enable;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7555,9 +7535,6 @@ int stmmac_dvr_probe(struct device *device,
|
|||
|
||||
INIT_WORK(&priv->service_task, stmmac_service_task);
|
||||
|
||||
/* Initialize Link Partner FPE workqueue */
|
||||
INIT_WORK(&priv->fpe_task, stmmac_fpe_lp_task);
|
||||
|
||||
/* Override with kernel parameters if supplied XXX CRS XXX
|
||||
* this needs to have multiple instances
|
||||
*/
|
||||
|
|
@ -7722,6 +7699,12 @@ 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);
|
||||
|
||||
/* If a specific clk_csr value is passed from the platform
|
||||
* this means that the CSR Clock Range selection cannot be
|
||||
* changed at run-time and it is fixed. Viceversa the driver'll try to
|
||||
|
|
@ -7895,16 +7878,8 @@ int stmmac_suspend(struct device *dev)
|
|||
}
|
||||
rtnl_unlock();
|
||||
|
||||
if (priv->dma_cap.fpesel) {
|
||||
/* Disable FPE */
|
||||
stmmac_fpe_configure(priv, priv->ioaddr,
|
||||
priv->plat->fpe_cfg,
|
||||
priv->plat->tx_queues_to_use,
|
||||
priv->plat->rx_queues_to_use, false);
|
||||
|
||||
stmmac_fpe_handshake(priv, false);
|
||||
stmmac_fpe_stop_wq(priv);
|
||||
}
|
||||
if (priv->dma_cap.fpesel)
|
||||
timer_shutdown_sync(&priv->fpe_cfg.verify_timer);
|
||||
|
||||
priv->speed = SPEED_UNKNOWN;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -282,16 +282,6 @@ static int tc_init(struct stmmac_priv *priv)
|
|||
if (ret)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!priv->plat->fpe_cfg) {
|
||||
priv->plat->fpe_cfg = devm_kzalloc(priv->device,
|
||||
sizeof(*priv->plat->fpe_cfg),
|
||||
GFP_KERNEL);
|
||||
if (!priv->plat->fpe_cfg)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
memset(priv->plat->fpe_cfg, 0, sizeof(*priv->plat->fpe_cfg));
|
||||
}
|
||||
|
||||
/* Fail silently as we can still use remaining features, e.g. CBS */
|
||||
if (!dma_cap->frpsel)
|
||||
return 0;
|
||||
|
|
@ -941,9 +931,9 @@ 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 netlink_ext_ack *extack = qopt->mqprio.extack;
|
||||
struct timespec64 time, current_time, qopt_time;
|
||||
ktime_t current_time_ns;
|
||||
bool fpe = false;
|
||||
int i, ret = 0;
|
||||
u64 ctr;
|
||||
|
||||
|
|
@ -1028,16 +1018,12 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
|
|||
|
||||
switch (qopt->entries[i].command) {
|
||||
case TC_TAPRIO_CMD_SET_GATES:
|
||||
if (fpe)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case TC_TAPRIO_CMD_SET_AND_HOLD:
|
||||
gates |= BIT(0);
|
||||
fpe = true;
|
||||
break;
|
||||
case TC_TAPRIO_CMD_SET_AND_RELEASE:
|
||||
gates &= ~BIT(0);
|
||||
fpe = true;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -1068,16 +1054,6 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
|
|||
|
||||
tc_taprio_map_maxsdu_txq(priv, qopt);
|
||||
|
||||
if (fpe && !priv->dma_cap.fpesel) {
|
||||
mutex_unlock(&priv->est_lock);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Actual FPE register configuration will be done after FPE handshake
|
||||
* is success.
|
||||
*/
|
||||
priv->plat->fpe_cfg->enable = fpe;
|
||||
|
||||
ret = stmmac_est_configure(priv, priv, priv->est,
|
||||
priv->plat->clk_ptp_rate);
|
||||
mutex_unlock(&priv->est_lock);
|
||||
|
|
@ -1086,12 +1062,10 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
|
|||
goto disable;
|
||||
}
|
||||
|
||||
netdev_info(priv->dev, "configured EST\n");
|
||||
|
||||
if (fpe) {
|
||||
stmmac_fpe_handshake(priv, true);
|
||||
netdev_info(priv->dev, "start FPE handshake\n");
|
||||
}
|
||||
ret = stmmac_fpe_map_preemption_class(priv, priv->dev, extack,
|
||||
qopt->mqprio.preemptible_tcs);
|
||||
if (ret)
|
||||
goto disable;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -1109,16 +1083,7 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
|
|||
mutex_unlock(&priv->est_lock);
|
||||
}
|
||||
|
||||
priv->plat->fpe_cfg->enable = false;
|
||||
stmmac_fpe_configure(priv, priv->ioaddr,
|
||||
priv->plat->fpe_cfg,
|
||||
priv->plat->tx_queues_to_use,
|
||||
priv->plat->rx_queues_to_use,
|
||||
false);
|
||||
netdev_info(priv->dev, "disabled FPE\n");
|
||||
|
||||
stmmac_fpe_handshake(priv, false);
|
||||
netdev_info(priv->dev, "stop FPE handshake\n");
|
||||
stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1174,6 +1139,18 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int tc_setup_taprio_without_fpe(struct stmmac_priv *priv,
|
||||
struct tc_taprio_qopt_offload *qopt)
|
||||
{
|
||||
if (!qopt->mqprio.preemptible_tcs)
|
||||
return tc_setup_taprio(priv, qopt);
|
||||
|
||||
NL_SET_ERR_MSG_MOD(qopt->mqprio.extack,
|
||||
"taprio with FPE is not implemented for this MAC");
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int tc_setup_etf(struct stmmac_priv *priv,
|
||||
struct tc_etf_qopt_offload *qopt)
|
||||
{
|
||||
|
|
@ -1198,6 +1175,13 @@ static int tc_query_caps(struct stmmac_priv *priv,
|
|||
struct tc_query_caps_base *base)
|
||||
{
|
||||
switch (base->type) {
|
||||
case TC_SETUP_QDISC_MQPRIO: {
|
||||
struct tc_mqprio_caps *caps = base->caps;
|
||||
|
||||
caps->validate_queue_counts = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case TC_SETUP_QDISC_TAPRIO: {
|
||||
struct tc_taprio_caps *caps = base->caps;
|
||||
|
||||
|
|
@ -1214,6 +1198,81 @@ static int tc_query_caps(struct stmmac_priv *priv,
|
|||
}
|
||||
}
|
||||
|
||||
static void stmmac_reset_tc_mqprio(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
|
||||
netdev_reset_tc(ndev);
|
||||
netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use);
|
||||
stmmac_fpe_map_preemption_class(priv, ndev, extack, 0);
|
||||
}
|
||||
|
||||
static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
|
||||
struct tc_mqprio_qopt_offload *mqprio)
|
||||
{
|
||||
struct netlink_ext_ack *extack = mqprio->extack;
|
||||
struct tc_mqprio_qopt *qopt = &mqprio->qopt;
|
||||
u32 offset, count, num_stack_tx_queues = 0;
|
||||
struct net_device *ndev = priv->dev;
|
||||
u32 num_tc = qopt->num_tc;
|
||||
int err;
|
||||
|
||||
if (!num_tc) {
|
||||
stmmac_reset_tc_mqprio(ndev, extack);
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = netdev_set_num_tc(ndev, num_tc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (u32 tc = 0; tc < num_tc; tc++) {
|
||||
offset = qopt->offset[tc];
|
||||
count = qopt->count[tc];
|
||||
num_stack_tx_queues += count;
|
||||
|
||||
err = netdev_set_tc_queue(ndev, tc, count, offset);
|
||||
if (err)
|
||||
goto err_reset_tc;
|
||||
}
|
||||
|
||||
err = netif_set_real_num_tx_queues(ndev, num_stack_tx_queues);
|
||||
if (err)
|
||||
goto err_reset_tc;
|
||||
|
||||
err = stmmac_fpe_map_preemption_class(priv, ndev, extack,
|
||||
mqprio->preemptible_tcs);
|
||||
if (err)
|
||||
goto err_reset_tc;
|
||||
|
||||
return 0;
|
||||
|
||||
err_reset_tc:
|
||||
stmmac_reset_tc_mqprio(ndev, extack);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tc_setup_mqprio_unimplemented(struct stmmac_priv *priv,
|
||||
struct tc_mqprio_qopt_offload *mqprio)
|
||||
{
|
||||
NL_SET_ERR_MSG_MOD(mqprio->extack,
|
||||
"mqprio HW offload is not implemented for this MAC");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
const struct stmmac_tc_ops dwmac4_tc_ops = {
|
||||
.init = tc_init,
|
||||
.setup_cls_u32 = tc_setup_cls_u32,
|
||||
.setup_cbs = tc_setup_cbs,
|
||||
.setup_cls = tc_setup_cls,
|
||||
.setup_taprio = tc_setup_taprio_without_fpe,
|
||||
.setup_etf = tc_setup_etf,
|
||||
.query_caps = tc_query_caps,
|
||||
.setup_mqprio = tc_setup_mqprio_unimplemented,
|
||||
};
|
||||
|
||||
const struct stmmac_tc_ops dwmac510_tc_ops = {
|
||||
.init = tc_init,
|
||||
.setup_cls_u32 = tc_setup_cls_u32,
|
||||
|
|
@ -1222,4 +1281,16 @@ const struct stmmac_tc_ops dwmac510_tc_ops = {
|
|||
.setup_taprio = tc_setup_taprio,
|
||||
.setup_etf = tc_setup_etf,
|
||||
.query_caps = tc_query_caps,
|
||||
.setup_mqprio = tc_setup_dwmac510_mqprio,
|
||||
};
|
||||
|
||||
const struct stmmac_tc_ops dwxgmac_tc_ops = {
|
||||
.init = tc_init,
|
||||
.setup_cls_u32 = tc_setup_cls_u32,
|
||||
.setup_cbs = tc_setup_cbs,
|
||||
.setup_cls = tc_setup_cls,
|
||||
.setup_taprio = tc_setup_taprio_without_fpe,
|
||||
.setup_etf = tc_setup_etf,
|
||||
.query_caps = tc_query_caps,
|
||||
.setup_mqprio = tc_setup_mqprio_unimplemented,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -138,33 +138,6 @@ struct stmmac_txq_cfg {
|
|||
int tbs_en;
|
||||
};
|
||||
|
||||
/* FPE link state */
|
||||
enum stmmac_fpe_state {
|
||||
FPE_STATE_OFF = 0,
|
||||
FPE_STATE_CAPABLE = 1,
|
||||
FPE_STATE_ENTERING_ON = 2,
|
||||
FPE_STATE_ON = 3,
|
||||
};
|
||||
|
||||
/* FPE link-partner hand-shaking mPacket type */
|
||||
enum stmmac_mpacket_type {
|
||||
MPACKET_VERIFY = 0,
|
||||
MPACKET_RESPONSE = 1,
|
||||
};
|
||||
|
||||
enum stmmac_fpe_task_state_t {
|
||||
__FPE_REMOVING,
|
||||
__FPE_TASK_SCHED,
|
||||
};
|
||||
|
||||
struct stmmac_fpe_cfg {
|
||||
bool enable; /* FPE enable */
|
||||
bool hs_enable; /* FPE handshake enable */
|
||||
enum stmmac_fpe_state lp_fpe_state; /* Link Partner FPE state */
|
||||
enum stmmac_fpe_state lo_fpe_state; /* Local station FPE state */
|
||||
u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */
|
||||
};
|
||||
|
||||
struct stmmac_safety_feature_cfg {
|
||||
u32 tsoee;
|
||||
u32 mrxpee;
|
||||
|
|
@ -232,7 +205,6 @@ struct plat_stmmacenet_data {
|
|||
struct fwnode_handle *port_node;
|
||||
struct device_node *mdio_node;
|
||||
struct stmmac_dma_cfg *dma_cfg;
|
||||
struct stmmac_fpe_cfg *fpe_cfg;
|
||||
struct stmmac_safety_feature_cfg *safety_feat_cfg;
|
||||
int clk_csr;
|
||||
int has_gmac;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user