]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: fec: Restart PPS after link state change
authorCsókás, Bence <csokas.bence@prolan.hu>
Tue, 24 Sep 2024 09:37:04 +0000 (11:37 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Oct 2024 10:00:07 +0000 (12:00 +0200)
[ Upstream commit a1477dc87dc4996dcf65a4893d4e2c3a6b593002 ]

On link state change, the controller gets reset,
causing PPS to drop out. Re-enable PPS if it was
enabled before the controller reset.

Fixes: 6605b730c061 ("FEC: Add time stamping code and a PTP hardware clock")
Signed-off-by: Csókás, Bence <csokas.bence@prolan.hu>
Link: https://patch.msgid.link/20240924093705.2897329-1-csokas.bence@prolan.hu
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fec_ptp.c

index a19cb2a786fd2808e355dd91c057afa35c752f17..0552317a2554bcdb4833234bb4ec62c9166cdc32 100644 (file)
@@ -691,10 +691,16 @@ struct fec_enet_private {
        /* XDP BPF Program */
        struct bpf_prog *xdp_prog;
 
+       struct {
+               int pps_enable;
+       } ptp_saved_state;
+
        u64 ethtool_stats[];
 };
 
 void fec_ptp_init(struct platform_device *pdev, int irq_idx);
+void fec_ptp_restore_state(struct fec_enet_private *fep);
+void fec_ptp_save_state(struct fec_enet_private *fep);
 void fec_ptp_stop(struct platform_device *pdev);
 void fec_ptp_start_cyclecounter(struct net_device *ndev);
 int fec_ptp_set(struct net_device *ndev, struct kernel_hwtstamp_config *config,
index fb19295529a218343d857656fb50d4516d5f8a1a..8004f12352b6b567c48924c42ac0f07cbbf022d6 100644 (file)
@@ -1077,6 +1077,8 @@ fec_restart(struct net_device *ndev)
        u32 rcntl = OPT_FRAME_SIZE | 0x04;
        u32 ecntl = FEC_ECR_ETHEREN;
 
+       fec_ptp_save_state(fep);
+
        /* Whack a reset.  We should wait for this.
         * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
         * instead of reset MAC itself.
@@ -1244,8 +1246,10 @@ fec_restart(struct net_device *ndev)
        writel(ecntl, fep->hwp + FEC_ECNTRL);
        fec_enet_active_rxring(ndev);
 
-       if (fep->bufdesc_ex)
+       if (fep->bufdesc_ex) {
                fec_ptp_start_cyclecounter(ndev);
+               fec_ptp_restore_state(fep);
+       }
 
        /* Enable interrupts we wish to service */
        if (fep->link)
@@ -1336,6 +1340,8 @@ fec_stop(struct net_device *ndev)
                        netdev_err(ndev, "Graceful transmit stop did not complete!\n");
        }
 
+       fec_ptp_save_state(fep);
+
        /* Whack a reset.  We should wait for this.
         * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
         * instead of reset MAC itself.
@@ -1366,6 +1372,9 @@ fec_stop(struct net_device *ndev)
                val = readl(fep->hwp + FEC_ECNTRL);
                val |= FEC_ECR_EN1588;
                writel(val, fep->hwp + FEC_ECNTRL);
+
+               fec_ptp_start_cyclecounter(ndev);
+               fec_ptp_restore_state(fep);
        }
 }
 
index 2e4f3e1782a2520c45912b414fd340db298b1fe7..8027b532de0789ea9ed38e1b3f140cc46aaf4c70 100644 (file)
@@ -770,6 +770,36 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx)
        schedule_delayed_work(&fep->time_keep, HZ);
 }
 
+void fec_ptp_save_state(struct fec_enet_private *fep)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&fep->tmreg_lock, flags);
+
+       fep->ptp_saved_state.pps_enable = fep->pps_enable;
+
+       spin_unlock_irqrestore(&fep->tmreg_lock, flags);
+}
+
+/* Restore PTP functionality after a reset */
+void fec_ptp_restore_state(struct fec_enet_private *fep)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&fep->tmreg_lock, flags);
+
+       /* Reset turned it off, so adjust our status flag */
+       fep->pps_enable = 0;
+
+       spin_unlock_irqrestore(&fep->tmreg_lock, flags);
+
+       /* Restart PPS if needed */
+       if (fep->ptp_saved_state.pps_enable) {
+               /* Re-enable PPS */
+               fec_ptp_enable_pps(fep, 1);
+       }
+}
+
 void fec_ptp_stop(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);