Merge branch 'support-external-snapshots-on-dwmac1000'

Maxime Chevallier says:

====================
Support external snapshots on dwmac1000

The main change since v3 is the move of the fifo flush wait in the
ptp_clock_info enable() function within the mutex that protects the ptp
registers. Thanks Jakub and Paolo for spotting this.

This series also aggregates Daniel's reviews, except for the patch 4
which was modified since then.

This series is another take on the previous work [1] done by
Alexis Lothoré, that fixes the support for external snapshots
timestamping in GMAC3-based devices.

Details on why this is needed are mentionned on the cover [2] from V1.

[1]: https://lore.kernel.org/netdev/20230616100409.164583-1-alexis.lothore@bootlin.com/
[2]: https://lore.kernel.org/netdev/20241029115419.1160201-1-maxime.chevallier@bootlin.com/

Link to V1: https://lore.kernel.org/netdev/20241029115419.1160201-1-maxime.chevallier@bootlin.com/
Link to V2: https://lore.kernel.org/netdev/20241104170251.2202270-1-maxime.chevallier@bootlin.com/
Link to V3: https://lore.kernel.org/netdev/20241106090331.56519-1-maxime.chevallier@bootlin.com/
====================

Link: https://patch.msgid.link/20241112170658.2388529-1-maxime.chevallier@bootlin.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2024-11-13 18:52:16 -08:00
8 changed files with 196 additions and 11 deletions

View File

@@ -549,8 +549,12 @@ extern const struct stmmac_desc_ops ndesc_ops;
struct mac_device_info;
extern const struct stmmac_hwtimestamp stmmac_ptp;
extern const struct stmmac_hwtimestamp dwmac1000_ptp;
extern const struct stmmac_mode_ops dwmac4_ring_mode_ops;
extern const struct ptp_clock_info stmmac_ptp_clock_ops;
extern const struct ptp_clock_info dwmac1000_ptp_clock_ops;
struct mac_link {
u32 caps;
u32 speed_mask;

View File

@@ -485,6 +485,7 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
plat_dat->pcs_init = socfpga_dwmac_pcs_init;
plat_dat->pcs_exit = socfpga_dwmac_pcs_exit;
plat_dat->select_pcs = socfpga_dwmac_select_pcs;
plat_dat->has_gmac = true;
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret)

View File

@@ -329,5 +329,17 @@ enum rtc_control {
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
#define GMAC_EXTHASH_BASE 0x500
/* PTP and timestamping registers */
#define GMAC3_X_ATSNS GENMASK(19, 16)
#define GMAC3_X_ATSNS_SHIFT 16
#define GMAC_PTP_TCR_ATSFC BIT(24)
#define GMAC_PTP_TCR_ATSEN0 BIT(25)
#define GMAC3_X_TIMESTAMP_STATUS 0x28
#define GMAC_PTP_ATNR 0x30
#define GMAC_PTP_ATSR 0x34
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
#endif /* __DWMAC1000_H__ */

View File

@@ -18,6 +18,7 @@
#include <linux/io.h>
#include "stmmac.h"
#include "stmmac_pcs.h"
#include "stmmac_ptp.h"
#include "dwmac1000.h"
static void dwmac1000_core_init(struct mac_device_info *hw,
@@ -551,3 +552,103 @@ int dwmac1000_setup(struct stmmac_priv *priv)
return 0;
}
/* DWMAC 1000 HW Timestaming ops */
void dwmac1000_get_ptptime(void __iomem *ptpaddr, u64 *ptp_time)
{
u64 ns;
ns = readl(ptpaddr + GMAC_PTP_ATNR);
ns += readl(ptpaddr + GMAC_PTP_ATSR) * NSEC_PER_SEC;
*ptp_time = ns;
}
void dwmac1000_timestamp_interrupt(struct stmmac_priv *priv)
{
struct ptp_clock_event event;
u32 ts_status, num_snapshot;
unsigned long flags;
u64 ptp_time;
int i;
/* Clears the timestamp interrupt */
ts_status = readl(priv->ptpaddr + GMAC3_X_TIMESTAMP_STATUS);
if (!(priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN))
return;
num_snapshot = (ts_status & GMAC3_X_ATSNS) >> GMAC3_X_ATSNS_SHIFT;
for (i = 0; i < num_snapshot; i++) {
read_lock_irqsave(&priv->ptp_lock, flags);
stmmac_get_ptptime(priv, priv->ptpaddr, &ptp_time);
read_unlock_irqrestore(&priv->ptp_lock, flags);
event.type = PTP_CLOCK_EXTTS;
event.index = 0;
event.timestamp = ptp_time;
ptp_clock_event(priv->ptp_clock, &event);
}
}
/* DWMAC 1000 ptp_clock_info ops */
static void dwmac1000_timestamp_interrupt_cfg(struct stmmac_priv *priv, bool en)
{
void __iomem *ioaddr = priv->ioaddr;
u32 intr_mask = readl(ioaddr + GMAC_INT_MASK);
if (en)
intr_mask &= ~GMAC_INT_DISABLE_TIMESTAMP;
else
intr_mask |= GMAC_INT_DISABLE_TIMESTAMP;
writel(intr_mask, ioaddr + GMAC_INT_MASK);
}
int dwmac1000_ptp_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on)
{
struct stmmac_priv *priv =
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
void __iomem *ptpaddr = priv->ptpaddr;
int ret = -EOPNOTSUPP;
u32 tcr_val;
switch (rq->type) {
case PTP_CLK_REQ_EXTTS:
mutex_lock(&priv->aux_ts_lock);
tcr_val = readl(ptpaddr + PTP_TCR);
if (on) {
tcr_val |= GMAC_PTP_TCR_ATSEN0;
tcr_val |= GMAC_PTP_TCR_ATSFC;
priv->plat->flags |= STMMAC_FLAG_EXT_SNAPSHOT_EN;
} else {
tcr_val &= ~GMAC_PTP_TCR_ATSEN0;
priv->plat->flags &= ~STMMAC_FLAG_EXT_SNAPSHOT_EN;
}
netdev_dbg(priv->dev, "Auxiliary Snapshot %s.\n",
on ? "enabled" : "disabled");
writel(tcr_val, ptpaddr + PTP_TCR);
/* wait for auxts fifo clear to finish */
ret = readl_poll_timeout(ptpaddr + PTP_TCR, tcr_val,
!(tcr_val & GMAC_PTP_TCR_ATSFC),
10, 10000);
mutex_unlock(&priv->aux_ts_lock);
dwmac1000_timestamp_interrupt_cfg(priv, on);
break;
default:
break;
}
return ret;
}

View File

@@ -113,6 +113,7 @@ static const struct stmmac_hwif_entry {
const void *dma;
const void *mac;
const void *hwtimestamp;
const void *ptp;
const void *mode;
const void *tc;
const void *mmc;
@@ -133,7 +134,8 @@ static const struct stmmac_hwif_entry {
.desc = NULL,
.dma = &dwmac100_dma_ops,
.mac = &dwmac100_ops,
.hwtimestamp = &stmmac_ptp,
.hwtimestamp = &dwmac1000_ptp,
.ptp = &dwmac1000_ptp_clock_ops,
.mode = NULL,
.tc = NULL,
.mmc = &dwmac_mmc_ops,
@@ -151,7 +153,8 @@ static const struct stmmac_hwif_entry {
.desc = NULL,
.dma = &dwmac1000_dma_ops,
.mac = &dwmac1000_ops,
.hwtimestamp = &stmmac_ptp,
.hwtimestamp = &dwmac1000_ptp,
.ptp = &dwmac1000_ptp_clock_ops,
.mode = NULL,
.tc = NULL,
.mmc = &dwmac_mmc_ops,
@@ -171,6 +174,7 @@ static const struct stmmac_hwif_entry {
.dma = &dwmac4_dma_ops,
.mac = &dwmac4_ops,
.hwtimestamp = &stmmac_ptp,
.ptp = &stmmac_ptp_clock_ops,
.mode = NULL,
.tc = &dwmac4_tc_ops,
.mmc = &dwmac_mmc_ops,
@@ -192,6 +196,7 @@ static const struct stmmac_hwif_entry {
.dma = &dwmac4_dma_ops,
.mac = &dwmac410_ops,
.hwtimestamp = &stmmac_ptp,
.ptp = &stmmac_ptp_clock_ops,
.mode = &dwmac4_ring_mode_ops,
.tc = &dwmac510_tc_ops,
.mmc = &dwmac_mmc_ops,
@@ -213,6 +218,7 @@ static const struct stmmac_hwif_entry {
.dma = &dwmac410_dma_ops,
.mac = &dwmac410_ops,
.hwtimestamp = &stmmac_ptp,
.ptp = &stmmac_ptp_clock_ops,
.mode = &dwmac4_ring_mode_ops,
.tc = &dwmac510_tc_ops,
.mmc = &dwmac_mmc_ops,
@@ -234,6 +240,7 @@ static const struct stmmac_hwif_entry {
.dma = &dwmac410_dma_ops,
.mac = &dwmac510_ops,
.hwtimestamp = &stmmac_ptp,
.ptp = &stmmac_ptp_clock_ops,
.mode = &dwmac4_ring_mode_ops,
.tc = &dwmac510_tc_ops,
.mmc = &dwmac_mmc_ops,
@@ -256,6 +263,7 @@ static const struct stmmac_hwif_entry {
.dma = &dwxgmac210_dma_ops,
.mac = &dwxgmac210_ops,
.hwtimestamp = &stmmac_ptp,
.ptp = &stmmac_ptp_clock_ops,
.mode = NULL,
.tc = &dwxgmac_tc_ops,
.mmc = &dwxgmac_mmc_ops,
@@ -278,6 +286,7 @@ static const struct stmmac_hwif_entry {
.dma = &dwxgmac210_dma_ops,
.mac = &dwxlgmac2_ops,
.hwtimestamp = &stmmac_ptp,
.ptp = &stmmac_ptp_clock_ops,
.mode = NULL,
.tc = &dwxgmac_tc_ops,
.mmc = &dwxgmac_mmc_ops,
@@ -362,6 +371,8 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
priv->fpe_cfg.reg = entry->regs.fpe_reg;
priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
memcpy(&priv->ptp_clock_ops, entry->ptp,
sizeof(struct ptp_clock_info));
if (entry->est)
priv->estaddr = priv->ioaddr + entry->regs.est_off;

View File

@@ -18,9 +18,22 @@
#include "dwmac4.h"
#include "stmmac.h"
#define STMMAC_HWTS_CFG_MASK (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | \
PTP_TCR_TSINIT | PTP_TCR_TSUPDT | \
PTP_TCR_TSCTRLSSR | PTP_TCR_SNAPTYPSEL_1 | \
PTP_TCR_TSIPV4ENA | PTP_TCR_TSIPV6ENA | \
PTP_TCR_TSEVNTENA | PTP_TCR_TSMSTRENA | \
PTP_TCR_TSVER2ENA | PTP_TCR_TSIPENA | \
PTP_TCR_TSTRIG | PTP_TCR_TSENALL)
static void config_hw_tstamping(void __iomem *ioaddr, u32 data)
{
writel(data, ioaddr + PTP_TCR);
u32 regval = readl(ioaddr + PTP_TCR);
regval &= ~STMMAC_HWTS_CFG_MASK;
regval |= data;
writel(regval, ioaddr + PTP_TCR);
}
static void config_sub_second_increment(void __iomem *ioaddr,
@@ -269,3 +282,14 @@ const struct stmmac_hwtimestamp stmmac_ptp = {
.timestamp_interrupt = timestamp_interrupt,
.hwtstamp_correct_latency = hwtstamp_correct_latency,
};
const struct stmmac_hwtimestamp dwmac1000_ptp = {
.config_hw_tstamping = config_hw_tstamping,
.init_systime = init_systime,
.config_sub_second_increment = config_sub_second_increment,
.config_addend = config_addend,
.adjust_systime = adjust_systime,
.get_systime = get_systime,
.get_ptptime = dwmac1000_get_ptptime,
.timestamp_interrupt = dwmac1000_timestamp_interrupt,
};

View File

@@ -9,7 +9,6 @@
*******************************************************************************/
#include "stmmac.h"
#include "stmmac_ptp.h"
#include "dwmac4.h"
/**
* stmmac_adjust_freq
@@ -265,7 +264,7 @@ static int stmmac_getcrosststamp(struct ptp_clock_info *ptp,
}
/* structure describing a PTP hardware clock */
static struct ptp_clock_info stmmac_ptp_clock_ops = {
const struct ptp_clock_info stmmac_ptp_clock_ops = {
.owner = THIS_MODULE,
.name = "stmmac ptp",
.max_adj = 62500000,
@@ -282,6 +281,24 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = {
.getcrosststamp = stmmac_getcrosststamp,
};
/* structure describing a PTP hardware clock */
const struct ptp_clock_info dwmac1000_ptp_clock_ops = {
.owner = THIS_MODULE,
.name = "stmmac ptp",
.max_adj = 62500000,
.n_alarm = 0,
.n_ext_ts = 1,
.n_per_out = 0,
.n_pins = 0,
.pps = 0,
.adjfine = stmmac_adjust_freq,
.adjtime = stmmac_adjust_time,
.gettime64 = stmmac_get_time,
.settime64 = stmmac_set_time,
.enable = dwmac1000_ptp_enable,
.getcrosststamp = stmmac_getcrosststamp,
};
/**
* stmmac_ptp_register
* @priv: driver private structure
@@ -298,20 +315,25 @@ void stmmac_ptp_register(struct stmmac_priv *priv)
priv->pps[i].available = true;
}
if (priv->plat->ptp_max_adj)
stmmac_ptp_clock_ops.max_adj = priv->plat->ptp_max_adj;
/* Calculate the clock domain crossing (CDC) error if necessary */
priv->plat->cdc_error_adj = 0;
if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate)
priv->plat->cdc_error_adj = (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate;
stmmac_ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num;
stmmac_ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n;
/* Update the ptp clock parameters based on feature discovery, when
* available
*/
if (priv->dma_cap.pps_out_num)
priv->ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num;
if (priv->dma_cap.aux_snapshot_n)
priv->ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n;
if (priv->plat->ptp_max_adj)
priv->ptp_clock_ops.max_adj = priv->plat->ptp_max_adj;
rwlock_init(&priv->ptp_lock);
mutex_init(&priv->aux_ts_lock);
priv->ptp_clock_ops = stmmac_ptp_clock_ops;
priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
priv->device);

View File

@@ -94,4 +94,14 @@ enum aux_snapshot {
AUX_SNAPSHOT3 = 0x80,
};
struct ptp_clock_info;
struct ptp_clock_request;
struct stmmac_priv;
int dwmac1000_ptp_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on);
void dwmac1000_get_ptptime(void __iomem *ptpaddr, u64 *ptp_time);
void dwmac1000_timestamp_interrupt(struct stmmac_priv *priv);
#endif /* __STMMAC_PTP_H__ */