Skip to content

Commit f799592

Browse files
Csókás Bencedavem330
authored andcommitted
fec: Restart PPS after link state change
On link state change, the controller gets reset, causing PPS to drop out and the PHC to lose its time and calibration. So we restart it if needed, restoring calibration and time registers. Changes since v2: * Add `fec_ptp_save_state()`/`fec_ptp_restore_state()` * Use `ktime_get_real_ns()` * Use `BIT()` macro Changes since v1: * More ECR #define's * Stop PPS in `fec_ptp_stop()` Signed-off-by: Csókás Bence <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d5485d9 commit f799592

File tree

3 files changed

+77
-4
lines changed

3 files changed

+77
-4
lines changed

drivers/net/ethernet/freescale/fec.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,13 @@ struct fec_enet_private {
634634
int pps_enable;
635635
unsigned int next_counter;
636636

637+
struct {
638+
struct timespec64 ts_phc;
639+
u64 ns_sys;
640+
u32 at_corr;
641+
u8 at_inc_corr;
642+
} ptp_saved_state;
643+
637644
u64 ethtool_stats[];
638645
};
639646

@@ -644,5 +651,8 @@ void fec_ptp_disable_hwts(struct net_device *ndev);
644651
int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
645652
int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
646653

654+
void fec_ptp_save_state(struct fec_enet_private *fep);
655+
int fec_ptp_restore_state(struct fec_enet_private *fep);
656+
647657
/****************************************************************************/
648658
#endif /* FEC_H */

drivers/net/ethernet/freescale/fec_main.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,11 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
285285
#define FEC_MMFR_TA (2 << 16)
286286
#define FEC_MMFR_DATA(v) (v & 0xffff)
287287
/* FEC ECR bits definition */
288-
#define FEC_ECR_MAGICEN (1 << 2)
289-
#define FEC_ECR_SLEEP (1 << 3)
288+
#define FEC_ECR_RESET BIT(0)
289+
#define FEC_ECR_ETHEREN BIT(1)
290+
#define FEC_ECR_MAGICEN BIT(2)
291+
#define FEC_ECR_SLEEP BIT(3)
292+
#define FEC_ECR_EN1588 BIT(4)
290293

291294
#define FEC_MII_TIMEOUT 30000 /* us */
292295

@@ -982,6 +985,9 @@ fec_restart(struct net_device *ndev)
982985
u32 temp_mac[2];
983986
u32 rcntl = OPT_FRAME_SIZE | 0x04;
984987
u32 ecntl = 0x2; /* ETHEREN */
988+
struct ptp_clock_request ptp_rq = { .type = PTP_CLK_REQ_PPS };
989+
990+
fec_ptp_save_state(fep);
985991

986992
/* Whack a reset. We should wait for this.
987993
* For i.MX6SX SOC, enet use AXI bus, we use disable MAC
@@ -1135,7 +1141,7 @@ fec_restart(struct net_device *ndev)
11351141
}
11361142

11371143
if (fep->bufdesc_ex)
1138-
ecntl |= (1 << 4);
1144+
ecntl |= FEC_ECR_EN1588;
11391145

11401146
if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT &&
11411147
fep->rgmii_txc_dly)
@@ -1156,6 +1162,14 @@ fec_restart(struct net_device *ndev)
11561162
if (fep->bufdesc_ex)
11571163
fec_ptp_start_cyclecounter(ndev);
11581164

1165+
/* Restart PPS if needed */
1166+
if (fep->pps_enable) {
1167+
/* Clear flag so fec_ptp_enable_pps() doesn't return immediately */
1168+
fep->pps_enable = 0;
1169+
fec_ptp_restore_state(fep);
1170+
fep->ptp_caps.enable(&fep->ptp_caps, &ptp_rq, 1);
1171+
}
1172+
11591173
/* Enable interrupts we wish to service */
11601174
if (fep->link)
11611175
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
@@ -1206,6 +1220,8 @@ fec_stop(struct net_device *ndev)
12061220
struct fec_enet_private *fep = netdev_priv(ndev);
12071221
u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
12081222
u32 val;
1223+
struct ptp_clock_request ptp_rq = { .type = PTP_CLK_REQ_PPS };
1224+
u32 ecntl = 0;
12091225

12101226
/* We cannot expect a graceful transmit stop without link !!! */
12111227
if (fep->link) {
@@ -1215,6 +1231,8 @@ fec_stop(struct net_device *ndev)
12151231
netdev_err(ndev, "Graceful transmit stop did not complete!\n");
12161232
}
12171233

1234+
fec_ptp_save_state(fep);
1235+
12181236
/* Whack a reset. We should wait for this.
12191237
* For i.MX6SX SOC, enet use AXI bus, we use disable MAC
12201238
* instead of reset MAC itself.
@@ -1234,12 +1252,28 @@ fec_stop(struct net_device *ndev)
12341252
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
12351253
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
12361254

1255+
if (fep->bufdesc_ex)
1256+
ecntl |= FEC_ECR_EN1588;
1257+
12371258
/* We have to keep ENET enabled to have MII interrupt stay working */
12381259
if (fep->quirks & FEC_QUIRK_ENET_MAC &&
12391260
!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
1240-
writel(2, fep->hwp + FEC_ECNTRL);
1261+
ecntl |= FEC_ECR_ETHEREN;
12411262
writel(rmii_mode, fep->hwp + FEC_R_CNTRL);
12421263
}
1264+
1265+
writel(ecntl, fep->hwp + FEC_ECNTRL);
1266+
1267+
if (fep->bufdesc_ex)
1268+
fec_ptp_start_cyclecounter(ndev);
1269+
1270+
/* Restart PPS if needed */
1271+
if (fep->pps_enable) {
1272+
/* Clear flag so fec_ptp_enable_pps() doesn't return immediately */
1273+
fep->pps_enable = 0;
1274+
fec_ptp_restore_state(fep);
1275+
fep->ptp_caps.enable(&fep->ptp_caps, &ptp_rq, 1);
1276+
}
12431277
}
12441278

12451279

drivers/net/ethernet/freescale/fec_ptp.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,36 @@ void fec_ptp_stop(struct platform_device *pdev)
633633
struct net_device *ndev = platform_get_drvdata(pdev);
634634
struct fec_enet_private *fep = netdev_priv(ndev);
635635

636+
if (fep->pps_enable)
637+
fec_ptp_enable_pps(fep, 0);
638+
636639
cancel_delayed_work_sync(&fep->time_keep);
637640
if (fep->ptp_clock)
638641
ptp_clock_unregister(fep->ptp_clock);
639642
}
643+
644+
void fec_ptp_save_state(struct fec_enet_private *fep)
645+
{
646+
u32 atime_inc_corr;
647+
648+
fec_ptp_gettime(&fep->ptp_caps, &fep->ptp_saved_state.ts_phc);
649+
fep->ptp_saved_state.ns_sys = ktime_get_ns();
650+
651+
fep->ptp_saved_state.at_corr = readl(fep->hwp + FEC_ATIME_CORR);
652+
atime_inc_corr = readl(fep->hwp + FEC_ATIME_INC) & FEC_T_INC_CORR_MASK;
653+
fep->ptp_saved_state.at_inc_corr = (u8)(atime_inc_corr >> FEC_T_INC_CORR_OFFSET);
654+
}
655+
656+
int fec_ptp_restore_state(struct fec_enet_private *fep)
657+
{
658+
u32 atime_inc = readl(fep->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK;
659+
u64 ns_sys;
660+
661+
writel(fep->ptp_saved_state.at_corr, fep->hwp + FEC_ATIME_CORR);
662+
atime_inc |= ((u32)fep->ptp_saved_state.at_inc_corr) << FEC_T_INC_CORR_OFFSET;
663+
writel(atime_inc, fep->hwp + FEC_ATIME_INC);
664+
665+
ns_sys = ktime_get_ns() - fep->ptp_saved_state.ns_sys;
666+
timespec64_add_ns(&fep->ptp_saved_state.ts_phc, ns_sys);
667+
return fec_ptp_settime(&fep->ptp_caps, &fep->ptp_saved_state.ts_phc);
668+
}

0 commit comments

Comments
 (0)