net: stmmac: Introduce separate files for FPE implementation

By moving FPE related code info separate files, FPE implementation
becomes a separate module initially.
No functional change intended.

Signed-off-by: Furong Xu <0x1207@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Link: https://patch.msgid.link/e9ddf4fbf0fc053ae30592aa6c4363e72a4d8e62.1730449003.git.0x1207@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Furong Xu 2024-11-01 21:31:28 +08:00 committed by Jakub Kicinski
parent 72ea418bd7
commit 2c6ad81de1
11 changed files with 405 additions and 363 deletions

View File

@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o \
dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
stmmac_xdp.o stmmac_est.o \
stmmac_xdp.o stmmac_est.o stmmac_fpe.o \
$(stmmac-y)
stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o

View File

@ -16,6 +16,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include "stmmac.h"
#include "stmmac_fpe.h"
#include "stmmac_pcs.h"
#include "dwmac4.h"
#include "dwmac5.h"

View File

@ -572,153 +572,3 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
writel(val, ioaddr + MAC_PPS_CONTROL);
return 0;
}
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool tx_enable, bool pmac_enable)
{
u32 value;
if (tx_enable) {
cfg->fpe_csr = EFPE;
value = readl(ioaddr + GMAC_RXQ_CTRL1);
value &= ~GMAC_RXQCTRL_FPRQ;
value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
writel(value, ioaddr + GMAC_RXQ_CTRL1);
} else {
cfg->fpe_csr = 0;
}
writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS);
value = readl(ioaddr + GMAC_INT_EN);
if (pmac_enable) {
if (!(value & GMAC_INT_FPE_EN)) {
/* Dummy read to clear any pending masked interrupts */
readl(ioaddr + MAC_FPE_CTRL_STS);
value |= GMAC_INT_FPE_EN;
}
} else {
value &= ~GMAC_INT_FPE_EN;
}
writel(value, ioaddr + GMAC_INT_EN);
}
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
{
u32 value;
int status;
status = FPE_EVENT_UNKNOWN;
/* Reads from the MAC_FPE_CTRL_STS register should only be performed
* here, since the status flags of MAC_FPE_CTRL_STS are "clear on read"
*/
value = readl(ioaddr + MAC_FPE_CTRL_STS);
if (value & TRSP) {
status |= FPE_EVENT_TRSP;
netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n");
}
if (value & TVER) {
status |= FPE_EVENT_TVER;
netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n");
}
if (value & RRSP) {
status |= FPE_EVENT_RRSP;
netdev_dbg(dev, "FPE: Respond mPacket is received\n");
}
if (value & RVER) {
status |= FPE_EVENT_RVER;
netdev_dbg(dev, "FPE: Verify mPacket is received\n");
}
return status;
}
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
enum stmmac_mpacket_type type)
{
u32 value = cfg->fpe_csr;
if (type == MPACKET_VERIFY)
value |= SVER;
else if (type == MPACKET_RESPONSE)
value |= SRSP;
writel(value, ioaddr + MAC_FPE_CTRL_STS);
}
int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr)
{
return FIELD_GET(DWMAC5_ADD_FRAG_SZ, readl(ioaddr + MTL_FPE_CTRL_STS));
}
void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size)
{
u32 value;
value = readl(ioaddr + MTL_FPE_CTRL_STS);
writel(u32_replace_bits(value, add_frag_size, DWMAC5_ADD_FRAG_SZ),
ioaddr + MTL_FPE_CTRL_STS);
}
#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping"
#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]"
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
struct netlink_ext_ack *extack, u32 pclass)
{
u32 val, offset, count, queue_weight, preemptible_txqs = 0;
struct stmmac_priv *priv = netdev_priv(ndev);
u32 num_tc = ndev->num_tc;
if (!pclass)
goto update_mapping;
/* DWMAC CORE4+ can not program TC:TXQ mapping to hardware.
*
* Synopsys Databook:
* "The number of Tx DMA channels is equal to the number of Tx queues,
* and is direct one-to-one mapping."
*/
for (u32 tc = 0; tc < num_tc; tc++) {
count = ndev->tc_to_txq[tc].count;
offset = ndev->tc_to_txq[tc].offset;
if (pclass & BIT(tc))
preemptible_txqs |= GENMASK(offset + count - 1, offset);
/* This is 1:1 mapping, go to next TC */
if (count == 1)
continue;
if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) {
NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
return -EINVAL;
}
queue_weight = priv->plat->tx_queues_cfg[offset].weight;
for (u32 i = 1; i < count; i++) {
if (priv->plat->tx_queues_cfg[offset + i].weight !=
queue_weight) {
NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG,
queue_weight, tc);
return -EINVAL;
}
}
}
update_mapping:
val = readl(priv->ioaddr + MTL_FPE_CTRL_STS);
writel(u32_replace_bits(val, preemptible_txqs, DWMAC5_PREEMPTION_CLASS),
priv->ioaddr + MTL_FPE_CTRL_STS);
return 0;
}

View File

@ -11,15 +11,6 @@
#define PRTYEN BIT(1)
#define TMOUTEN BIT(0)
#define MAC_FPE_CTRL_STS 0x00000234
#define TRSP BIT(19)
#define TVER BIT(18)
#define RRSP BIT(17)
#define RVER BIT(16)
#define SRSP BIT(2)
#define SVER BIT(1)
#define EFPE BIT(0)
#define MAC_PPS_CONTROL 0x00000b70
#define PPS_MAXIDX(x) ((((x) + 1) * 8) - 1)
#define PPS_MINIDX(x) ((x) * 8)
@ -39,12 +30,6 @@
#define MAC_PPSx_INTERVAL(x) (0x00000b88 + ((x) * 0x10))
#define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10))
#define MTL_FPE_CTRL_STS 0x00000c90
/* Preemption Classification */
#define DWMAC5_PREEMPTION_CLASS GENMASK(15, 8)
/* Additional Fragment Size of preempted frames */
#define DWMAC5_ADD_FRAG_SZ GENMASK(1, 0)
#define MTL_RXP_CONTROL_STATUS 0x00000ca0
#define RXPI BIT(31)
#define NPE GENMASK(23, 16)
@ -108,16 +93,5 @@ int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
struct stmmac_pps_cfg *cfg, bool enable,
u32 sub_second_inc, u32 systime_flags);
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool tx_enable, bool pmac_enable);
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
struct stmmac_fpe_cfg *cfg,
enum stmmac_mpacket_type type);
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev);
int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr);
void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size);
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
struct netlink_ext_ack *extack, u32 pclass);
#endif /* __DWMAC5_H__ */

View File

@ -193,8 +193,6 @@
#define XGMAC_MDIO_ADDR 0x00000200
#define XGMAC_MDIO_DATA 0x00000204
#define XGMAC_MDIO_C22P 0x00000220
#define XGMAC_FPE_CTRL_STS 0x00000280
#define XGMAC_EFPE BIT(0)
#define XGMAC_ADDRx_HIGH(x) (0x00000300 + (x) * 0x8)
#define XGMAC_ADDR_MAX 32
#define XGMAC_AE BIT(31)

View File

@ -8,6 +8,7 @@
#include <linux/crc32.h>
#include <linux/iopoll.h>
#include "stmmac.h"
#include "stmmac_fpe.h"
#include "stmmac_ptp.h"
#include "dwxlgmac2.h"
#include "dwxgmac2.h"
@ -1504,32 +1505,6 @@ static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en,
writel(value, ioaddr + XGMAC_RX_CONFIG);
}
static void dwxgmac3_fpe_configure(void __iomem *ioaddr,
struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool tx_enable, bool pmac_enable)
{
u32 value;
if (!tx_enable) {
value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
value &= ~XGMAC_EFPE;
writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
return;
}
value = readl(ioaddr + XGMAC_RXQ_CTRL1);
value &= ~XGMAC_RQ;
value |= (num_rxq - 1) << XGMAC_RQ_SHIFT;
writel(value, ioaddr + XGMAC_RXQ_CTRL1);
value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
value |= XGMAC_EFPE;
writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
}
const struct stmmac_ops dwxgmac210_ops = {
.core_init = dwxgmac2_core_init,
.set_mac = dwxgmac2_set_mac,

View File

@ -146,15 +146,6 @@ struct stmmac_channel {
u32 index;
};
/* FPE link-partner hand-shaking mPacket type */
enum stmmac_mpacket_type {
MPACKET_VERIFY = 0,
MPACKET_RESPONSE = 1,
};
#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES 3
#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS 128
struct stmmac_fpe_cfg {
/* Serialize access to MAC Merge state between ethtool requests
* and link state updates.
@ -420,7 +411,6 @@ bool stmmac_eee_init(struct stmmac_priv *priv);
int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size);
int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled);
void stmmac_fpe_apply(struct stmmac_priv *priv);
static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv)
{

View File

@ -17,9 +17,9 @@
#include <linux/net_tstamp.h>
#include "stmmac.h"
#include "stmmac_fpe.h"
#include "dwmac_dma.h"
#include "dwxgmac2.h"
#include "dwmac5.h"
#define REG_SPACE_SIZE 0x1060
#define GMAC4_REG_SPACE_SIZE 0x116C

View File

@ -0,0 +1,354 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2024 Furong Xu <0x1207@gmail.com>
* stmmac FPE(802.3 Qbu) handling
*/
#include "stmmac.h"
#include "stmmac_fpe.h"
#include "dwmac4.h"
#include "dwmac5.h"
#include "dwxgmac2.h"
#define MAC_FPE_CTRL_STS 0x00000234
#define TRSP BIT(19)
#define TVER BIT(18)
#define RRSP BIT(17)
#define RVER BIT(16)
#define SRSP BIT(2)
#define SVER BIT(1)
#define EFPE BIT(0)
#define MTL_FPE_CTRL_STS 0x00000c90
/* Preemption Classification */
#define DWMAC5_PREEMPTION_CLASS GENMASK(15, 8)
/* Additional Fragment Size of preempted frames */
#define DWMAC5_ADD_FRAG_SZ GENMASK(1, 0)
#define XGMAC_FPE_CTRL_STS 0x00000280
#define XGMAC_EFPE BIT(0)
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool tx_enable, bool pmac_enable)
{
u32 value;
if (tx_enable) {
cfg->fpe_csr = EFPE;
value = readl(ioaddr + GMAC_RXQ_CTRL1);
value &= ~GMAC_RXQCTRL_FPRQ;
value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
writel(value, ioaddr + GMAC_RXQ_CTRL1);
} else {
cfg->fpe_csr = 0;
}
writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS);
value = readl(ioaddr + GMAC_INT_EN);
if (pmac_enable) {
if (!(value & GMAC_INT_FPE_EN)) {
/* Dummy read to clear any pending masked interrupts */
readl(ioaddr + MAC_FPE_CTRL_STS);
value |= GMAC_INT_FPE_EN;
}
} else {
value &= ~GMAC_INT_FPE_EN;
}
writel(value, ioaddr + GMAC_INT_EN);
}
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
enum stmmac_mpacket_type type)
{
u32 value = cfg->fpe_csr;
if (type == MPACKET_VERIFY)
value |= SVER;
else if (type == MPACKET_RESPONSE)
value |= SRSP;
writel(value, ioaddr + MAC_FPE_CTRL_STS);
}
void stmmac_fpe_event_status(struct stmmac_priv *priv, int status)
{
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
/* This is interrupt context, just spin_lock() */
spin_lock(&fpe_cfg->lock);
if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN)
goto unlock_out;
/* LP has sent verify mPacket */
if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER)
stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
MPACKET_RESPONSE);
/* Local has sent verify mPacket */
if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER &&
fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED)
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING;
/* LP has sent response mPacket */
if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP &&
fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING)
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
unlock_out:
spin_unlock(&fpe_cfg->lock);
}
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
{
u32 value;
int status;
status = FPE_EVENT_UNKNOWN;
/* Reads from the MAC_FPE_CTRL_STS register should only be performed
* here, since the status flags of MAC_FPE_CTRL_STS are "clear on read"
*/
value = readl(ioaddr + MAC_FPE_CTRL_STS);
if (value & TRSP) {
status |= FPE_EVENT_TRSP;
netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n");
}
if (value & TVER) {
status |= FPE_EVENT_TVER;
netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n");
}
if (value & RRSP) {
status |= FPE_EVENT_RRSP;
netdev_dbg(dev, "FPE: Respond mPacket is received\n");
}
if (value & RVER) {
status |= FPE_EVENT_RVER;
netdev_dbg(dev, "FPE: Verify mPacket is received\n");
}
return status;
}
/**
* stmmac_fpe_verify_timer - Timer for MAC Merge verification
* @t: timer_list struct containing private info
*
* Verify the MAC Merge capability in the local TX direction, by
* transmitting Verify mPackets up to 3 times. Wait until link
* partner responds with a Response mPacket, otherwise fail.
*/
static void stmmac_fpe_verify_timer(struct timer_list *t)
{
struct stmmac_fpe_cfg *fpe_cfg = from_timer(fpe_cfg, t, verify_timer);
struct stmmac_priv *priv = container_of(fpe_cfg, struct stmmac_priv,
fpe_cfg);
unsigned long flags;
bool rearm = false;
spin_lock_irqsave(&fpe_cfg->lock, flags);
switch (fpe_cfg->status) {
case ETHTOOL_MM_VERIFY_STATUS_INITIAL:
case ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
if (fpe_cfg->verify_retries != 0) {
stmmac_fpe_send_mpacket(priv, priv->ioaddr,
fpe_cfg, MPACKET_VERIFY);
rearm = true;
} else {
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
}
fpe_cfg->verify_retries--;
break;
case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED:
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use,
true, true);
break;
default:
break;
}
if (rearm) {
mod_timer(&fpe_cfg->verify_timer,
jiffies + msecs_to_jiffies(fpe_cfg->verify_time));
}
spin_unlock_irqrestore(&fpe_cfg->lock, flags);
}
static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg)
{
if (fpe_cfg->pmac_enabled && fpe_cfg->tx_enabled &&
fpe_cfg->verify_enabled &&
fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_FAILED &&
fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) {
timer_setup(&fpe_cfg->verify_timer, stmmac_fpe_verify_timer, 0);
mod_timer(&fpe_cfg->verify_timer, jiffies);
}
}
void stmmac_fpe_init(struct stmmac_priv *priv)
{
priv->fpe_cfg.verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
priv->fpe_cfg.verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS;
priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0);
spin_lock_init(&priv->fpe_cfg.lock);
}
void stmmac_fpe_apply(struct stmmac_priv *priv)
{
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
/* If verification is disabled, configure FPE right away.
* Otherwise let the timer code do it.
*/
if (!fpe_cfg->verify_enabled) {
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use,
fpe_cfg->tx_enabled,
fpe_cfg->pmac_enabled);
} else {
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL;
fpe_cfg->verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
if (netif_running(priv->dev))
stmmac_fpe_verify_timer_arm(fpe_cfg);
}
}
void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
{
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
unsigned long flags;
timer_shutdown_sync(&fpe_cfg->verify_timer);
spin_lock_irqsave(&fpe_cfg->lock, flags);
if (is_up && fpe_cfg->pmac_enabled) {
/* VERIFY process requires pmac enabled when NIC comes up */
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use,
false, true);
/* New link => maybe new partner => new verification process */
stmmac_fpe_apply(priv);
} else {
/* No link => turn off EFPE */
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use,
false, false);
}
spin_unlock_irqrestore(&fpe_cfg->lock, flags);
}
int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr)
{
return FIELD_GET(DWMAC5_ADD_FRAG_SZ, readl(ioaddr + MTL_FPE_CTRL_STS));
}
void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size)
{
u32 value;
value = readl(ioaddr + MTL_FPE_CTRL_STS);
writel(u32_replace_bits(value, add_frag_size, DWMAC5_ADD_FRAG_SZ),
ioaddr + MTL_FPE_CTRL_STS);
}
#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping"
#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]"
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
struct netlink_ext_ack *extack, u32 pclass)
{
u32 val, offset, count, queue_weight, preemptible_txqs = 0;
struct stmmac_priv *priv = netdev_priv(ndev);
u32 num_tc = ndev->num_tc;
if (!pclass)
goto update_mapping;
/* DWMAC CORE4+ can not program TC:TXQ mapping to hardware.
*
* Synopsys Databook:
* "The number of Tx DMA channels is equal to the number of Tx queues,
* and is direct one-to-one mapping."
*/
for (u32 tc = 0; tc < num_tc; tc++) {
count = ndev->tc_to_txq[tc].count;
offset = ndev->tc_to_txq[tc].offset;
if (pclass & BIT(tc))
preemptible_txqs |= GENMASK(offset + count - 1, offset);
/* This is 1:1 mapping, go to next TC */
if (count == 1)
continue;
if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) {
NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
return -EINVAL;
}
queue_weight = priv->plat->tx_queues_cfg[offset].weight;
for (u32 i = 1; i < count; i++) {
if (priv->plat->tx_queues_cfg[offset + i].weight !=
queue_weight) {
NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG,
queue_weight, tc);
return -EINVAL;
}
}
}
update_mapping:
val = readl(priv->ioaddr + MTL_FPE_CTRL_STS);
writel(u32_replace_bits(val, preemptible_txqs, DWMAC5_PREEMPTION_CLASS),
priv->ioaddr + MTL_FPE_CTRL_STS);
return 0;
}
void dwxgmac3_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool tx_enable, bool pmac_enable)
{
u32 value;
if (!tx_enable) {
value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
value &= ~XGMAC_EFPE;
writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
return;
}
value = readl(ioaddr + XGMAC_RXQ_CTRL1);
value &= ~XGMAC_RQ;
value |= (num_rxq - 1) << XGMAC_RQ_SHIFT;
writel(value, ioaddr + XGMAC_RXQ_CTRL1);
value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
value |= XGMAC_EFPE;
writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
}

View File

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2024 Furong Xu <0x1207@gmail.com>
* stmmac FPE(802.3 Qbu) handling
*/
#ifndef _STMMAC_FPE_H_
#define _STMMAC_FPE_H_
#include <linux/types.h>
#include <linux/netdevice.h>
#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES 3
#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS 128
/* FPE link-partner hand-shaking mPacket type */
enum stmmac_mpacket_type {
MPACKET_VERIFY = 0,
MPACKET_RESPONSE = 1,
};
struct stmmac_priv;
struct stmmac_fpe_cfg;
void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up);
void stmmac_fpe_event_status(struct stmmac_priv *priv, int status);
void stmmac_fpe_init(struct stmmac_priv *priv);
void stmmac_fpe_apply(struct stmmac_priv *priv);
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool tx_enable, bool pmac_enable);
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
struct stmmac_fpe_cfg *cfg,
enum stmmac_mpacket_type type);
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev);
int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr);
void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size);
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
struct netlink_ext_ack *extack, u32 pclass);
void dwxgmac3_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool tx_enable, bool pmac_enable);
#endif

View File

@ -43,6 +43,7 @@
#include <net/pkt_cls.h>
#include <net/xdp_sock_drv.h>
#include "stmmac_ptp.h"
#include "stmmac_fpe.h"
#include "stmmac.h"
#include "stmmac_xdp.h"
#include <linux/reset.h>
@ -966,35 +967,6 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
/* Nothing to do, xpcs_config() handles everything */
}
static void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
{
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
unsigned long flags;
timer_shutdown_sync(&fpe_cfg->verify_timer);
spin_lock_irqsave(&fpe_cfg->lock, flags);
if (is_up && fpe_cfg->pmac_enabled) {
/* VERIFY process requires pmac enabled when NIC comes up */
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use,
false, true);
/* New link => maybe new partner => new verification process */
stmmac_fpe_apply(priv);
} else {
/* No link => turn off EFPE */
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use,
false, false);
}
spin_unlock_irqrestore(&fpe_cfg->lock, flags);
}
static void stmmac_mac_link_down(struct phylink_config *config,
unsigned int mode, phy_interface_t interface)
{
@ -5965,35 +5937,6 @@ static int stmmac_set_features(struct net_device *netdev,
return 0;
}
static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status)
{
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
/* This is interrupt context, just spin_lock() */
spin_lock(&fpe_cfg->lock);
if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN)
goto unlock_out;
/* LP has sent verify mPacket */
if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER)
stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
MPACKET_RESPONSE);
/* Local has sent verify mPacket */
if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER &&
fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED)
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING;
/* LP has sent response mPacket */
if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP &&
fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING)
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
unlock_out:
spin_unlock(&fpe_cfg->lock);
}
static void stmmac_common_interrupt(struct stmmac_priv *priv)
{
u32 rx_cnt = priv->plat->rx_queues_to_use;
@ -7349,90 +7292,6 @@ int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size)
return ret;
}
/**
* stmmac_fpe_verify_timer - Timer for MAC Merge verification
* @t: timer_list struct containing private info
*
* Verify the MAC Merge capability in the local TX direction, by
* transmitting Verify mPackets up to 3 times. Wait until link
* partner responds with a Response mPacket, otherwise fail.
*/
static void stmmac_fpe_verify_timer(struct timer_list *t)
{
struct stmmac_fpe_cfg *fpe_cfg = from_timer(fpe_cfg, t, verify_timer);
struct stmmac_priv *priv = container_of(fpe_cfg, struct stmmac_priv,
fpe_cfg);
unsigned long flags;
bool rearm = false;
spin_lock_irqsave(&fpe_cfg->lock, flags);
switch (fpe_cfg->status) {
case ETHTOOL_MM_VERIFY_STATUS_INITIAL:
case ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
if (fpe_cfg->verify_retries != 0) {
stmmac_fpe_send_mpacket(priv, priv->ioaddr,
fpe_cfg, MPACKET_VERIFY);
rearm = true;
} else {
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
}
fpe_cfg->verify_retries--;
break;
case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED:
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use,
true, true);
break;
default:
break;
}
if (rearm) {
mod_timer(&fpe_cfg->verify_timer,
jiffies + msecs_to_jiffies(fpe_cfg->verify_time));
}
spin_unlock_irqrestore(&fpe_cfg->lock, flags);
}
static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg)
{
if (fpe_cfg->pmac_enabled && fpe_cfg->tx_enabled &&
fpe_cfg->verify_enabled &&
fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_FAILED &&
fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) {
timer_setup(&fpe_cfg->verify_timer, stmmac_fpe_verify_timer, 0);
mod_timer(&fpe_cfg->verify_timer, jiffies);
}
}
void stmmac_fpe_apply(struct stmmac_priv *priv)
{
struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
/* If verification is disabled, configure FPE right away.
* Otherwise let the timer code do it.
*/
if (!fpe_cfg->verify_enabled) {
stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
priv->plat->tx_queues_to_use,
priv->plat->rx_queues_to_use,
fpe_cfg->tx_enabled,
fpe_cfg->pmac_enabled);
} else {
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL;
fpe_cfg->verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
if (netif_running(priv->dev))
stmmac_fpe_verify_timer_arm(fpe_cfg);
}
}
static int stmmac_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp)
{
const struct stmmac_xdp_buff *ctx = (void *)_ctx;
@ -7711,11 +7570,7 @@ int stmmac_dvr_probe(struct device *device,
mutex_init(&priv->lock);
priv->fpe_cfg.verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
priv->fpe_cfg.verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS;
priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0);
spin_lock_init(&priv->fpe_cfg.lock);
stmmac_fpe_init(priv);
/* If a specific clk_csr value is passed from the platform
* this means that the CSR Clock Range selection cannot be