]> www.infradead.org Git - users/willy/pagecache.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)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 1 Oct 2024 09:21:12 +0000 (11:21 +0200)
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>
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 acbb627d51bfa62adeaa43e8e044861f1573b2d6..31ebf6a4f973bd70a8d38530ad09a572cc416fa6 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 4cffda363a148e0c170d07aadbd83cb2aec411a0..df1ef023493b9f08e30878ca85a1fbd9b55546d6 100644 (file)
@@ -764,6 +764,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);