summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/freescale
diff options
context:
space:
mode:
authorCsókás, Bence <csokas.bence@prolan.hu>2024-09-24 12:37:06 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-10-10 13:00:07 +0300
commit5b88ee8318f10bd9117fea71d0928582cf6b065a (patch)
treefcd6e4c4e9cfb20a59052bbf53a5ec25a5263597 /drivers/net/ethernet/freescale
parentcf53d7e76f1fb751b12ceda6a49942414d2f9ea9 (diff)
downloadlinux-5b88ee8318f10bd9117fea71d0928582cf6b065a.tar.xz
net: fec: Reload PTP registers after link-state change
[ Upstream commit d9335d0232d2da605585eea1518ac6733518f938 ] On link-state change, the controller gets reset, which clears all PTP registers, including PHC time, calibrated clock correction values etc. For correct IEEE 1588 operation we need to restore these after the reset. Fixes: 6605b730c061 ("FEC: Add time stamping code and a PTP hardware clock") Signed-off-by: Csókás, Bence <csokas.bence@prolan.hu> Reviewed-by: Wei Fang <wei.fang@nxp.com> Link: https://patch.msgid.link/20240924093705.2897329-2-csokas.bence@prolan.hu Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r--drivers/net/ethernet/freescale/fec.h3
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c20
2 files changed, 23 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 0552317a2554..1cca0425d493 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -693,6 +693,9 @@ struct fec_enet_private {
struct {
int pps_enable;
+ u64 ns_sys, ns_phc;
+ u32 at_corr;
+ u8 at_inc_corr;
} ptp_saved_state;
u64 ethtool_stats[];
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index 8027b532de07..5e8fac50f945 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -773,24 +773,44 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx)
void fec_ptp_save_state(struct fec_enet_private *fep)
{
unsigned long flags;
+ u32 atime_inc_corr;
spin_lock_irqsave(&fep->tmreg_lock, flags);
fep->ptp_saved_state.pps_enable = fep->pps_enable;
+ fep->ptp_saved_state.ns_phc = timecounter_read(&fep->tc);
+ fep->ptp_saved_state.ns_sys = ktime_get_ns();
+
+ fep->ptp_saved_state.at_corr = readl(fep->hwp + FEC_ATIME_CORR);
+ atime_inc_corr = readl(fep->hwp + FEC_ATIME_INC) & FEC_T_INC_CORR_MASK;
+ fep->ptp_saved_state.at_inc_corr = (u8)(atime_inc_corr >> FEC_T_INC_CORR_OFFSET);
+
spin_unlock_irqrestore(&fep->tmreg_lock, flags);
}
/* Restore PTP functionality after a reset */
void fec_ptp_restore_state(struct fec_enet_private *fep)
{
+ u32 atime_inc = readl(fep->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK;
unsigned long flags;
+ u32 counter;
+ u64 ns;
spin_lock_irqsave(&fep->tmreg_lock, flags);
/* Reset turned it off, so adjust our status flag */
fep->pps_enable = 0;
+ writel(fep->ptp_saved_state.at_corr, fep->hwp + FEC_ATIME_CORR);
+ atime_inc |= ((u32)fep->ptp_saved_state.at_inc_corr) << FEC_T_INC_CORR_OFFSET;
+ writel(atime_inc, fep->hwp + FEC_ATIME_INC);
+
+ ns = ktime_get_ns() - fep->ptp_saved_state.ns_sys + fep->ptp_saved_state.ns_phc;
+ counter = ns & fep->cc.mask;
+ writel(counter, fep->hwp + FEC_ATIME);
+ timecounter_init(&fep->tc, &fep->cc, ns);
+
spin_unlock_irqrestore(&fep->tmreg_lock, flags);
/* Restart PPS if needed */