* [PATCH net-next v4 0/7] net: stmmac: FPE via ethtool + tc
@ 2024-08-20 9:38 Furong Xu
2024-08-20 9:38 ` [PATCH net-next v4 1/7] net: stmmac: move stmmac_fpe_cfg to stmmac_priv data Furong Xu
` (6 more replies)
0 siblings, 7 replies; 18+ messages in thread
From: Furong Xu @ 2024-08-20 9:38 UTC (permalink / raw)
To: Serge Semin, Andrew Lunn, Vladimir Oltean, David S. Miller,
Alexandre Torgue, Jose Abreu, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Joao Pinto
Cc: netdev, linux-stm32, linux-arm-kernel, linux-kernel, xfr,
Furong Xu
Move the Frame Preemption(FPE) over to the new standard API which uses
ethtool-mm/tc-mqprio/tc-taprio.
Changes in v4:
1. reorder FPE-related declarations and definitions into clean groups
2. move mm_lock to stmmac_fpe_cfg.lock
3. protect user configurations across NIC up/down
4. block stmmac_set_mm() when fpe_task is in progress to finish
5. convert to ethtool_dev_mm_supported() to check FPE capability in
tc-mqprio/tc-taprio
6. silence FPE workqueue start/stop logs
Changes in v3:
1. avoid races among ISR, workqueue, link update and
register configuration.
2. update FPE verification retry logic, so it retries
and fails as expected.
Changes in v2:
1. refactor FPE verification processe
2. suspend/resume and kselftest-ethtool_mm, all test cases passed
3. handle TC:TXQ remapping for DWMAC CORE4+
Furong Xu (7):
net: stmmac: move stmmac_fpe_cfg to stmmac_priv data
net: stmmac: drop stmmac_fpe_handshake
net: stmmac: refactor FPE verification process
net: stmmac: configure FPE via ethtool-mm
net: stmmac: support fp parameter of tc-mqprio
net: stmmac: support fp parameter of tc-taprio
net: stmmac: silence FPE kernel logs
.../net/ethernet/stmicro/stmmac/dwmac4_core.c | 10 +-
drivers/net/ethernet/stmicro/stmmac/dwmac5.c | 96 +++++++-
drivers/net/ethernet/stmicro/stmmac/dwmac5.h | 11 +-
.../ethernet/stmicro/stmmac/dwxgmac2_core.c | 4 +-
drivers/net/ethernet/stmicro/stmmac/hwif.h | 20 +-
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 27 ++-
.../ethernet/stmicro/stmmac/stmmac_ethtool.c | 110 +++++++++
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 214 +++++++++---------
.../net/ethernet/stmicro/stmmac/stmmac_tc.c | 124 +++++++---
include/linux/stmmac.h | 28 ---
10 files changed, 463 insertions(+), 181 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH net-next v4 1/7] net: stmmac: move stmmac_fpe_cfg to stmmac_priv data
2024-08-20 9:38 [PATCH net-next v4 0/7] net: stmmac: FPE via ethtool + tc Furong Xu
@ 2024-08-20 9:38 ` Furong Xu
2024-08-20 9:55 ` Vladimir Oltean
2024-08-20 9:38 ` [PATCH net-next v4 2/7] net: stmmac: drop stmmac_fpe_handshake Furong Xu
` (5 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Furong Xu @ 2024-08-20 9:38 UTC (permalink / raw)
To: Serge Semin, Andrew Lunn, Vladimir Oltean, David S. Miller,
Alexandre Torgue, Jose Abreu, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Joao Pinto
Cc: netdev, linux-stm32, linux-arm-kernel, linux-kernel, xfr,
Furong Xu
By moving the fpe_cfg field to the stmmac_priv data, stmmac_fpe_cfg
becomes platform-data eventually, instead of a run-time config.
Suggested-by: Serge Semin <fancer.lancer@gmail.com>
Signed-off-by: Furong Xu <0x1207@gmail.com>
---
drivers/net/ethernet/stmicro/stmmac/hwif.h | 2 ++
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 30 ++++++++++++++++++-
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 20 ++++++-------
.../net/ethernet/stmicro/stmmac/stmmac_tc.c | 16 ++--------
include/linux/stmmac.h | 28 -----------------
5 files changed, 44 insertions(+), 52 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 7e90f34b8c88..d3da82982012 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -26,6 +26,8 @@
})
struct stmmac_extra_stats;
+struct stmmac_fpe_cfg;
+enum stmmac_mpacket_type;
struct stmmac_priv;
struct stmmac_safety_stats;
struct dma_desc;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index b23b920eedb1..458d6b16ce21 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -146,6 +146,33 @@ struct stmmac_channel {
u32 index;
};
+/* 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_tc_entry {
bool in_use;
bool in_hw;
@@ -339,11 +366,12 @@ struct stmmac_priv {
struct workqueue_struct *wq;
struct work_struct service_task;
- /* Workqueue for handling FPE hand-shaking */
+ /* Frame Preemption feature (FPE) */
unsigned long fpe_task_state;
struct workqueue_struct *fpe_wq;
struct work_struct fpe_task;
char wq_name[IFNAMSIZ + 4];
+ struct stmmac_fpe_cfg fpe_cfg;
/* TC Handling */
unsigned int tc_entries_max;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index d9fca8d1227c..529fe31f8b04 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -968,7 +968,7 @@ 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;
+ struct stmmac_fpe_cfg *fpe_cfg = &priv->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;
@@ -3536,7 +3536,7 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)
if (priv->dma_cap.fpesel) {
stmmac_fpe_start_wq(priv);
- if (priv->plat->fpe_cfg->enable)
+ if (priv->fpe_cfg.enable)
stmmac_fpe_handshake(priv, true);
}
@@ -5982,7 +5982,7 @@ 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;
+ struct stmmac_fpe_cfg *fpe_cfg = &priv->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;
@@ -7381,7 +7381,7 @@ static void stmmac_fpe_lp_task(struct work_struct *work)
{
struct stmmac_priv *priv = container_of(work, struct stmmac_priv,
fpe_task);
- struct stmmac_fpe_cfg *fpe_cfg = priv->plat->fpe_cfg;
+ struct stmmac_fpe_cfg *fpe_cfg = &priv->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;
@@ -7427,17 +7427,17 @@ static void stmmac_fpe_lp_task(struct work_struct *work)
void stmmac_fpe_handshake(struct stmmac_priv *priv, bool enable)
{
- if (priv->plat->fpe_cfg->hs_enable != enable) {
+ if (priv->fpe_cfg.hs_enable != enable) {
if (enable) {
stmmac_fpe_send_mpacket(priv, priv->ioaddr,
- priv->plat->fpe_cfg,
+ &priv->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;
+ priv->fpe_cfg.lo_fpe_state = FPE_STATE_OFF;
+ priv->fpe_cfg.lp_fpe_state = FPE_STATE_OFF;
}
- priv->plat->fpe_cfg->hs_enable = enable;
+ priv->fpe_cfg.hs_enable = enable;
}
}
@@ -7898,7 +7898,7 @@ int stmmac_suspend(struct device *dev)
if (priv->dma_cap.fpesel) {
/* Disable FPE */
stmmac_fpe_configure(priv, priv->ioaddr,
- priv->plat->fpe_cfg,
+ &priv->fpe_cfg,
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use, false);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 996f2bcd07a2..9cc41ed01882 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -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;
@@ -1076,7 +1066,7 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
/* Actual FPE register configuration will be done after FPE handshake
* is success.
*/
- priv->plat->fpe_cfg->enable = fpe;
+ priv->fpe_cfg.enable = fpe;
ret = stmmac_est_configure(priv, priv, priv->est,
priv->plat->clk_ptp_rate);
@@ -1109,9 +1099,9 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
mutex_unlock(&priv->est_lock);
}
- priv->plat->fpe_cfg->enable = false;
+ priv->fpe_cfg.enable = false;
stmmac_fpe_configure(priv, priv->ioaddr,
- priv->plat->fpe_cfg,
+ &priv->fpe_cfg,
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use,
false);
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 338991c08f00..d79ff252cfdc 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -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;
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v4 2/7] net: stmmac: drop stmmac_fpe_handshake
2024-08-20 9:38 [PATCH net-next v4 0/7] net: stmmac: FPE via ethtool + tc Furong Xu
2024-08-20 9:38 ` [PATCH net-next v4 1/7] net: stmmac: move stmmac_fpe_cfg to stmmac_priv data Furong Xu
@ 2024-08-20 9:38 ` Furong Xu
2024-08-20 9:56 ` Vladimir Oltean
2024-08-20 9:38 ` [PATCH net-next v4 3/7] net: stmmac: refactor FPE verification process Furong Xu
` (4 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Furong Xu @ 2024-08-20 9:38 UTC (permalink / raw)
To: Serge Semin, Andrew Lunn, Vladimir Oltean, David S. Miller,
Alexandre Torgue, Jose Abreu, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Joao Pinto
Cc: netdev, linux-stm32, linux-arm-kernel, linux-kernel, xfr,
Furong Xu
ethtool --set-mm can trigger FPE verification processe by calling
stmmac_fpe_send_mpacket, stmmac_fpe_handshake should be gone.
Signed-off-by: Furong Xu <0x1207@gmail.com>
---
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 23 +------------------
.../net/ethernet/stmicro/stmmac/stmmac_tc.c | 8 -------
2 files changed, 1 insertion(+), 30 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 529fe31f8b04..3072ad33b105 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3533,13 +3533,9 @@ 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) {
+ if (priv->dma_cap.fpesel)
stmmac_fpe_start_wq(priv);
- if (priv->fpe_cfg.enable)
- stmmac_fpe_handshake(priv, true);
- }
-
return 0;
}
@@ -7425,22 +7421,6 @@ static void stmmac_fpe_lp_task(struct work_struct *work)
clear_bit(__FPE_TASK_SCHED, &priv->fpe_task_state);
}
-void stmmac_fpe_handshake(struct stmmac_priv *priv, bool enable)
-{
- if (priv->fpe_cfg.hs_enable != enable) {
- if (enable) {
- stmmac_fpe_send_mpacket(priv, priv->ioaddr,
- &priv->fpe_cfg,
- MPACKET_VERIFY);
- } else {
- priv->fpe_cfg.lo_fpe_state = FPE_STATE_OFF;
- priv->fpe_cfg.lp_fpe_state = FPE_STATE_OFF;
- }
-
- priv->fpe_cfg.hs_enable = enable;
- }
-}
-
static int stmmac_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp)
{
const struct stmmac_xdp_buff *ctx = (void *)_ctx;
@@ -7902,7 +7882,6 @@ int stmmac_suspend(struct device *dev)
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use, false);
- stmmac_fpe_handshake(priv, false);
stmmac_fpe_stop_wq(priv);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 9cc41ed01882..b0cc45331ff7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -1078,11 +1078,6 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
netdev_info(priv->dev, "configured EST\n");
- if (fpe) {
- stmmac_fpe_handshake(priv, true);
- netdev_info(priv->dev, "start FPE handshake\n");
- }
-
return 0;
disable:
@@ -1107,9 +1102,6 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
false);
netdev_info(priv->dev, "disabled FPE\n");
- stmmac_fpe_handshake(priv, false);
- netdev_info(priv->dev, "stop FPE handshake\n");
-
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v4 3/7] net: stmmac: refactor FPE verification process
2024-08-20 9:38 [PATCH net-next v4 0/7] net: stmmac: FPE via ethtool + tc Furong Xu
2024-08-20 9:38 ` [PATCH net-next v4 1/7] net: stmmac: move stmmac_fpe_cfg to stmmac_priv data Furong Xu
2024-08-20 9:38 ` [PATCH net-next v4 2/7] net: stmmac: drop stmmac_fpe_handshake Furong Xu
@ 2024-08-20 9:38 ` Furong Xu
2024-08-20 12:34 ` Vladimir Oltean
2024-08-20 14:36 ` Alexander Lobakin
2024-08-20 9:38 ` [PATCH net-next v4 4/7] net: stmmac: configure FPE via ethtool-mm Furong Xu
` (3 subsequent siblings)
6 siblings, 2 replies; 18+ messages in thread
From: Furong Xu @ 2024-08-20 9:38 UTC (permalink / raw)
To: Serge Semin, Andrew Lunn, Vladimir Oltean, David S. Miller,
Alexandre Torgue, Jose Abreu, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Joao Pinto
Cc: netdev, linux-stm32, linux-arm-kernel, linux-kernel, xfr,
Furong Xu
Drop driver defined stmmac_fpe_state, and switch to common
ethtool_mm_verify_status for local TX verification status.
Local side and remote side verification processes are completely
independent. There is no reason at all to keep a local state and
a remote state.
Add a spinlock to avoid races among ISR, workqueue, link update
and register configuration.
Signed-off-by: Furong Xu <0x1207@gmail.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 21 +--
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 172 ++++++++++--------
.../net/ethernet/stmicro/stmmac/stmmac_tc.c | 6 -
3 files changed, 102 insertions(+), 97 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 458d6b16ce21..407b59f2783f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -146,14 +146,6 @@ struct stmmac_channel {
u32 index;
};
-/* 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,
@@ -166,11 +158,16 @@ enum stmmac_fpe_task_state_t {
};
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 */
+ /* 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 */
+ u32 verify_time; /* see ethtool_mm_state */
+ bool pmac_enabled; /* see ethtool_mm_state */
+ bool verify_enabled; /* see ethtool_mm_state */
+ enum ethtool_mm_verify_status status;
};
struct stmmac_tc_entry {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 3072ad33b105..6ae95f20b24f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -969,17 +969,21 @@ 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->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;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
+
+ if (!fpe_cfg->pmac_enabled)
+ goto __unlock_out;
- if (is_up && *hs_enable) {
+ if (is_up && fpe_cfg->verify_enabled)
stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
MPACKET_VERIFY);
- } else {
- *lo_state = FPE_STATE_OFF;
- *lp_state = FPE_STATE_OFF;
- }
+ else
+ fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
+
+__unlock_out:
+ spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
}
static void stmmac_mac_link_down(struct phylink_config *config,
@@ -4091,11 +4095,25 @@ static int stmmac_release(struct net_device *dev)
stmmac_release_ptp(priv);
- pm_runtime_put(priv->device);
-
- if (priv->dma_cap.fpesel)
+ if (priv->dma_cap.fpesel) {
stmmac_fpe_stop_wq(priv);
+ /* stmmac_ethtool_ops.begin() guarantees that all ethtool
+ * requests to fail with EBUSY when !netif_running()
+ *
+ * Prepare some params here, then fpe_cfg can keep consistent
+ * with the register states after a SW reset by __stmmac_open().
+ */
+ priv->fpe_cfg.pmac_enabled = false;
+ priv->fpe_cfg.verify_enabled = false;
+ priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
+
+ /* Reset MAC_FPE_CTRL_STS reg cache */
+ priv->fpe_cfg.fpe_csr = 0;
+ }
+
+ pm_runtime_put(priv->device);
+
return 0;
}
@@ -5979,44 +5997,34 @@ 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->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;
- if (status == FPE_EVENT_UNKNOWN || !*hs_enable)
- return;
+ spin_lock(&priv->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 */
+ /* LP has sent response mPacket */
if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP)
- *lp_state = FPE_STATE_ENTERING_ON;
-
- /* 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;
+ fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
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(&priv->fpe_cfg.lock);
}
static void stmmac_common_interrupt(struct stmmac_priv *priv)
@@ -7372,50 +7380,57 @@ 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)
+static void stmmac_fpe_verify_task(struct work_struct *work)
{
struct stmmac_priv *priv = container_of(work, struct stmmac_priv,
fpe_task);
struct stmmac_fpe_cfg *fpe_cfg = &priv->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;
-
- while (retries-- > 0) {
- /* Bail out immediately if FPE handshake is OFF */
- if (*lo_state == FPE_STATE_OFF || !*hs_enable)
+ int verify_limit = 3; /* defined by 802.3 */
+ unsigned long flags;
+ u32 sleep_ms;
+
+ spin_lock(&priv->fpe_cfg.lock);
+ sleep_ms = fpe_cfg->verify_time;
+ spin_unlock(&priv->fpe_cfg.lock);
+
+ while (1) {
+ /* The initial VERIFY was triggered by linkup event or
+ * stmmac_set_mm(), sleep then check MM_VERIFY_STATUS.
+ */
+ msleep(sleep_ms);
+
+ if (!netif_running(priv->dev))
break;
- 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);
+ spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
- netdev_info(priv->dev, "configured FPE\n");
+ if (fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_DISABLED ||
+ fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||
+ !fpe_cfg->pmac_enabled || !fpe_cfg->verify_enabled) {
+ spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
+ break;
+ }
- *lo_state = FPE_STATE_ON;
- *lp_state = FPE_STATE_ON;
- netdev_info(priv->dev, "!!! BOTH FPE stations ON\n");
+ if (verify_limit == 0) {
+ fpe_cfg->verify_enabled = false;
+ fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
+ stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
+ priv->plat->tx_queues_to_use,
+ priv->plat->rx_queues_to_use,
+ false);
+ spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
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);
- stmmac_fpe_send_mpacket(priv, priv->ioaddr,
- fpe_cfg,
+ if (fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING)
+ stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
MPACKET_VERIFY);
- }
- /* Sleep then retry */
- msleep(500);
+
+ sleep_ms = fpe_cfg->verify_time;
+
+ spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
+
+ verify_limit--;
}
clear_bit(__FPE_TASK_SCHED, &priv->fpe_task_state);
@@ -7535,8 +7550,8 @@ 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);
+ /* Initialize FPE verify workqueue */
+ INIT_WORK(&priv->fpe_task, stmmac_fpe_verify_task);
/* Override with kernel parameters if supplied XXX CRS XXX
* this needs to have multiple instances
@@ -7702,6 +7717,12 @@ int stmmac_dvr_probe(struct device *device,
mutex_init(&priv->lock);
+ spin_lock_init(&priv->fpe_cfg.lock);
+ priv->fpe_cfg.pmac_enabled = false;
+ priv->fpe_cfg.verify_time = 128; /* ethtool_mm_state.max_verify_time */
+ priv->fpe_cfg.verify_enabled = false;
+ priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
+
/* 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
@@ -7875,15 +7896,8 @@ int stmmac_suspend(struct device *dev)
}
rtnl_unlock();
- if (priv->dma_cap.fpesel) {
- /* Disable FPE */
- stmmac_fpe_configure(priv, priv->ioaddr,
- &priv->fpe_cfg,
- priv->plat->tx_queues_to_use,
- priv->plat->rx_queues_to_use, false);
-
+ if (priv->dma_cap.fpesel)
stmmac_fpe_stop_wq(priv);
- }
priv->speed = SPEED_UNKNOWN;
return 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index b0cc45331ff7..783829a6479c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -1063,11 +1063,6 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
return -EOPNOTSUPP;
}
- /* Actual FPE register configuration will be done after FPE handshake
- * is success.
- */
- priv->fpe_cfg.enable = fpe;
-
ret = stmmac_est_configure(priv, priv, priv->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->est_lock);
@@ -1094,7 +1089,6 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
mutex_unlock(&priv->est_lock);
}
- priv->fpe_cfg.enable = false;
stmmac_fpe_configure(priv, priv->ioaddr,
&priv->fpe_cfg,
priv->plat->tx_queues_to_use,
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v4 4/7] net: stmmac: configure FPE via ethtool-mm
2024-08-20 9:38 [PATCH net-next v4 0/7] net: stmmac: FPE via ethtool + tc Furong Xu
` (2 preceding siblings ...)
2024-08-20 9:38 ` [PATCH net-next v4 3/7] net: stmmac: refactor FPE verification process Furong Xu
@ 2024-08-20 9:38 ` Furong Xu
2024-08-20 14:48 ` Alexander Lobakin
2024-08-20 9:38 ` [PATCH net-next v4 5/7] net: stmmac: support fp parameter of tc-mqprio Furong Xu
` (2 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Furong Xu @ 2024-08-20 9:38 UTC (permalink / raw)
To: Serge Semin, Andrew Lunn, Vladimir Oltean, David S. Miller,
Alexandre Torgue, Jose Abreu, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Joao Pinto
Cc: netdev, linux-stm32, linux-arm-kernel, linux-kernel, xfr,
Furong Xu
Implement ethtool --show-mm and --set-mm callbacks.
NIC up/down, link up/down, suspend/resume, kselftest-ethtool_mm,
all tested okay.
Signed-off-by: Furong Xu <0x1207@gmail.com>
---
.../net/ethernet/stmicro/stmmac/dwmac4_core.c | 8 +-
drivers/net/ethernet/stmicro/stmmac/dwmac5.c | 36 +++++-
drivers/net/ethernet/stmicro/stmmac/dwmac5.h | 7 +-
.../ethernet/stmicro/stmmac/dwxgmac2_core.c | 4 +-
drivers/net/ethernet/stmicro/stmmac/hwif.h | 8 +-
.../ethernet/stmicro/stmmac/stmmac_ethtool.c | 110 ++++++++++++++++++
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 17 ++-
.../net/ethernet/stmicro/stmmac/stmmac_tc.c | 2 +-
8 files changed, 179 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 31c387cc5f26..679efcc631f1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -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,8 @@ 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,
.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 +1318,8 @@ 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,
.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,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
index e02cebc3f1b7..4c91fa766b13 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
@@ -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 */
+ (void)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)
@@ -638,3 +653,20 @@ 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(void __iomem *ioaddr)
+{
+ return FIELD_GET(AFSZ, 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);
+
+ value &= ~AFSZ;
+ value |= FIELD_PREP(AFSZ, add_frag_size);
+
+ writel(value, ioaddr + MTL_FPE_CTRL_STS);
+}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
index bf33a51d229e..e369e65920fc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
@@ -39,6 +39,9 @@
#define MAC_PPSx_INTERVAL(x) (0x00000b88 + ((x) * 0x10))
#define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10))
+#define MTL_FPE_CTRL_STS 0x00000c90
+#define AFSZ GENMASK(1, 0)
+
#define MTL_RXP_CONTROL_STATUS 0x00000ca0
#define RXPI BIT(31)
#define NPE GENMASK(23, 16)
@@ -104,10 +107,12 @@ 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(void __iomem *ioaddr);
+void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size);
#endif /* __DWMAC5_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index cbf2dd976ab1..55a175ced77f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -1506,11 +1506,11 @@ static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en,
static void dwxgmac3_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq,
- u32 num_rxq, bool enable)
+ 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;
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index d3da82982012..ba4418eaa8ba 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -421,11 +421,13 @@ 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)(void __iomem *ioaddr);
+ void (*fpe_set_add_frag_size)(void __iomem *ioaddr, u32 add_frag_size);
};
#define stmmac_core_init(__priv, __args...) \
@@ -530,6 +532,10 @@ 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)
/* PTP and HW Timer helpers */
struct stmmac_hwtimestamp {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 7008219fd88d..a8cdcacecc26 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -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
@@ -1270,6 +1271,112 @@ 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 add_frag_size;
+
+ if (!priv->dma_cap.fpesel)
+ return -EOPNOTSUPP;
+
+ spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
+
+ state->pmac_enabled = priv->fpe_cfg.pmac_enabled;
+ state->verify_time = priv->fpe_cfg.verify_time;
+ state->verify_enabled = priv->fpe_cfg.verify_enabled;
+ state->verify_status = priv->fpe_cfg.status;
+ state->rx_min_frag_size = ETH_ZLEN;
+
+ /* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime
+ * variable has a range between 1 and 128 ms inclusive. Limit to that.
+ */
+ state->max_verify_time = 128;
+
+ /* Cannot read MAC_FPE_CTRL_STS register here, or FPE interrupt events
+ * can be lost.
+ *
+ * See commit 37e4b8df27bc ("net: stmmac: fix FPE events losing")
+ */
+ state->tx_enabled = !!(priv->fpe_cfg.fpe_csr == EFPE);
+
+ /* FPE active if common tx_enabled and verification success or disabled (forced) */
+ state->tx_active = state->tx_enabled &&
+ (state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||
+ state->verify_status == ETHTOOL_MM_VERIFY_STATUS_DISABLED);
+
+ add_frag_size = stmmac_fpe_get_add_frag_size(priv, priv->ioaddr);
+ state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(add_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 add_frag_size;
+ int err;
+
+ if (!priv->dma_cap.fpesel)
+ return -EOPNOTSUPP;
+
+ /* Wait for the fpe_task that's currently in progress to finish */
+ flush_workqueue(priv->fpe_wq);
+
+ err = ethtool_mm_frag_size_min_to_add(cfg->tx_min_frag_size,
+ &add_frag_size, extack);
+ if (err)
+ return err;
+
+ spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
+
+ fpe_cfg->pmac_enabled = cfg->pmac_enabled;
+ fpe_cfg->verify_time = cfg->verify_time;
+ fpe_cfg->verify_enabled = cfg->verify_enabled;
+
+ stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
+ priv->plat->tx_queues_to_use,
+ priv->plat->rx_queues_to_use,
+ cfg->tx_enabled, cfg->pmac_enabled);
+
+ stmmac_fpe_set_add_frag_size(priv, priv->ioaddr, add_frag_size);
+
+ if (cfg->verify_enabled)
+ stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
+ MPACKET_VERIFY);
+ else
+ fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
+
+ spin_unlock_irqrestore(&priv->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->MACMergeFrameSmdErrorCount = mmc->mmc_rx_packet_smd_err_cntr;
+ s->MACMergeFrameAssOkCount = mmc->mmc_rx_packet_assembly_ok_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,
@@ -1309,6 +1416,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)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 6ae95f20b24f..00ed0543f5cf 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3537,8 +3537,21 @@ 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)
+ if (priv->dma_cap.fpesel) {
+ /* A SW reset just happened in stmmac_init_dma_engine(),
+ * we should restore fpe_cfg to HW, or FPE will stop working
+ * from suspend/resume.
+ */
+ spin_lock(&priv->fpe_cfg.lock);
+ stmmac_fpe_configure(priv, priv->ioaddr,
+ &priv->fpe_cfg,
+ priv->plat->tx_queues_to_use,
+ priv->plat->rx_queues_to_use,
+ false, priv->fpe_cfg.pmac_enabled);
+ spin_unlock(&priv->fpe_cfg.lock);
+
stmmac_fpe_start_wq(priv);
+ }
return 0;
}
@@ -7417,7 +7430,7 @@ static void stmmac_fpe_verify_task(struct work_struct *work)
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use,
- false);
+ false, fpe_cfg->pmac_enabled);
spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
break;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 783829a6479c..a58282d6458c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -1093,7 +1093,7 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
&priv->fpe_cfg,
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use,
- false);
+ false, false);
netdev_info(priv->dev, "disabled FPE\n");
return ret;
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v4 5/7] net: stmmac: support fp parameter of tc-mqprio
2024-08-20 9:38 [PATCH net-next v4 0/7] net: stmmac: FPE via ethtool + tc Furong Xu
` (3 preceding siblings ...)
2024-08-20 9:38 ` [PATCH net-next v4 4/7] net: stmmac: configure FPE via ethtool-mm Furong Xu
@ 2024-08-20 9:38 ` Furong Xu
2024-08-20 9:51 ` Vladimir Oltean
2024-08-20 15:00 ` Alexander Lobakin
2024-08-20 9:38 ` [PATCH net-next v4 6/7] net: stmmac: support fp parameter of tc-taprio Furong Xu
2024-08-20 9:38 ` [PATCH net-next v4 7/7] net: stmmac: silence FPE kernel logs Furong Xu
6 siblings, 2 replies; 18+ messages in thread
From: Furong Xu @ 2024-08-20 9:38 UTC (permalink / raw)
To: Serge Semin, Andrew Lunn, Vladimir Oltean, David S. Miller,
Alexandre Torgue, Jose Abreu, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Joao Pinto
Cc: netdev, linux-stm32, linux-arm-kernel, linux-kernel, xfr,
Furong Xu
tc-mqprio can select whether traffic classes are express or preemptible.
After some traffic tests, MAC merge layer statistics are all good.
Local device:
ethtool --include-statistics --json --show-mm eth1
[ {
"ifname": "eth1",
"pmac-enabled": true,
"tx-enabled": true,
"tx-active": true,
"tx-min-frag-size": 60,
"rx-min-frag-size": 60,
"verify-enabled": true,
"verify-time": 100,
"max-verify-time": 128,
"verify-status": "SUCCEEDED",
"statistics": {
"MACMergeFrameAssErrorCount": 0,
"MACMergeFrameSmdErrorCount": 0,
"MACMergeFrameAssOkCount": 0,
"MACMergeFragCountRx": 0,
"MACMergeFragCountTx": 35105,
"MACMergeHoldCount": 0
}
} ]
Remote device:
ethtool --include-statistics --json --show-mm end1
[ {
"ifname": "end1",
"pmac-enabled": true,
"tx-enabled": true,
"tx-active": true,
"tx-min-frag-size": 60,
"rx-min-frag-size": 60,
"verify-enabled": true,
"verify-time": 100,
"max-verify-time": 128,
"verify-status": "SUCCEEDED",
"statistics": {
"MACMergeFrameAssErrorCount": 0,
"MACMergeFrameSmdErrorCount": 0,
"MACMergeFrameAssOkCount": 35105,
"MACMergeFragCountRx": 35105,
"MACMergeFragCountTx": 0,
"MACMergeHoldCount": 0
}
} ]
Tested on DWMAC CORE 5.10a
Signed-off-by: Furong Xu <0x1207@gmail.com>
---
.../net/ethernet/stmicro/stmmac/dwmac4_core.c | 2 +
drivers/net/ethernet/stmicro/stmmac/dwmac5.c | 52 ++++++++++++
drivers/net/ethernet/stmicro/stmmac/dwmac5.h | 4 +
drivers/net/ethernet/stmicro/stmmac/hwif.h | 10 +++
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +
.../net/ethernet/stmicro/stmmac/stmmac_tc.c | 81 +++++++++++++++++++
6 files changed, 151 insertions(+)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 679efcc631f1..4722bac7e3d4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -1266,6 +1266,7 @@ const struct stmmac_ops dwmac410_ops = {
.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_set_preemptible_tcs = dwmac5_fpe_set_preemptible_tcs,
.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 +1321,7 @@ const struct stmmac_ops dwmac510_ops = {
.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_set_preemptible_tcs = dwmac5_fpe_set_preemptible_tcs,
.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,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
index 4c91fa766b13..1e87dbc9a406 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
@@ -670,3 +670,55 @@ void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size)
writel(value, ioaddr + MTL_FPE_CTRL_STS);
}
+
+int dwmac5_fpe_set_preemptible_tcs(struct net_device *ndev,
+ struct netlink_ext_ack *extack,
+ unsigned long tcs)
+{
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ void __iomem *ioaddr = priv->ioaddr;
+ unsigned long queue_tcs = 0;
+ int num_tc = ndev->num_tc;
+ u32 value, queue_weight;
+ u16 offset, count;
+ int tc, i;
+
+ if (!tcs)
+ goto __update_queue_tcs;
+
+ for (tc = 0; tc < num_tc; tc++) {
+ count = ndev->tc_to_txq[tc].count;
+ offset = ndev->tc_to_txq[tc].offset;
+
+ if (tcs & BIT(tc))
+ queue_tcs |= 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, "TX algorithm SP is not suitable for one TC to multiple TXQs mapping");
+ return -EINVAL;
+ }
+
+ queue_weight = priv->plat->tx_queues_cfg[offset].weight;
+ for (i = 1; i < count; i++) {
+ if (queue_weight != priv->plat->tx_queues_cfg[offset + i].weight) {
+ NL_SET_ERR_MSG_FMT_MOD(extack, "TXQ weight [%u] differs across other TXQs in TC: [%u]",
+ queue_weight, tc);
+ return -EINVAL;
+ }
+ }
+ }
+
+__update_queue_tcs:
+ value = readl(ioaddr + MTL_FPE_CTRL_STS);
+
+ value &= ~PEC;
+ value |= FIELD_PREP(PEC, queue_tcs);
+
+ writel(value, ioaddr + MTL_FPE_CTRL_STS);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
index e369e65920fc..d3191c48354d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
@@ -40,6 +40,7 @@
#define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10))
#define MTL_FPE_CTRL_STS 0x00000c90
+#define PEC GENMASK(15, 8)
#define AFSZ GENMASK(1, 0)
#define MTL_RXP_CONTROL_STATUS 0x00000ca0
@@ -114,5 +115,8 @@ void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev);
int dwmac5_fpe_get_add_frag_size(void __iomem *ioaddr);
void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size);
+int dwmac5_fpe_set_preemptible_tcs(struct net_device *ndev,
+ struct netlink_ext_ack *extack,
+ unsigned long tcs);
#endif /* __DWMAC5_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index ba4418eaa8ba..37e8fecaf042 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -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...) \
({ \
@@ -428,6 +429,9 @@ struct stmmac_ops {
int (*fpe_irq_status)(void __iomem *ioaddr, struct net_device *dev);
int (*fpe_get_add_frag_size)(void __iomem *ioaddr);
void (*fpe_set_add_frag_size)(void __iomem *ioaddr, u32 add_frag_size);
+ int (*fpe_set_preemptible_tcs)(struct net_device *ndev,
+ struct netlink_ext_ack *extack,
+ unsigned long tcs);
};
#define stmmac_core_init(__priv, __args...) \
@@ -536,6 +540,8 @@ struct stmmac_ops {
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_set_preemptible_tcs(__priv, __args...) \
+ stmmac_do_callback(__priv, mac, fpe_set_preemptible_tcs, __args)
/* PTP and HW Timer helpers */
struct stmmac_hwtimestamp {
@@ -623,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...) \
@@ -639,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;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 00ed0543f5cf..6d7aca411af7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -6274,6 +6274,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,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index a58282d6458c..f8f09ef2d447 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -4,6 +4,7 @@
* stmmac TC Handling (HW only)
*/
+#include <linux/ethtool_netlink.h>
#include <net/pkt_cls.h>
#include <net/tc_act/tc_gact.h>
#include "common.h"
@@ -1174,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;
@@ -1190,6 +1198,78 @@ 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_set_preemptible_tcs(priv, ndev, extack, 0);
+}
+
+static int tc_setup_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;
+ struct net_device *ndev = priv->dev;
+ int num_stack_tx_queues = 0;
+ int num_tc = qopt->num_tc;
+ u16 offset, count;
+ int tc, err;
+
+ if (!num_tc) {
+ stmmac_reset_tc_mqprio(ndev, extack);
+ return 0;
+ }
+
+ if (mqprio->preemptible_tcs && !ethtool_dev_mm_supported(ndev)) {
+ NL_SET_ERR_MSG_MOD(extack, "Device does not support preemption");
+ return -EOPNOTSUPP;
+ }
+
+ err = netdev_set_num_tc(ndev, num_tc);
+ if (err)
+ return err;
+
+ /* DWMAC CORE4+ can not programming 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."
+ *
+ * Luckily, DWXGMAC CORE can.
+ *
+ * Thus preemptible_tcs should be handled in a per core manner.
+ */
+ for (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_set_preemptible_tcs(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;
+}
+
const struct stmmac_tc_ops dwmac510_tc_ops = {
.init = tc_init,
.setup_cls_u32 = tc_setup_cls_u32,
@@ -1198,4 +1278,5 @@ 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_mqprio,
};
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v4 6/7] net: stmmac: support fp parameter of tc-taprio
2024-08-20 9:38 [PATCH net-next v4 0/7] net: stmmac: FPE via ethtool + tc Furong Xu
` (4 preceding siblings ...)
2024-08-20 9:38 ` [PATCH net-next v4 5/7] net: stmmac: support fp parameter of tc-mqprio Furong Xu
@ 2024-08-20 9:38 ` Furong Xu
2024-08-20 9:38 ` [PATCH net-next v4 7/7] net: stmmac: silence FPE kernel logs Furong Xu
6 siblings, 0 replies; 18+ messages in thread
From: Furong Xu @ 2024-08-20 9:38 UTC (permalink / raw)
To: Serge Semin, Andrew Lunn, Vladimir Oltean, David S. Miller,
Alexandre Torgue, Jose Abreu, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Joao Pinto
Cc: netdev, linux-stm32, linux-arm-kernel, linux-kernel, xfr,
Furong Xu
tc-taprio can select whether traffic classes are express or preemptible.
0) tc qdisc add dev eth1 parent root handle 100 taprio \
num_tc 4 \
map 0 1 2 3 2 2 2 2 2 2 2 2 2 2 2 3 \
queues 1@0 1@1 1@2 1@3 \
base-time 1000000000 \
sched-entry S 03 10000000 \
sched-entry S 0e 10000000 \
flags 0x2 fp P E E E
1) After some traffic tests, MAC merge layer statistics are all good.
Local device:
[ {
"ifname": "eth1",
"pmac-enabled": true,
"tx-enabled": true,
"tx-active": true,
"tx-min-frag-size": 60,
"rx-min-frag-size": 60,
"verify-enabled": true,
"verify-time": 100,
"max-verify-time": 128,
"verify-status": "SUCCEEDED",
"statistics": {
"MACMergeFrameAssErrorCount": 0,
"MACMergeFrameSmdErrorCount": 0,
"MACMergeFrameAssOkCount": 0,
"MACMergeFragCountRx": 0,
"MACMergeFragCountTx": 17837,
"MACMergeHoldCount": 18639
}
} ]
Remote device:
[ {
"ifname": "end1",
"pmac-enabled": true,
"tx-enabled": true,
"tx-active": true,
"tx-min-frag-size": 60,
"rx-min-frag-size": 60,
"verify-enabled": true,
"verify-time": 100,
"max-verify-time": 128,
"verify-status": "SUCCEEDED",
"statistics": {
"MACMergeFrameAssErrorCount": 0,
"MACMergeFrameSmdErrorCount": 0,
"MACMergeFrameAssOkCount": 17189,
"MACMergeFragCountRx": 17837,
"MACMergeFragCountTx": 0,
"MACMergeHoldCount": 0
}
} ]
Tested on DWMAC CORE 5.10a
Signed-off-by: Furong Xu <0x1207@gmail.com>
---
.../net/ethernet/stmicro/stmmac/stmmac_tc.c | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index f8f09ef2d447..589fbe9de09b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -932,9 +932,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;
@@ -1019,16 +1019,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;
@@ -1059,7 +1055,8 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
tc_taprio_map_maxsdu_txq(priv, qopt);
- if (fpe && !priv->dma_cap.fpesel) {
+ if (qopt->mqprio.preemptible_tcs && !ethtool_dev_mm_supported(priv->dev)) {
+ NL_SET_ERR_MSG_MOD(extack, "Device does not support preemption");
mutex_unlock(&priv->est_lock);
return -EOPNOTSUPP;
}
@@ -1072,6 +1069,9 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
goto disable;
}
+ stmmac_fpe_set_preemptible_tcs(priv, priv->dev, extack,
+ qopt->mqprio.preemptible_tcs);
+
netdev_info(priv->dev, "configured EST\n");
return 0;
@@ -1090,11 +1090,8 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
mutex_unlock(&priv->est_lock);
}
- stmmac_fpe_configure(priv, priv->ioaddr,
- &priv->fpe_cfg,
- priv->plat->tx_queues_to_use,
- priv->plat->rx_queues_to_use,
- false, false);
+ stmmac_fpe_set_preemptible_tcs(priv, priv->dev, extack, 0);
+
netdev_info(priv->dev, "disabled FPE\n");
return ret;
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v4 7/7] net: stmmac: silence FPE kernel logs
2024-08-20 9:38 [PATCH net-next v4 0/7] net: stmmac: FPE via ethtool + tc Furong Xu
` (5 preceding siblings ...)
2024-08-20 9:38 ` [PATCH net-next v4 6/7] net: stmmac: support fp parameter of tc-taprio Furong Xu
@ 2024-08-20 9:38 ` Furong Xu
6 siblings, 0 replies; 18+ messages in thread
From: Furong Xu @ 2024-08-20 9:38 UTC (permalink / raw)
To: Serge Semin, Andrew Lunn, Vladimir Oltean, David S. Miller,
Alexandre Torgue, Jose Abreu, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Joao Pinto
Cc: netdev, linux-stm32, linux-arm-kernel, linux-kernel, xfr,
Furong Xu
ethtool --show-mm can get real-time state of FPE.
Those kernel logs should keep quiet.
Signed-off-by: Furong Xu <0x1207@gmail.com>
---
drivers/net/ethernet/stmicro/stmmac/dwmac5.c | 8 ++++----
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
index 1e87dbc9a406..c9905caf97ff 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
@@ -620,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;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 6d7aca411af7..e2e1f1d6ff39 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3378,7 +3378,7 @@ static int stmmac_fpe_start_wq(struct stmmac_priv *priv)
return -ENOMEM;
}
- netdev_info(priv->dev, "FPE workqueue start");
+ netdev_dbg(priv->dev, "FPE workqueue start");
return 0;
}
@@ -4058,7 +4058,7 @@ static void stmmac_fpe_stop_wq(struct stmmac_priv *priv)
priv->fpe_wq = NULL;
}
- netdev_info(priv->dev, "FPE workqueue stop");
+ netdev_dbg(priv->dev, "FPE workqueue stop");
}
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 5/7] net: stmmac: support fp parameter of tc-mqprio
2024-08-20 9:38 ` [PATCH net-next v4 5/7] net: stmmac: support fp parameter of tc-mqprio Furong Xu
@ 2024-08-20 9:51 ` Vladimir Oltean
2024-08-20 15:00 ` Alexander Lobakin
1 sibling, 0 replies; 18+ messages in thread
From: Vladimir Oltean @ 2024-08-20 9:51 UTC (permalink / raw)
To: Furong Xu
Cc: Serge Semin, Andrew Lunn, David S. Miller, Alexandre Torgue,
Jose Abreu, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Maxime Coquelin, Joao Pinto, netdev, linux-stm32,
linux-arm-kernel, linux-kernel, xfr
On Tue, Aug 20, 2024 at 05:38:33PM +0800, Furong Xu wrote:
> +static int tc_setup_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;
> + struct net_device *ndev = priv->dev;
> + int num_stack_tx_queues = 0;
> + int num_tc = qopt->num_tc;
> + u16 offset, count;
> + int tc, err;
> +
> + if (!num_tc) {
> + stmmac_reset_tc_mqprio(ndev, extack);
> + return 0;
> + }
> +
> + if (mqprio->preemptible_tcs && !ethtool_dev_mm_supported(ndev)) {
> + NL_SET_ERR_MSG_MOD(extack, "Device does not support preemption");
> + return -EOPNOTSUPP;
> + }
When I said that "this condition is dealt with by the core, now"
https://lore.kernel.org/netdev/20240819114242.2m6okk7bq64e437c@skbuf/
I meant that the driver doesn't need to check anything - the check has
already run once, in the Qdisc layer. See taprio_parse_tc_entries() and
mqprio_parse_tc_entries(). I was not asking to insert this test, just to
completely remove, rather than adapt, the entire block:
if (fpe && !priv->dma_cap.fpesel) {
mutex_unlock(&priv->est_lock);
return -EOPNOTSUPP;
}
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 1/7] net: stmmac: move stmmac_fpe_cfg to stmmac_priv data
2024-08-20 9:38 ` [PATCH net-next v4 1/7] net: stmmac: move stmmac_fpe_cfg to stmmac_priv data Furong Xu
@ 2024-08-20 9:55 ` Vladimir Oltean
0 siblings, 0 replies; 18+ messages in thread
From: Vladimir Oltean @ 2024-08-20 9:55 UTC (permalink / raw)
To: Furong Xu
Cc: Serge Semin, Andrew Lunn, David S. Miller, Alexandre Torgue,
Jose Abreu, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Maxime Coquelin, Joao Pinto, netdev, linux-stm32,
linux-arm-kernel, linux-kernel, xfr
On Tue, Aug 20, 2024 at 05:38:29PM +0800, Furong Xu wrote:
> By moving the fpe_cfg field to the stmmac_priv data, stmmac_fpe_cfg
> becomes platform-data eventually, instead of a run-time config.
>
> Suggested-by: Serge Semin <fancer.lancer@gmail.com>
> Signed-off-by: Furong Xu <0x1207@gmail.com>
> ---
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 2/7] net: stmmac: drop stmmac_fpe_handshake
2024-08-20 9:38 ` [PATCH net-next v4 2/7] net: stmmac: drop stmmac_fpe_handshake Furong Xu
@ 2024-08-20 9:56 ` Vladimir Oltean
0 siblings, 0 replies; 18+ messages in thread
From: Vladimir Oltean @ 2024-08-20 9:56 UTC (permalink / raw)
To: Furong Xu
Cc: Serge Semin, Andrew Lunn, David S. Miller, Alexandre Torgue,
Jose Abreu, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Maxime Coquelin, Joao Pinto, netdev, linux-stm32,
linux-arm-kernel, linux-kernel, xfr
On Tue, Aug 20, 2024 at 05:38:30PM +0800, Furong Xu wrote:
> ethtool --set-mm can trigger FPE verification processe by calling
nitpick: process
> stmmac_fpe_send_mpacket, stmmac_fpe_handshake should be gone.
>
> Signed-off-by: Furong Xu <0x1207@gmail.com>
> ---
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/7] net: stmmac: refactor FPE verification process
2024-08-20 9:38 ` [PATCH net-next v4 3/7] net: stmmac: refactor FPE verification process Furong Xu
@ 2024-08-20 12:34 ` Vladimir Oltean
2024-08-20 12:52 ` Vladimir Oltean
2024-08-21 4:58 ` Furong Xu
2024-08-20 14:36 ` Alexander Lobakin
1 sibling, 2 replies; 18+ messages in thread
From: Vladimir Oltean @ 2024-08-20 12:34 UTC (permalink / raw)
To: Furong Xu
Cc: Serge Semin, Andrew Lunn, David S. Miller, Alexandre Torgue,
Jose Abreu, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Maxime Coquelin, Joao Pinto, netdev, linux-stm32,
linux-arm-kernel, linux-kernel, xfr
[-- Attachment #1: Type: text/plain, Size: 12169 bytes --]
On Tue, Aug 20, 2024 at 05:38:31PM +0800, Furong Xu wrote:
> Drop driver defined stmmac_fpe_state, and switch to common
> ethtool_mm_verify_status for local TX verification status.
>
> Local side and remote side verification processes are completely
> independent. There is no reason at all to keep a local state and
> a remote state.
>
> Add a spinlock to avoid races among ISR, workqueue, link update
> and register configuration.
>
> Signed-off-by: Furong Xu <0x1207@gmail.com>
> ---
> drivers/net/ethernet/stmicro/stmmac/stmmac.h | 21 +--
> .../net/ethernet/stmicro/stmmac/stmmac_main.c | 172 ++++++++++--------
> .../net/ethernet/stmicro/stmmac/stmmac_tc.c | 6 -
> 3 files changed, 102 insertions(+), 97 deletions(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> index 458d6b16ce21..407b59f2783f 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> @@ -146,14 +146,6 @@ struct stmmac_channel {
> u32 index;
> };
>
> -/* 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,
> @@ -166,11 +158,16 @@ enum stmmac_fpe_task_state_t {
> };
>
> 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 */
> + /* 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 */
> + u32 verify_time; /* see ethtool_mm_state */
> + bool pmac_enabled; /* see ethtool_mm_state */
> + bool verify_enabled; /* see ethtool_mm_state */
> + enum ethtool_mm_verify_status status;
> };
>
> struct stmmac_tc_entry {
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 3072ad33b105..6ae95f20b24f 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -969,17 +969,21 @@ 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->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;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
> +
> + if (!fpe_cfg->pmac_enabled)
> + goto __unlock_out;
>
> - if (is_up && *hs_enable) {
> + if (is_up && fpe_cfg->verify_enabled)
> stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
> MPACKET_VERIFY);
> - } else {
> - *lo_state = FPE_STATE_OFF;
> - *lp_state = FPE_STATE_OFF;
> - }
> + else
> + fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
The fpe_task may be scheduled here. When you unlock, it may run and
overwrite the fpe_cfg->status you've just set.
Although I don't actually recommend setting ETHTOOL_MM_VERIFY_STATUS_DISABLED
unless cfg->verify_enabled=false.
> +
> +__unlock_out:
> + spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
> }
>
> static void stmmac_mac_link_down(struct phylink_config *config,
> @@ -4091,11 +4095,25 @@ static int stmmac_release(struct net_device *dev)
>
> stmmac_release_ptp(priv);
>
> - pm_runtime_put(priv->device);
> -
> - if (priv->dma_cap.fpesel)
> + if (priv->dma_cap.fpesel) {
> stmmac_fpe_stop_wq(priv);
>
> + /* stmmac_ethtool_ops.begin() guarantees that all ethtool
> + * requests to fail with EBUSY when !netif_running()
> + *
> + * Prepare some params here, then fpe_cfg can keep consistent
> + * with the register states after a SW reset by __stmmac_open().
> + */
> + priv->fpe_cfg.pmac_enabled = false;
> + priv->fpe_cfg.verify_enabled = false;
> + priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
> +
> + /* Reset MAC_FPE_CTRL_STS reg cache */
> + priv->fpe_cfg.fpe_csr = 0;
> + }
With this block of code, you're saying that you're deliberately okay for
the ethtool-mm state to be lost after a stmmac_release() call. Mind you,
some of the call sites of this are:
- stmmac_change_mtu()
- stmmac_reinit_queues()
- stmmac_reinit_ringparam()
I disagree that it's okay to lose the state configured by user space.
Instead, you should reprogram the saved state once lost.
Note that because stmmac_release() calls phylink_stop(), I think that
restoring the state in stmmac_fpe_link_state_handle() is enough. Because
there will always be a link drop.
> +
> + pm_runtime_put(priv->device);
> +
> return 0;
> }
>
> @@ -5979,44 +5997,34 @@ 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->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;
>
> - if (status == FPE_EVENT_UNKNOWN || !*hs_enable)
> - return;
> + spin_lock(&priv->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 */
> + /* LP has sent response mPacket */
> if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP)
> - *lp_state = FPE_STATE_ENTERING_ON;
> -
> - /* 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;
> + fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
>
> 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(&priv->fpe_cfg.lock);
> }
>
> static void stmmac_common_interrupt(struct stmmac_priv *priv)
> @@ -7372,50 +7380,57 @@ 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)
> +static void stmmac_fpe_verify_task(struct work_struct *work)
> {
> struct stmmac_priv *priv = container_of(work, struct stmmac_priv,
> fpe_task);
> struct stmmac_fpe_cfg *fpe_cfg = &priv->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;
> -
> - while (retries-- > 0) {
> - /* Bail out immediately if FPE handshake is OFF */
> - if (*lo_state == FPE_STATE_OFF || !*hs_enable)
> + int verify_limit = 3; /* defined by 802.3 */
> + unsigned long flags;
> + u32 sleep_ms;
> +
> + spin_lock(&priv->fpe_cfg.lock);
> + sleep_ms = fpe_cfg->verify_time;
> + spin_unlock(&priv->fpe_cfg.lock);
> +
> + while (1) {
> + /* The initial VERIFY was triggered by linkup event or
> + * stmmac_set_mm(), sleep then check MM_VERIFY_STATUS.
> + */
> + msleep(sleep_ms);
Thanks for the added comment. But why don't you just use queue_delayed_work()
instead of queue_work() and sleeping at the very beginning?
With this, you really don't need to drop the lock and read fpe_cfg->verify_time
twice.
But I think what is needed here is better suited for a timer, especially
because of the required coordination with the IRQ. See the end and the
attachment for more details.
> +
> + if (!netif_running(priv->dev))
> break;
>
> - 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);
> + spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
>
> - netdev_info(priv->dev, "configured FPE\n");
> + if (fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_DISABLED ||
> + fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||
> + !fpe_cfg->pmac_enabled || !fpe_cfg->verify_enabled) {
> + spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
> + break;
> + }
>
> - *lo_state = FPE_STATE_ON;
> - *lp_state = FPE_STATE_ON;
> - netdev_info(priv->dev, "!!! BOTH FPE stations ON\n");
> + if (verify_limit == 0) {
> + fpe_cfg->verify_enabled = false;
I don't understand why turn off verify_enabled after failure? Only the
user should be able to modify this.
> + fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
> + stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
> + priv->plat->tx_queues_to_use,
> + priv->plat->rx_queues_to_use,
> + false);
I don't understand why turn off tx_enabled after failure, rather than
not turning it on at all until success?
This really has me thinking. This hardware does not have the explicit
notion of the verification state - it is purely a driver construct.
So I wonder if the EFPE bit in MAC_FPE_CTRL_STS isn't actually what
corresponds to "tx_active" rather than "tx_enabled"?
(definitions at https://docs.kernel.org/networking/ethtool-netlink.html)
And "tx_enabled" would just correspond to a state variable in the driver,
which does nothing until verification is actually complete.
There is a test in manual_failed_verification() which checks the
correctness of the tx_enabled/tx_active behavior. If tx_enabled=true but
verification fails (and also _up until_ that point), the MM layer is
supposed to send packets through the eMAC (because tx_active=false).
But for your driver, that test is inconclusive, because you don't report
ethtool stats broken down by eMAC/pMAC, just aggregate. So we don't know
unless we take a closer look manually at the driver in that state.
> + spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
> 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);
> - stmmac_fpe_send_mpacket(priv, priv->ioaddr,
> - fpe_cfg,
> + if (fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING)
> + stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
> MPACKET_VERIFY);
> - }
> - /* Sleep then retry */
> - msleep(500);
> +
> + sleep_ms = fpe_cfg->verify_time;
> +
> + spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
> +
> + verify_limit--;
> }
I took the liberty of rewriting the fpe_task to a timer, and delete the
workqueue. Here is a completely untested patch, which at least is less
complex, has less code and is easier to understand. What do you think?
[-- Attachment #2: 0001-net-stmmac-replace-FPE-workqueue-with-timer.patch --]
[-- Type: text/x-diff, Size: 14770 bytes --]
From 6ce277245128638160385d948583a3e6d2561a94 Mon Sep 17 00:00:00 2001
From: Vladimir Oltean <vladimir.oltean@nxp.com>
Date: Tue, 20 Aug 2024 14:50:32 +0300
Subject: [PATCH] net: stmmac: replace FPE workqueue with timer
What remains in the fpe_task after decoupling RX from TX appears
overengineered to use a workqueue. A timer which retransmits Verify
mPackets until the verify_limit expires, or enables transmission on
success, seems enough.
In the INITIAL state, the timer sends MPACKET_VERIFY. Eventually the
stmmac_fpe_event_status() IRQ fires and advances the state to VERIFYING,
then rearms the timer after verify_time ms. If a subsequent IRQ comes in
and modifies the state to SUCCEEDED after getting MPACKET_RESPONSE, the
timer sees this. It must enable the EFPE bit now. Otherwise, it
decrements the verify_limit counter and tries again. Eventually it
moves the status to FAILED, from which the IRQ cannot move it anywhere
else, except for another stmmac_fpe_apply() call.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 16 +-
.../ethernet/stmicro/stmmac/stmmac_ethtool.c | 35 +--
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 212 +++++++-----------
3 files changed, 100 insertions(+), 163 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 407b59f2783f..dd15f71e1663 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -152,21 +152,18 @@ enum stmmac_mpacket_type {
MPACKET_RESPONSE = 1,
};
-enum stmmac_fpe_task_state_t {
- __FPE_REMOVING,
- __FPE_TASK_SCHED,
-};
-
struct stmmac_fpe_cfg {
/* Serialize access to MAC Merge state between ethtool requests
* and link state updates.
*/
spinlock_t lock;
-
+ struct timer_list verify_timer;
u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */
u32 verify_time; /* see ethtool_mm_state */
bool pmac_enabled; /* see ethtool_mm_state */
bool verify_enabled; /* see ethtool_mm_state */
+ bool tx_enabled;
+ int verify_limit;
enum ethtool_mm_verify_status status;
};
@@ -364,10 +361,6 @@ struct stmmac_priv {
struct work_struct service_task;
/* Frame Preemption feature (FPE) */
- unsigned long fpe_task_state;
- struct workqueue_struct *fpe_wq;
- struct work_struct fpe_task;
- char wq_name[IFNAMSIZ + 4];
struct stmmac_fpe_cfg fpe_cfg;
/* TC Handling */
@@ -422,7 +415,8 @@ 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);
+void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg);
static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv)
{
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index a8cdcacecc26..3eb5344e2412 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -1293,14 +1293,7 @@ static int stmmac_get_mm(struct net_device *ndev,
* variable has a range between 1 and 128 ms inclusive. Limit to that.
*/
state->max_verify_time = 128;
-
- /* Cannot read MAC_FPE_CTRL_STS register here, or FPE interrupt events
- * can be lost.
- *
- * See commit 37e4b8df27bc ("net: stmmac: fix FPE events losing")
- */
- state->tx_enabled = !!(priv->fpe_cfg.fpe_csr == EFPE);
-
+ state->tx_enabled = priv->fpe_cfg.tx_enabled;
/* FPE active if common tx_enabled and verification success or disabled (forced) */
state->tx_active = state->tx_enabled &&
(state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||
@@ -1326,34 +1319,28 @@ static int stmmac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,
if (!priv->dma_cap.fpesel)
return -EOPNOTSUPP;
- /* Wait for the fpe_task that's currently in progress to finish */
- flush_workqueue(priv->fpe_wq);
-
err = ethtool_mm_frag_size_min_to_add(cfg->tx_min_frag_size,
&add_frag_size, extack);
if (err)
return err;
- spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
+ /* Wait for the verification that's currently in progress to finish */
+ del_timer_sync(&fpe_cfg->verify_timer);
+
+ spin_lock_irqsave(&fpe_cfg->lock, flags);
fpe_cfg->pmac_enabled = cfg->pmac_enabled;
+ fpe_cfg->tx_enabled = cfg->tx_enabled;
fpe_cfg->verify_time = cfg->verify_time;
fpe_cfg->verify_enabled = cfg->verify_enabled;
-
- stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
- priv->plat->tx_queues_to_use,
- priv->plat->rx_queues_to_use,
- cfg->tx_enabled, cfg->pmac_enabled);
+ fpe_cfg->verify_limit = 3; /* IEEE 802.3 constant */
+ if (!cfg->verify_enabled)
+ fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
stmmac_fpe_set_add_frag_size(priv, priv->ioaddr, add_frag_size);
+ stmmac_fpe_apply(priv);
- if (cfg->verify_enabled)
- stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
- MPACKET_VERIFY);
- else
- fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
-
- spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
+ spin_unlock_irqrestore(&fpe_cfg->lock, flags);
return 0;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index a5d01162fcc5..fa74504f3ad5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -971,19 +971,22 @@ 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;
- spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
+ del_timer_sync(&fpe_cfg->verify_timer);
- if (!fpe_cfg->pmac_enabled)
- goto __unlock_out;
+ spin_lock_irqsave(&fpe_cfg->lock, flags);
- if (is_up && fpe_cfg->verify_enabled)
- stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
- MPACKET_VERIFY);
- else
- fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
+ if (is_up) {
+ /* 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);
+ }
-__unlock_out:
- spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
+ spin_unlock_irqrestore(&fpe_cfg->lock, flags);
}
static void stmmac_mac_link_down(struct phylink_config *config,
@@ -3362,27 +3365,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_dbg(priv->dev, "FPE workqueue start");
-
- return 0;
-}
-
/**
* stmmac_hw_setup - setup mac in a usable state.
* @dev : pointer to the device structure.
@@ -3537,22 +3519,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) {
- /* A SW reset just happened in stmmac_init_dma_engine(),
- * we should restore fpe_cfg to HW, or FPE will stop working
- * from suspend/resume.
- */
- spin_lock(&priv->fpe_cfg.lock);
- stmmac_fpe_configure(priv, priv->ioaddr,
- &priv->fpe_cfg,
- priv->plat->tx_queues_to_use,
- priv->plat->rx_queues_to_use,
- false, priv->fpe_cfg.pmac_enabled);
- spin_unlock(&priv->fpe_cfg.lock);
-
- stmmac_fpe_start_wq(priv);
- }
-
return 0;
}
@@ -4049,18 +4015,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_dbg(priv->dev, "FPE workqueue stop");
-}
-
/**
* stmmac_release - close entry point of the driver
* @dev : device pointer.
@@ -4108,22 +4062,8 @@ static int stmmac_release(struct net_device *dev)
stmmac_release_ptp(priv);
- if (priv->dma_cap.fpesel) {
- stmmac_fpe_stop_wq(priv);
-
- /* stmmac_ethtool_ops.begin() guarantees that all ethtool
- * requests to fail with EBUSY when !netif_running()
- *
- * Prepare some params here, then fpe_cfg can keep consistent
- * with the register states after a SW reset by __stmmac_open().
- */
- priv->fpe_cfg.pmac_enabled = false;
- priv->fpe_cfg.verify_enabled = false;
- priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
-
- /* Reset MAC_FPE_CTRL_STS reg cache */
- priv->fpe_cfg.fpe_csr = 0;
- }
+ if (priv->dma_cap.fpesel)
+ del_timer_sync(&priv->fpe_cfg.verify_timer);
pm_runtime_put(priv->device);
@@ -6030,11 +5970,7 @@ static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status)
if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP)
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
- 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);
- }
+ stmmac_fpe_verify_timer_arm(fpe_cfg);
__unlock_out:
spin_unlock(&priv->fpe_cfg.lock);
@@ -7395,60 +7331,82 @@ int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size)
return ret;
}
-static void stmmac_fpe_verify_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->fpe_cfg;
- int verify_limit = 3; /* defined by 802.3 */
- unsigned long flags;
- u32 sleep_ms;
+ 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);
+ bool rearm = false;
- spin_lock(&priv->fpe_cfg.lock);
- sleep_ms = fpe_cfg->verify_time;
- spin_unlock(&priv->fpe_cfg.lock);
+ spin_lock(&fpe_cfg->lock);
- while (1) {
- /* The initial VERIFY was triggered by linkup event or
- * stmmac_set_mm(), sleep then check MM_VERIFY_STATUS.
- */
- msleep(sleep_ms);
-
- if (!netif_running(priv->dev))
- break;
-
- spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
-
- if (fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_DISABLED ||
- fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||
- !fpe_cfg->pmac_enabled || !fpe_cfg->verify_enabled) {
- spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
- break;
- }
-
- if (verify_limit == 0) {
- fpe_cfg->verify_enabled = false;
+ switch (fpe_cfg->status) {
+ case ETHTOOL_MM_VERIFY_STATUS_INITIAL:
+ case ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
+ stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
+ MPACKET_VERIFY);
+ if (fpe_cfg->verify_limit != 0) {
+ fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING;
+ rearm = true;
+ } else {
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
- stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
- priv->plat->tx_queues_to_use,
- priv->plat->rx_queues_to_use,
- false, fpe_cfg->pmac_enabled);
- spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
- break;
}
+ fpe_cfg->verify_limit--;
+ 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 (fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING)
- stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
- MPACKET_VERIFY);
-
- sleep_ms = fpe_cfg->verify_time;
+ if (rearm) {
+ mod_timer(&fpe_cfg->verify_timer,
+ msecs_to_jiffies(fpe_cfg->verify_time));
+ }
- spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
+ spin_unlock(&fpe_cfg->lock);
+}
- verify_limit--;
+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) {
+ mod_timer(&fpe_cfg->verify_timer,
+ msecs_to_jiffies(fpe_cfg->verify_time));
}
+}
- clear_bit(__FPE_TASK_SCHED, &priv->fpe_task_state);
+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;
+ stmmac_fpe_verify_timer_arm(fpe_cfg);
+ }
}
static int stmmac_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp)
@@ -7565,9 +7523,6 @@ int stmmac_dvr_probe(struct device *device,
INIT_WORK(&priv->service_task, stmmac_service_task);
- /* Initialize FPE verify workqueue */
- INIT_WORK(&priv->fpe_task, stmmac_fpe_verify_task);
-
/* Override with kernel parameters if supplied XXX CRS XXX
* this needs to have multiple instances
*/
@@ -7733,6 +7688,7 @@ int stmmac_dvr_probe(struct device *device,
mutex_init(&priv->lock);
spin_lock_init(&priv->fpe_cfg.lock);
+ timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0);
priv->fpe_cfg.pmac_enabled = false;
priv->fpe_cfg.verify_time = 128; /* ethtool_mm_state.max_verify_time */
priv->fpe_cfg.verify_enabled = false;
@@ -7912,7 +7868,7 @@ int stmmac_suspend(struct device *dev)
rtnl_unlock();
if (priv->dma_cap.fpesel)
- stmmac_fpe_stop_wq(priv);
+ del_timer_sync(&priv->fpe_cfg.verify_timer);
priv->speed = SPEED_UNKNOWN;
return 0;
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/7] net: stmmac: refactor FPE verification process
2024-08-20 12:34 ` Vladimir Oltean
@ 2024-08-20 12:52 ` Vladimir Oltean
2024-08-21 4:58 ` Furong Xu
1 sibling, 0 replies; 18+ messages in thread
From: Vladimir Oltean @ 2024-08-20 12:52 UTC (permalink / raw)
To: Furong Xu
Cc: Serge Semin, Andrew Lunn, David S. Miller, Alexandre Torgue,
Jose Abreu, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Maxime Coquelin, Joao Pinto, netdev, linux-stm32,
linux-arm-kernel, linux-kernel, xfr
On Tue, Aug 20, 2024 at 03:34:56PM +0300, Vladimir Oltean wrote:
> I took the liberty of rewriting the fpe_task to a timer, and delete the
> workqueue. Here is a completely untested patch, which at least is less
> complex, has less code and is easier to understand. What do you think?
I already found a bug in the code I sent, sorry. verify_limit needs to
be reset each time status is reset to ETHTOOL_MM_VERIFY_STATUS_INITIAL,
to allow for 3 retries on each clean-state verification process.
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 3eb5344e2412..530793bce231 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -1333,7 +1333,6 @@ static int stmmac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,
fpe_cfg->tx_enabled = cfg->tx_enabled;
fpe_cfg->verify_time = cfg->verify_time;
fpe_cfg->verify_enabled = cfg->verify_enabled;
- fpe_cfg->verify_limit = 3; /* IEEE 802.3 constant */
if (!cfg->verify_enabled)
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index fa74504f3ad5..a88ec40c4b6d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -7405,6 +7405,7 @@ void stmmac_fpe_apply(struct stmmac_priv *priv)
fpe_cfg->pmac_enabled);
} else {
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL;
+ fpe_cfg->verify_limit = 3; /* IEEE 802.3 constant */
stmmac_fpe_verify_timer_arm(fpe_cfg);
}
}
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/7] net: stmmac: refactor FPE verification process
2024-08-20 9:38 ` [PATCH net-next v4 3/7] net: stmmac: refactor FPE verification process Furong Xu
2024-08-20 12:34 ` Vladimir Oltean
@ 2024-08-20 14:36 ` Alexander Lobakin
1 sibling, 0 replies; 18+ messages in thread
From: Alexander Lobakin @ 2024-08-20 14:36 UTC (permalink / raw)
To: Furong Xu
Cc: Serge Semin, Andrew Lunn, Vladimir Oltean, David S. Miller,
Alexandre Torgue, Jose Abreu, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Joao Pinto, netdev, linux-stm32,
linux-arm-kernel, linux-kernel, xfr
From: Furong Xu <0x1207@gmail.com>
Date: Tue, 20 Aug 2024 17:38:31 +0800
> Drop driver defined stmmac_fpe_state, and switch to common
> ethtool_mm_verify_status for local TX verification status.
>
> Local side and remote side verification processes are completely
> independent. There is no reason at all to keep a local state and
> a remote state.
>
> Add a spinlock to avoid races among ISR, workqueue, link update
> and register configuration.
>
> Signed-off-by: Furong Xu <0x1207@gmail.com>
> ---
> drivers/net/ethernet/stmicro/stmmac/stmmac.h | 21 +--
> .../net/ethernet/stmicro/stmmac/stmmac_main.c | 172 ++++++++++--------
> .../net/ethernet/stmicro/stmmac/stmmac_tc.c | 6 -
> 3 files changed, 102 insertions(+), 97 deletions(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> index 458d6b16ce21..407b59f2783f 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> @@ -146,14 +146,6 @@ struct stmmac_channel {
> u32 index;
> };
>
> -/* 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,
> @@ -166,11 +158,16 @@ enum stmmac_fpe_task_state_t {
> };
>
> 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 */
> + /* 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 */
> + u32 verify_time; /* see ethtool_mm_state */
> + bool pmac_enabled; /* see ethtool_mm_state */
> + bool verify_enabled; /* see ethtool_mm_state */
> + enum ethtool_mm_verify_status status;
Why not embed ðtool_mm_state here then?
> };
>
> struct stmmac_tc_entry {
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 3072ad33b105..6ae95f20b24f 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -969,17 +969,21 @@ 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->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;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
> +
> + if (!fpe_cfg->pmac_enabled)
> + goto __unlock_out;
>
> - if (is_up && *hs_enable) {
> + if (is_up && fpe_cfg->verify_enabled)
> stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
> MPACKET_VERIFY);
> - } else {
> - *lo_state = FPE_STATE_OFF;
> - *lp_state = FPE_STATE_OFF;
> - }
> + else
> + fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
> +
> +__unlock_out:
Why underscores?
> + spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
> }
>
> static void stmmac_mac_link_down(struct phylink_config *config,
> @@ -4091,11 +4095,25 @@ static int stmmac_release(struct net_device *dev)
>
> stmmac_release_ptp(priv);
>
> - pm_runtime_put(priv->device);
> -
> - if (priv->dma_cap.fpesel)
> + if (priv->dma_cap.fpesel) {
> stmmac_fpe_stop_wq(priv);
>
> + /* stmmac_ethtool_ops.begin() guarantees that all ethtool
> + * requests to fail with EBUSY when !netif_running()
> + *
> + * Prepare some params here, then fpe_cfg can keep consistent
> + * with the register states after a SW reset by __stmmac_open().
> + */
> + priv->fpe_cfg.pmac_enabled = false;
> + priv->fpe_cfg.verify_enabled = false;
> + priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
> +
> + /* Reset MAC_FPE_CTRL_STS reg cache */
> + priv->fpe_cfg.fpe_csr = 0;
> + }
> +
> + pm_runtime_put(priv->device);
> +
> return 0;
> }
>
> @@ -5979,44 +5997,34 @@ 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->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;
>
> - if (status == FPE_EVENT_UNKNOWN || !*hs_enable)
> - return;
> + spin_lock(&priv->fpe_cfg.lock);
Is this ISR, so that you used the non-IRQ-safe variant?
>
> - /* 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;
[...]
> -#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)
> +static void stmmac_fpe_verify_task(struct work_struct *work)
> {
> struct stmmac_priv *priv = container_of(work, struct stmmac_priv,
> fpe_task);
> struct stmmac_fpe_cfg *fpe_cfg = &priv->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;
> -
> - while (retries-- > 0) {
> - /* Bail out immediately if FPE handshake is OFF */
> - if (*lo_state == FPE_STATE_OFF || !*hs_enable)
> + int verify_limit = 3; /* defined by 802.3 */
If it's a generic/IEEE definition, then either put it somewhere in the
generic headers or at least make a definition from it, doesn't open-code
directly.
> + unsigned long flags;
> + u32 sleep_ms;
> +
> + spin_lock(&priv->fpe_cfg.lock);
> + sleep_ms = fpe_cfg->verify_time;
> + spin_unlock(&priv->fpe_cfg.lock);
> +
> + while (1) {
> + /* The initial VERIFY was triggered by linkup event or
> + * stmmac_set_mm(), sleep then check MM_VERIFY_STATUS.
> + */
> + msleep(sleep_ms);
> +
> + if (!netif_running(priv->dev))
> break;
>
> - 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);
> + spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
>
> - netdev_info(priv->dev, "configured FPE\n");
> + if (fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_DISABLED ||
> + fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||
> + !fpe_cfg->pmac_enabled || !fpe_cfg->verify_enabled) {
> + spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
> + break;
> + }
>
> - *lo_state = FPE_STATE_ON;
> - *lp_state = FPE_STATE_ON;
> - netdev_info(priv->dev, "!!! BOTH FPE stations ON\n");
> + if (verify_limit == 0) {
> + fpe_cfg->verify_enabled = false;
> + fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
> + stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
> + priv->plat->tx_queues_to_use,
> + priv->plat->rx_queues_to_use,
> + false);
> + spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
> 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);
> - stmmac_fpe_send_mpacket(priv, priv->ioaddr,
> - fpe_cfg,
> + if (fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING)
> + stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
> MPACKET_VERIFY);
> - }
> - /* Sleep then retry */
> - msleep(500);
> +
> + sleep_ms = fpe_cfg->verify_time;
> +
> + spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
> +
> + verify_limit--;
Are these 3 empty newlines needed? I'd remove at least some of them.
> }
>
> clear_bit(__FPE_TASK_SCHED, &priv->fpe_task_state);
> @@ -7535,8 +7550,8 @@ 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);
> + /* Initialize FPE verify workqueue */
> + INIT_WORK(&priv->fpe_task, stmmac_fpe_verify_task);
>
> /* Override with kernel parameters if supplied XXX CRS XXX
> * this needs to have multiple instances
> @@ -7702,6 +7717,12 @@ int stmmac_dvr_probe(struct device *device,
>
> mutex_init(&priv->lock);
>
> + spin_lock_init(&priv->fpe_cfg.lock);
> + priv->fpe_cfg.pmac_enabled = false;
I think it's kzalloc()'d? If so, why initialize booleans to false?
> + priv->fpe_cfg.verify_time = 128; /* ethtool_mm_state.max_verify_time */
Same as verify_limit above, make it a definition, don't open-code.
> + priv->fpe_cfg.verify_enabled = false;
> + priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
> +
> /* 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
> @@ -7875,15 +7896,8 @@ int stmmac_suspend(struct device *dev)
> }
> rtnl_unlock();
>
> - if (priv->dma_cap.fpesel) {
> - /* Disable FPE */
> - stmmac_fpe_configure(priv, priv->ioaddr,
> - &priv->fpe_cfg,
> - priv->plat->tx_queues_to_use,
> - priv->plat->rx_queues_to_use, false);
> -
> + if (priv->dma_cap.fpesel)
> stmmac_fpe_stop_wq(priv);
> - }
>
> priv->speed = SPEED_UNKNOWN;
> return 0;
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
> index b0cc45331ff7..783829a6479c 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
> @@ -1063,11 +1063,6 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
> return -EOPNOTSUPP;
> }
>
> - /* Actual FPE register configuration will be done after FPE handshake
> - * is success.
> - */
> - priv->fpe_cfg.enable = fpe;
> -
> ret = stmmac_est_configure(priv, priv, priv->est,
> priv->plat->clk_ptp_rate);
> mutex_unlock(&priv->est_lock);
> @@ -1094,7 +1089,6 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
> mutex_unlock(&priv->est_lock);
> }
>
> - priv->fpe_cfg.enable = false;
> stmmac_fpe_configure(priv, priv->ioaddr,
> &priv->fpe_cfg,
> priv->plat->tx_queues_to_use,
Thanks,
Olek
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 4/7] net: stmmac: configure FPE via ethtool-mm
2024-08-20 9:38 ` [PATCH net-next v4 4/7] net: stmmac: configure FPE via ethtool-mm Furong Xu
@ 2024-08-20 14:48 ` Alexander Lobakin
0 siblings, 0 replies; 18+ messages in thread
From: Alexander Lobakin @ 2024-08-20 14:48 UTC (permalink / raw)
To: Furong Xu
Cc: Serge Semin, Andrew Lunn, Vladimir Oltean, David S. Miller,
Alexandre Torgue, Jose Abreu, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Joao Pinto, netdev, linux-stm32,
linux-arm-kernel, linux-kernel, xfr
From: Furong Xu <0x1207@gmail.com>
Date: Tue, 20 Aug 2024 17:38:32 +0800
> Implement ethtool --show-mm and --set-mm callbacks.
>
> NIC up/down, link up/down, suspend/resume, kselftest-ethtool_mm,
> all tested okay.
>
> Signed-off-by: Furong Xu <0x1207@gmail.com>
[...]
> @@ -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 */
> + (void)readl(ioaddr + MAC_FPE_CTRL_STS);
Are you sure this cast to void is needed? Have you seen readl() with
__must_check anywhere?
> +
> + 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)
> @@ -638,3 +653,20 @@ 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(void __iomem *ioaddr)
@ioaddr can be const.
> +{
> + return FIELD_GET(AFSZ, 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);
> +
> + value &= ~AFSZ;
> + value |= FIELD_PREP(AFSZ, add_frag_size);
> +
> + writel(value, ioaddr + MTL_FPE_CTRL_STS);
value = readl(ioaddr + MTL_FPE_CTRL_STS);
writel(u32_replace_bits(value, add_frag_size, AFSZ),
ioaddr + MTL_FPE_CTRL_STS);
> +}
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
> index bf33a51d229e..e369e65920fc 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
> @@ -39,6 +39,9 @@
> #define MAC_PPSx_INTERVAL(x) (0x00000b88 + ((x) * 0x10))
> #define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10))
>
> +#define MTL_FPE_CTRL_STS 0x00000c90
> +#define AFSZ GENMASK(1, 0)
Can you leave comments next to definitions explaining what this is?
I guessed AFSZ is "added frag size", but meh...
Also, I'd prefix every definition with some vendor prefix (STMMAC_ or
so), otherwise it may conflict one day with some generic one.
> +
> #define MTL_RXP_CONTROL_STATUS 0x00000ca0
> #define RXPI BIT(31)
> #define NPE GENMASK(23, 16)
[...]
> @@ -1270,6 +1271,112 @@ 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 add_frag_size;
> +
> + if (!priv->dma_cap.fpesel)
> + return -EOPNOTSUPP;
> +
> + spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
> +
> + state->pmac_enabled = priv->fpe_cfg.pmac_enabled;
> + state->verify_time = priv->fpe_cfg.verify_time;
> + state->verify_enabled = priv->fpe_cfg.verify_enabled;
> + state->verify_status = priv->fpe_cfg.status;
See, you could embed ðtool_mm_state into &fpe_cfg as I wrote under
the previous patch, so that you could do a direct assignment here :D
> + state->rx_min_frag_size = ETH_ZLEN;
> +
> + /* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime
> + * variable has a range between 1 and 128 ms inclusive. Limit to that.
> + */
Also make it a definition.
> + state->max_verify_time = 128;
> +
> + /* Cannot read MAC_FPE_CTRL_STS register here, or FPE interrupt events
> + * can be lost.
> + *
> + * See commit 37e4b8df27bc ("net: stmmac: fix FPE events losing")
I think it's not needed to leave commit references in the code?
> + */
> + state->tx_enabled = !!(priv->fpe_cfg.fpe_csr == EFPE);
tx_enabled is bool, you don't need to add a double negation here (the
parenthesis are redundant as well).
> +
> + /* FPE active if common tx_enabled and verification success or disabled (forced) */
> + state->tx_active = state->tx_enabled &&
> + (state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||
> + state->verify_status == ETHTOOL_MM_VERIFY_STATUS_DISABLED);
> +
> + add_frag_size = stmmac_fpe_get_add_frag_size(priv, priv->ioaddr);
> + state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(add_frag_size);
> +
> + spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
> +
> + return 0;
> +}
[...]
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 6ae95f20b24f..00ed0543f5cf 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -3537,8 +3537,21 @@ 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)
> + if (priv->dma_cap.fpesel) {
> + /* A SW reset just happened in stmmac_init_dma_engine(),
> + * we should restore fpe_cfg to HW, or FPE will stop working
> + * from suspend/resume.
> + */
> + spin_lock(&priv->fpe_cfg.lock);
I don't think this happens in the interrupt context, so you need
_irqsave() version here?
> + stmmac_fpe_configure(priv, priv->ioaddr,
> + &priv->fpe_cfg,
> + priv->plat->tx_queues_to_use,
> + priv->plat->rx_queues_to_use,
> + false, priv->fpe_cfg.pmac_enabled);
> + spin_unlock(&priv->fpe_cfg.lock);
> +
> stmmac_fpe_start_wq(priv);
> + }
>
> return 0;
> }
> @@ -7417,7 +7430,7 @@ static void stmmac_fpe_verify_task(struct work_struct *work)
> stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
> priv->plat->tx_queues_to_use,
> priv->plat->rx_queues_to_use,
> - false);
> + false, fpe_cfg->pmac_enabled);
> spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
> break;
> }
[...]
Thanks,
Olek
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 5/7] net: stmmac: support fp parameter of tc-mqprio
2024-08-20 9:38 ` [PATCH net-next v4 5/7] net: stmmac: support fp parameter of tc-mqprio Furong Xu
2024-08-20 9:51 ` Vladimir Oltean
@ 2024-08-20 15:00 ` Alexander Lobakin
1 sibling, 0 replies; 18+ messages in thread
From: Alexander Lobakin @ 2024-08-20 15:00 UTC (permalink / raw)
To: Furong Xu
Cc: Serge Semin, Andrew Lunn, Vladimir Oltean, David S. Miller,
Alexandre Torgue, Jose Abreu, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Joao Pinto, netdev, linux-stm32,
linux-arm-kernel, linux-kernel, xfr
From: Furong Xu <0x1207@gmail.com>
Date: Tue, 20 Aug 2024 17:38:33 +0800
> tc-mqprio can select whether traffic classes are express or preemptible.
>
> After some traffic tests, MAC merge layer statistics are all good.
[...]
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
> index 4c91fa766b13..1e87dbc9a406 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
> @@ -670,3 +670,55 @@ void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size)
>
> writel(value, ioaddr + MTL_FPE_CTRL_STS);
> }
> +
> +int dwmac5_fpe_set_preemptible_tcs(struct net_device *ndev,
> + struct netlink_ext_ack *extack,
> + unsigned long tcs)
> +{
> + struct stmmac_priv *priv = netdev_priv(ndev);
Can't it be const?
> + void __iomem *ioaddr = priv->ioaddr;
> + unsigned long queue_tcs = 0;
Why is @tcs and @queue_tcs unsigned long? You write @queue_tcs via
writel(), IOW it can't go past %U32_MAX.
> + int num_tc = ndev->num_tc;
> + u32 value, queue_weight;
> + u16 offset, count;
Just use u32 here for all three.
> + int tc, i;
> +
> + if (!tcs)
> + goto __update_queue_tcs;
> +
> + for (tc = 0; tc < num_tc; tc++) {
@tc can be declared right here in the loop declaration.
Also it's u32 as it can't be negative.
> + count = ndev->tc_to_txq[tc].count;
> + offset = ndev->tc_to_txq[tc].offset;
> +
> + if (tcs & BIT(tc))
> + queue_tcs |= 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, "TX algorithm SP is not suitable for one TC to multiple TXQs mapping");
> + return -EINVAL;
> + }
> +
> + queue_weight = priv->plat->tx_queues_cfg[offset].weight;
> + for (i = 1; i < count; i++) {
Same as with @tc for everything.
> + if (queue_weight != priv->plat->tx_queues_cfg[offset + i].weight) {
> + NL_SET_ERR_MSG_FMT_MOD(extack, "TXQ weight [%u] differs across other TXQs in TC: [%u]",
> + queue_weight, tc);
> + return -EINVAL;
> + }
> + }
> + }
> +
> +__update_queue_tcs:
Again underscores.
> + value = readl(ioaddr + MTL_FPE_CTRL_STS);
> +
> + value &= ~PEC;
> + value |= FIELD_PREP(PEC, queue_tcs);
> +
> + writel(value, ioaddr + MTL_FPE_CTRL_STS);
These are also u32_replace_bits() as in the previous patch.
> +
> + return 0;
> +}
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
> index e369e65920fc..d3191c48354d 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
> @@ -40,6 +40,7 @@
> #define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10))
>
> #define MTL_FPE_CTRL_STS 0x00000c90
> +#define PEC GENMASK(15, 8)
Again some driver prefix would be nice to see.
> #define AFSZ GENMASK(1, 0)
>
> #define MTL_RXP_CONTROL_STATUS 0x00000ca0
[...]
> @@ -1174,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;
Why not base->caps->blah directly? I think it would fit 80 cols?
> +
> + return 0;
> + }
> case TC_SETUP_QDISC_TAPRIO: {
> struct tc_taprio_caps *caps = base->caps;
>
> @@ -1190,6 +1198,78 @@ 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_set_preemptible_tcs(priv, ndev, extack, 0);
> +}
> +
> +static int tc_setup_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;
> + struct net_device *ndev = priv->dev;
> + int num_stack_tx_queues = 0;
> + int num_tc = qopt->num_tc;
> + u16 offset, count;
Also u32 for most of these.
> + int tc, err;
> +
> + if (!num_tc) {
> + stmmac_reset_tc_mqprio(ndev, extack);
> + return 0;
> + }
> +
> + if (mqprio->preemptible_tcs && !ethtool_dev_mm_supported(ndev)) {
> + NL_SET_ERR_MSG_MOD(extack, "Device does not support preemption");
> + return -EOPNOTSUPP;
> + }
> +
> + err = netdev_set_num_tc(ndev, num_tc);
> + if (err)
> + return err;
> +
> + /* DWMAC CORE4+ can not programming TC:TXQ mapping to hardware.
"can't program" or "can't do programming" or "doesn't support programming".
> + * Synopsys Databook:
> + * "The number of Tx DMA channels is equal to the number of Tx queues,
> + * and is direct one-to-one mapping."
> + *
> + * Luckily, DWXGMAC CORE can.
> + *
> + * Thus preemptible_tcs should be handled in a per core manner.
> + */
[...]
Thanks,
Olek
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/7] net: stmmac: refactor FPE verification process
2024-08-20 12:34 ` Vladimir Oltean
2024-08-20 12:52 ` Vladimir Oltean
@ 2024-08-21 4:58 ` Furong Xu
2024-08-21 10:27 ` Vladimir Oltean
1 sibling, 1 reply; 18+ messages in thread
From: Furong Xu @ 2024-08-21 4:58 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Serge Semin, Andrew Lunn, David S. Miller, Alexandre Torgue,
Jose Abreu, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Maxime Coquelin, Joao Pinto, netdev, linux-stm32,
linux-arm-kernel, linux-kernel, xfr
Hi Vladimir
On Tue, 20 Aug 2024 15:34:56 +0300, Vladimir Oltean <olteanv@gmail.com> wrote:
> I took the liberty of rewriting the fpe_task to a timer, and delete the
> workqueue. Here is a completely untested patch, which at least is less
> complex, has less code and is easier to understand. What do you think?
>
Your patch is much better than my ugly implementation ;)
Some small fixes are required to make kselftest-ethtool_mm pass.
Would you mind if I rebase you patch, fix some small issues, make sure all
test cases pass, split it into two patches and include them in my patchset,
then send to review as a Co-developer and a tester?
Thanks.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/7] net: stmmac: refactor FPE verification process
2024-08-21 4:58 ` Furong Xu
@ 2024-08-21 10:27 ` Vladimir Oltean
0 siblings, 0 replies; 18+ messages in thread
From: Vladimir Oltean @ 2024-08-21 10:27 UTC (permalink / raw)
To: Furong Xu
Cc: Serge Semin, Andrew Lunn, David S. Miller, Alexandre Torgue,
Jose Abreu, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Maxime Coquelin, Joao Pinto, netdev, linux-stm32,
linux-arm-kernel, linux-kernel, xfr
On Wed, Aug 21, 2024 at 12:58:33PM +0800, Furong Xu wrote:
>
> Hi Vladimir
>
> On Tue, 20 Aug 2024 15:34:56 +0300, Vladimir Oltean <olteanv@gmail.com> wrote:
> > I took the liberty of rewriting the fpe_task to a timer, and delete the
> > workqueue. Here is a completely untested patch, which at least is less
> > complex, has less code and is easier to understand. What do you think?
> >
>
> Your patch is much better than my ugly implementation ;)
Well, to be fair, it took us a number of iterations to properly see how
much it could be simplified.
> Some small fixes are required to make kselftest-ethtool_mm pass.
>
> Would you mind if I rebase you patch, fix some small issues, make sure all
> test cases pass, split it into two patches and include them in my patchset,
> then send to review as a Co-developer and a tester?
Please feel free to split up that patch and squash it into your patches,
keeping your Author: field and just a Co-developed-by: + Signed-off-by:
for me, where parts of that patch helped you.
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2024-08-21 10:28 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-20 9:38 [PATCH net-next v4 0/7] net: stmmac: FPE via ethtool + tc Furong Xu
2024-08-20 9:38 ` [PATCH net-next v4 1/7] net: stmmac: move stmmac_fpe_cfg to stmmac_priv data Furong Xu
2024-08-20 9:55 ` Vladimir Oltean
2024-08-20 9:38 ` [PATCH net-next v4 2/7] net: stmmac: drop stmmac_fpe_handshake Furong Xu
2024-08-20 9:56 ` Vladimir Oltean
2024-08-20 9:38 ` [PATCH net-next v4 3/7] net: stmmac: refactor FPE verification process Furong Xu
2024-08-20 12:34 ` Vladimir Oltean
2024-08-20 12:52 ` Vladimir Oltean
2024-08-21 4:58 ` Furong Xu
2024-08-21 10:27 ` Vladimir Oltean
2024-08-20 14:36 ` Alexander Lobakin
2024-08-20 9:38 ` [PATCH net-next v4 4/7] net: stmmac: configure FPE via ethtool-mm Furong Xu
2024-08-20 14:48 ` Alexander Lobakin
2024-08-20 9:38 ` [PATCH net-next v4 5/7] net: stmmac: support fp parameter of tc-mqprio Furong Xu
2024-08-20 9:51 ` Vladimir Oltean
2024-08-20 15:00 ` Alexander Lobakin
2024-08-20 9:38 ` [PATCH net-next v4 6/7] net: stmmac: support fp parameter of tc-taprio Furong Xu
2024-08-20 9:38 ` [PATCH net-next v4 7/7] net: stmmac: silence FPE kernel logs Furong Xu
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.