From patchwork Mon Aug 22 08:10:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?Q3PDs2vDoXMgQmVuY2U=?= X-Patchwork-Id: 12950305 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 82D06C28D13 for ; Mon, 22 Aug 2022 08:12:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231834AbiHVIMQ (ORCPT ); Mon, 22 Aug 2022 04:12:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42922 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231278AbiHVIMP (ORCPT ); Mon, 22 Aug 2022 04:12:15 -0400 Received: from fw2.prolan.hu (fw2.prolan.hu [193.68.50.107]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 95D4DF36 for ; Mon, 22 Aug 2022 01:12:12 -0700 (PDT) Received: from imsva.intranet.prolan.hu (imsva.intranet.prolan.hu [10.254.254.252]) by fw2.prolan.hu (Postfix) with ESMTPS id 339217F495; Mon, 22 Aug 2022 10:12:09 +0200 (CEST) Received: from imsva.intranet.prolan.hu (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 20DB034064; Mon, 22 Aug 2022 10:12:09 +0200 (CEST) Received: from imsva.intranet.prolan.hu (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 05CF53405A; Mon, 22 Aug 2022 10:12:09 +0200 (CEST) Received: from fw2.prolan.hu (unknown [10.254.254.253]) by imsva.intranet.prolan.hu (Postfix) with ESMTPS; Mon, 22 Aug 2022 10:12:08 +0200 (CEST) Received: from sinope.intranet.prolan.hu (sinope.intranet.prolan.hu [10.254.0.237]) by fw2.prolan.hu (Postfix) with ESMTPS id D14637F495; Mon, 22 Aug 2022 10:12:08 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=prolan.hu; s=mail; t=1661155928; bh=ulxL8/0Y7YcUWKra+w4Hf8bldxxmozBRDn951g3dY/Q=; h=From:To:CC:Subject:Date:From; b=IoShsR5+AWJmwWIqm+K2uOLpMu0zj9riaSdEQDUGAu4/UJIpaTinEW3LH+t1FQV6M AgIeOcN+DPoqybw8b+Nl2FskHDUPFTlmoawbyhDREPMceLXhxpWOMandAlesWBpIXp ANRxb3chlTmBtf4qYhEnDhwXWIIoq7JMXxtqD8ArH1xggAO+hVdCKwTBWwYHIPWkti sPAm7EY+3bXnxxRPZi6BRpFYKIrkf5UrawSeZ3dMx5/iRkA5PbckK7yMee3M0NW6T8 fQbICfzKSt5rvOYQhI92CnGLA0NsF3tinzoR5n7bSYAeUn4qFDE9Wbf2nNdC7X1Z/m fb6ahanbET44Q== Received: from atlas.intranet.prolan.hu (10.254.0.229) by sinope.intranet.prolan.hu (10.254.0.237) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P521) id 15.1.2507.9; Mon, 22 Aug 2022 10:12:08 +0200 Received: from P-01011.intranet.prolan.hu (10.254.7.28) by atlas.intranet.prolan.hu (10.254.0.229) with Microsoft SMTP Server id 15.1.2507.9 via Frontend Transport; Mon, 22 Aug 2022 10:12:08 +0200 From: =?utf-8?b?Q3PDs2vDoXMgQmVuY2U=?= To: CC: Richard Cochran , "David S. Miller" , Jakub Kicinski , , Andrew Lunn , =?utf-8?b?Q3PDs2s=?= =?utf-8?b?w6FzIEJlbmNl?= Subject: [PATCH v3 resubmit] fec: Restart PPS after link state change Date: Mon, 22 Aug 2022 10:10:52 +0200 Message-ID: <20220822081051.7873-1-csokas.bence@prolan.hu> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-ESET-AS: R=OK;S=0;OP=CALC;TIME=1661155928;VERSION=7933;MC=1813014912;TRN=0;CRV=0;IPC=;SP=0;SIPS=0;PI=3;F=0 X-ESET-Antispam: OK X-EsetResult: clean, is OK X-EsetId: 37303A29A91EF45660726B X-TM-AS-GCONF: 00 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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 --- drivers/net/ethernet/freescale/fec.h | 10 ++++++ drivers/net/ethernet/freescale/fec_main.c | 42 ++++++++++++++++++++--- drivers/net/ethernet/freescale/fec_ptp.c | 29 ++++++++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index ed7301b69169..0cebe4b63adb 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -634,6 +634,13 @@ struct fec_enet_private { int pps_enable; unsigned int next_counter; + struct { + struct timespec64 ts_phc; + u64 ns_sys; + u32 at_corr; + u8 at_inc_corr; + } ptp_saved_state; + u64 ethtool_stats[]; }; @@ -644,5 +651,8 @@ void fec_ptp_disable_hwts(struct net_device *ndev); int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr); int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr); +void fec_ptp_save_state(struct fec_enet_private *fep); +int fec_ptp_restore_state(struct fec_enet_private *fep); + /****************************************************************************/ #endif /* FEC_H */ diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index e8e2aa1e7f01..b0d60f898249 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -285,8 +285,11 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_MMFR_TA (2 << 16) #define FEC_MMFR_DATA(v) (v & 0xffff) /* FEC ECR bits definition */ -#define FEC_ECR_MAGICEN (1 << 2) -#define FEC_ECR_SLEEP (1 << 3) +#define FEC_ECR_RESET BIT(0) +#define FEC_ECR_ETHEREN BIT(1) +#define FEC_ECR_MAGICEN BIT(2) +#define FEC_ECR_SLEEP BIT(3) +#define FEC_ECR_EN1588 BIT(4) #define FEC_MII_TIMEOUT 30000 /* us */ @@ -982,6 +985,9 @@ fec_restart(struct net_device *ndev) u32 temp_mac[2]; u32 rcntl = OPT_FRAME_SIZE | 0x04; u32 ecntl = 0x2; /* ETHEREN */ + struct ptp_clock_request ptp_rq = { .type = PTP_CLK_REQ_PPS }; + + 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 @@ -1135,7 +1141,7 @@ fec_restart(struct net_device *ndev) } if (fep->bufdesc_ex) - ecntl |= (1 << 4); + ecntl |= FEC_ECR_EN1588; if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT && fep->rgmii_txc_dly) @@ -1156,6 +1162,14 @@ fec_restart(struct net_device *ndev) if (fep->bufdesc_ex) fec_ptp_start_cyclecounter(ndev); + /* Restart PPS if needed */ + if (fep->pps_enable) { + /* Clear flag so fec_ptp_enable_pps() doesn't return immediately */ + fep->pps_enable = 0; + fec_ptp_restore_state(fep); + fep->ptp_caps.enable(&fep->ptp_caps, &ptp_rq, 1); + } + /* Enable interrupts we wish to service */ if (fep->link) writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); @@ -1206,6 +1220,8 @@ fec_stop(struct net_device *ndev) struct fec_enet_private *fep = netdev_priv(ndev); u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); u32 val; + struct ptp_clock_request ptp_rq = { .type = PTP_CLK_REQ_PPS }; + u32 ecntl = 0; /* We cannot expect a graceful transmit stop without link !!! */ if (fep->link) { @@ -1215,6 +1231,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. @@ -1234,12 +1252,28 @@ fec_stop(struct net_device *ndev) writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); + if (fep->bufdesc_ex) + ecntl |= FEC_ECR_EN1588; + /* We have to keep ENET enabled to have MII interrupt stay working */ if (fep->quirks & FEC_QUIRK_ENET_MAC && !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { - writel(2, fep->hwp + FEC_ECNTRL); + ecntl |= FEC_ECR_ETHEREN; writel(rmii_mode, fep->hwp + FEC_R_CNTRL); } + + writel(ecntl, fep->hwp + FEC_ECNTRL); + + if (fep->bufdesc_ex) + fec_ptp_start_cyclecounter(ndev); + + /* Restart PPS if needed */ + if (fep->pps_enable) { + /* Clear flag so fec_ptp_enable_pps() doesn't return immediately */ + fep->pps_enable = 0; + fec_ptp_restore_state(fep); + fep->ptp_caps.enable(&fep->ptp_caps, &ptp_rq, 1); + } } diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 3dc3c0b626c2..c74d04f4b2fd 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -633,7 +633,36 @@ void fec_ptp_stop(struct platform_device *pdev) struct net_device *ndev = platform_get_drvdata(pdev); struct fec_enet_private *fep = netdev_priv(ndev); + if (fep->pps_enable) + fec_ptp_enable_pps(fep, 0); + cancel_delayed_work_sync(&fep->time_keep); if (fep->ptp_clock) ptp_clock_unregister(fep->ptp_clock); } + +void fec_ptp_save_state(struct fec_enet_private *fep) +{ + u32 atime_inc_corr; + + fec_ptp_gettime(&fep->ptp_caps, &fep->ptp_saved_state.ts_phc); + 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); +} + +int fec_ptp_restore_state(struct fec_enet_private *fep) +{ + u32 atime_inc = readl(fep->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK; + u64 ns_sys; + + 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_sys = ktime_get_ns() - fep->ptp_saved_state.ns_sys; + timespec64_add_ns(&fep->ptp_saved_state.ts_phc, ns_sys); + return fec_ptp_settime(&fep->ptp_caps, &fep->ptp_saved_state.ts_phc); +}