* [PATCH net-next 0/5] Add ptp library for Microchip phys
@ 2024-11-04 9:07 Divya Koppera
2024-11-04 9:07 ` [PATCH net-next 1/5] net: phy: microchip_ptp : Add header file for Microchip ptp library Divya Koppera
` (4 more replies)
0 siblings, 5 replies; 15+ messages in thread
From: Divya Koppera @ 2024-11-04 9:07 UTC (permalink / raw)
To: andrew, arun.ramadoss, UNGLinuxDriver, hkallweit1, linux, davem,
edumazet, kuba, pabeni, netdev, linux-kernel, richardcochran
Adds support of ptp library in Microchip phys
Divya Koppera (5):
net: phy: microchip_ptp : Add header file for Microchip ptp library
net: phy: microchip_ptp : Add ptp library for Microchip phys
net: phy: Kconfig: Add ptp library support and 1588 optional flag in
Microchip phys
net: phy: Makefile: Add makefile support for ptp in Microchip phys
net: phy: microchip_t1 : Add initialization of ptp for lan887x
drivers/net/phy/Kconfig | 9 +-
drivers/net/phy/Makefile | 1 +
drivers/net/phy/microchip_ptp.c | 990 ++++++++++++++++++++++++++++++++
drivers/net/phy/microchip_ptp.h | 217 +++++++
drivers/net/phy/microchip_t1.c | 29 +-
5 files changed, 1242 insertions(+), 4 deletions(-)
create mode 100644 drivers/net/phy/microchip_ptp.c
create mode 100644 drivers/net/phy/microchip_ptp.h
--
2.17.1
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH net-next 1/5] net: phy: microchip_ptp : Add header file for Microchip ptp library
2024-11-04 9:07 [PATCH net-next 0/5] Add ptp library for Microchip phys Divya Koppera
@ 2024-11-04 9:07 ` Divya Koppera
2024-11-04 9:07 ` [PATCH net-next 2/5] net: phy: microchip_ptp : Add ptp library for Microchip phys Divya Koppera
` (3 subsequent siblings)
4 siblings, 0 replies; 15+ messages in thread
From: Divya Koppera @ 2024-11-04 9:07 UTC (permalink / raw)
To: andrew, arun.ramadoss, UNGLinuxDriver, hkallweit1, linux, davem,
edumazet, kuba, pabeni, netdev, linux-kernel, richardcochran
This ptp header file library will cover ptp macros for future phys in Microchip
where addresses will be same but base offset and mmd address may changes.
Signed-off-by: Divya Koppera <divya.koppera@microchip.com>
---
drivers/net/phy/microchip_ptp.h | 217 ++++++++++++++++++++++++++++++++
1 file changed, 217 insertions(+)
create mode 100644 drivers/net/phy/microchip_ptp.h
diff --git a/drivers/net/phy/microchip_ptp.h b/drivers/net/phy/microchip_ptp.h
new file mode 100644
index 000000000000..617418bf9abb
--- /dev/null
+++ b/drivers/net/phy/microchip_ptp.h
@@ -0,0 +1,217 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright (C) 2024 Microchip Technology
+ */
+
+#ifndef _MICROCHIP_PTP_H
+#define _MICROCHIP_PTP_H
+
+#ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
+
+#include <linux/ptp_clock_kernel.h>
+#include <linux/ptp_clock.h>
+#include <linux/ptp_classify.h>
+#include <linux/net_tstamp.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#define MCHP_PTP_CMD_CTL(b) ((b) + 0x0)
+#define MCHP_PTP_CMD_CTL_LTC_STEP_NSEC BIT(6)
+#define MCHP_PTP_CMD_CTL_LTC_STEP_SEC BIT(5)
+#define MCHP_PTP_CMD_CTL_CLOCK_LOAD BIT(4)
+#define MCHP_PTP_CMD_CTL_CLOCK_READ BIT(3)
+#define MCHP_PTP_CMD_CTL_EN BIT(1)
+#define MCHP_PTP_CMD_CTL_DIS BIT(0)
+
+#define MCHP_PTP_REF_CLK_CFG(b) ((b) + 0x2)
+#define MCHP_PTP_REF_CLK_SRC_250MHZ 0x0
+#define MCHP_PTP_REF_CLK_PERIOD_OVERRIDE BIT(9)
+#define MCHP_PTP_REF_CLK_PERIOD 4
+#define MCHP_PTP_REF_CLK_CFG_SET (MCHP_PTP_REF_CLK_SRC_250MHZ |\
+ MCHP_PTP_REF_CLK_PERIOD_OVERRIDE |\
+ MCHP_PTP_REF_CLK_PERIOD)
+
+#define MCHP_PTP_LTC_SEC_HI(b) ((b) + 0x5)
+#define MCHP_PTP_LTC_SEC_MID(b) ((b) + 0x6)
+#define MCHP_PTP_LTC_SEC_LO(b) ((b) + 0x7)
+#define MCHP_PTP_LTC_NS_HI(b) ((b) + 0x8)
+#define MCHP_PTP_LTC_NS_LO(b) ((b) + 0x9)
+#define MCHP_PTP_LTC_RATE_ADJ_HI(b) ((b) + 0xc)
+#define MCHP_PTP_LTC_RATE_ADJ_HI_DIR BIT(15)
+#define MCHP_PTP_LTC_RATE_ADJ_LO(b) ((b) + 0xd)
+#define MCHP_PTP_LTC_STEP_ADJ_HI(b) ((b) + 0x12)
+#define MCHP_PTP_LTC_STEP_ADJ_HI_DIR BIT(15)
+#define MCHP_PTP_LTC_STEP_ADJ_LO(b) ((b) + 0x13)
+#define MCHP_PTP_LTC_READ_SEC_HI(b) ((b) + 0x29)
+#define MCHP_PTP_LTC_READ_SEC_MID(b) ((b) + 0x2a)
+#define MCHP_PTP_LTC_READ_SEC_LO(b) ((b) + 0x2b)
+#define MCHP_PTP_LTC_READ_NS_HI(b) ((b) + 0x2c)
+#define MCHP_PTP_LTC_READ_NS_LO(b) ((b) + 0x2d)
+#define MCHP_PTP_OP_MODE(b) ((b) + 0x41)
+#define MCHP_PTP_OP_MODE_DIS 0
+#define MCHP_PTP_OP_MODE_STANDALONE 1
+#define MCHP_PTP_LATENCY_CORRECTION_CTL(b) ((b) + 0x44)
+#define MCHP_PTP_PREDICTOR_EN BIT(6)
+#define MCHP_PTP_TX_PRED_DIS BIT(1)
+#define MCHP_PTP_RX_PRED_DIS BIT(0)
+#define MCHP_PTP_LATENCY_SETTING (MCHP_PTP_PREDICTOR_EN | \
+ MCHP_PTP_TX_PRED_DIS | \
+ MCHP_PTP_RX_PRED_DIS)
+
+#define MCHP_PTP_INT_EN(b) ((b) + 0x0)
+#define MCHP_PTP_INT_STS(b) ((b) + 0x01)
+#define MCHP_PTP_INT_TX_TS_OVRFL_EN BIT(3)
+#define MCHP_PTP_INT_TX_TS_EN BIT(2)
+#define MCHP_PTP_INT_RX_TS_OVRFL_EN BIT(1)
+#define MCHP_PTP_INT_RX_TS_EN BIT(0)
+#define MCHP_PTP_INT_ALL_MSK (MCHP_PTP_INT_TX_TS_OVRFL_EN | \
+ MCHP_PTP_INT_TX_TS_EN | \
+ MCHP_PTP_INT_RX_TS_OVRFL_EN |\
+ MCHP_PTP_INT_RX_TS_EN)
+
+#define MCHP_PTP_CAP_INFO(b) ((b) + 0x2e)
+#define MCHP_PTP_TX_TS_CNT(v) (((v) & GENMASK(11, 8)) >> 8)
+#define MCHP_PTP_RX_TS_CNT(v) ((v) & GENMASK(3, 0))
+
+#define MCHP_PTP_RX_PARSE_CONFIG(b) ((b) + 0x42)
+#define MCHP_PTP_RX_PARSE_L2_ADDR_EN(b) ((b) + 0x44)
+#define MCHP_PTP_RX_PARSE_IPV4_ADDR_EN(b) ((b) + 0x45)
+
+#define MCHP_PTP_RX_TIMESTAMP_CONFIG(b) ((b) + 0x4e)
+#define MCHP_PTP_RX_TIMESTAMP_CONFIG_PTP_FCS_DIS BIT(0)
+
+#define MCHP_PTP_RX_VERSION(b) ((b) + 0x48)
+#define MCHP_PTP_RX_TIMESTAMP_EN(b) ((b) + 0x4d)
+
+#define MCHP_PTP_RX_INGRESS_NS_HI(b) ((b) + 0x54)
+#define MCHP_PTP_RX_INGRESS_NS_HI_TS_VALID BIT(15)
+
+#define MCHP_PTP_RX_INGRESS_NS_LO(b) ((b) + 0x55)
+#define MCHP_PTP_RX_INGRESS_SEC_HI(b) ((b) + 0x56)
+#define MCHP_PTP_RX_INGRESS_SEC_LO(b) ((b) + 0x57)
+#define MCHP_PTP_RX_MSG_HEADER2(b) ((b) + 0x59)
+
+#define MCHP_PTP_TX_PARSE_CONFIG(b) ((b) + 0x82)
+#define MCHP_PTP_PARSE_CONFIG_LAYER2_EN BIT(0)
+#define MCHP_PTP_PARSE_CONFIG_IPV4_EN BIT(1)
+#define MCHP_PTP_PARSE_CONFIG_IPV6_EN BIT(2)
+
+#define MCHP_PTP_TX_PARSE_L2_ADDR_EN(b) ((b) + 0x84)
+#define MCHP_PTP_TX_PARSE_IPV4_ADDR_EN(b) ((b) + 0x85)
+
+#define MCHP_PTP_TX_VERSION(b) ((b) + 0x88)
+#define MCHP_PTP_MAX_VERSION(x) (((x) & GENMASK(7, 0)) << 8)
+#define MCHP_PTP_MIN_VERSION(x) ((x) & GENMASK(7, 0))
+
+#define MCHP_PTP_TX_TIMESTAMP_EN(b) ((b) + 0x8d)
+#define MCHP_PTP_TIMESTAMP_EN_SYNC BIT(0)
+#define MCHP_PTP_TIMESTAMP_EN_DREQ BIT(1)
+#define MCHP_PTP_TIMESTAMP_EN_PDREQ BIT(2)
+#define MCHP_PTP_TIMESTAMP_EN_PDRES BIT(3)
+#define MCHP_PTP_TIMESTAMP_EN_ALL (MCHP_PTP_TIMESTAMP_EN_SYNC |\
+ MCHP_PTP_TIMESTAMP_EN_DREQ |\
+ MCHP_PTP_TIMESTAMP_EN_PDREQ |\
+ MCHP_PTP_TIMESTAMP_EN_PDRES)
+
+#define MCHP_PTP_TX_TIMESTAMP_CONFIG(b) ((b) + 0x8e)
+#define MCHP_PTP_TX_TIMESTAMP_CONFIG_PTP_FCS_DIS BIT(0)
+
+#define MCHP_PTP_TX_MOD(b) ((b) + 0x8f)
+#define MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT BIT(12)
+#define MCHP_PTP_TX_MOD_PTP_FU_TS_INSERT BIT(11)
+
+#define MCHP_PTP_TX_EGRESS_NS_HI(b) ((b) + 0x94)
+#define MCHP_PTP_TX_EGRESS_NS_HI_TS_VALID BIT(15)
+
+#define MCHP_PTP_TX_EGRESS_NS_LO(b) ((b) + 0x95)
+#define MCHP_PTP_TX_EGRESS_SEC_HI(b) ((b) + 0x96)
+#define MCHP_PTP_TX_EGRESS_SEC_LO(b) ((b) + 0x97)
+#define MCHP_PTP_TX_MSG_HEADER2(b) ((b) + 0x99)
+
+#define MCHP_PTP_TSU_GEN_CONFIG(b) ((b) + 0xc0)
+#define MCHP_PTP_TSU_GEN_CFG_TSU_EN BIT(0)
+
+#define MCHP_PTP_TSU_HARD_RESET(b) ((b) + 0xc1)
+#define MCHP_PTP_TSU_HARDRESET BIT(0)
+
+/* Represents 1ppm adjustment in 2^32 format with
+ * each nsec contains 4 clock cycles in 250MHz.
+ * The value is calculated as following: (1/1000000)/((2^-32)/4)
+ */
+#define MCHP_PTP_1PPM_FORMAT 17179
+#define MCHP_PTP_FIFO_SIZE 8
+#define MCHP_PTP_MAX_ADJ 31249999
+
+#define BASE_CLK(p) ((p)->clk_base_addr)
+#define BASE_PORT(p) ((p)->port_base_addr)
+#define PTP_MMD(p) ((p)->mmd)
+
+enum ptp_fifo_dir {
+ PTP_INGRESS_FIFO,
+ PTP_EGRESS_FIFO
+};
+
+struct mchp_ptp_clock {
+ struct mii_timestamper mii_ts;
+ struct phy_device *phydev;
+
+ struct sk_buff_head tx_queue;
+ struct sk_buff_head rx_queue;
+
+ struct list_head rx_ts_list;
+ /* Lock for Rx ts fifo */
+ spinlock_t rx_ts_lock;
+
+ int hwts_tx_type;
+ enum hwtstamp_rx_filters rx_filter;
+ int layer;
+ int version;
+
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info caps;
+
+ /* Lock for phc */
+ struct mutex ptp_lock;
+
+ u16 port_base_addr;
+ u16 clk_base_addr;
+ u8 mmd;
+};
+
+struct mchp_ptp_rx_ts {
+ struct list_head list;
+ u32 seconds;
+ u32 nsec;
+ u16 seq_id;
+};
+
+struct mchp_ptp_clock *mchp_ptp_probe(struct phy_device *phydev, u8 mmd,
+ u16 clk_base, u16 port_base);
+
+int mchp_config_ptp_intr(struct mchp_ptp_clock *ptp_clock,
+ u16 reg, u16 val, bool enable);
+
+irqreturn_t mchp_ptp_handle_interrupt(struct mchp_ptp_clock *ptp_clock);
+
+#else
+
+static inline struct mchp_ptp_clock *mchp_ptp_probe(struct phy_device *phydev,
+ u8 mmd, u16 clk_base,
+ u16 port_base)
+{
+ return 0;
+}
+
+static inline int mchp_config_ptp_intr(struct mchp_ptp_clock *ptp_clock,
+ u16 reg, u16 val, bool enable)
+{
+ return 0;
+}
+
+static inline irqreturn_t mchp_ptp_handle_interrupt(struct mchp_ptp_clock *ptp_clock)
+{
+ return IRQ_NONE;
+}
+
+#endif //CONFIG_NETWORK_PHY_TIMESTAMPING
+
+#endif //_MICROCHIP_PTP_H
--
2.17.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH net-next 2/5] net: phy: microchip_ptp : Add ptp library for Microchip phys
2024-11-04 9:07 [PATCH net-next 0/5] Add ptp library for Microchip phys Divya Koppera
2024-11-04 9:07 ` [PATCH net-next 1/5] net: phy: microchip_ptp : Add header file for Microchip ptp library Divya Koppera
@ 2024-11-04 9:07 ` Divya Koppera
2024-11-04 12:32 ` Vadim Fedorenko
2024-11-07 14:34 ` Simon Horman
2024-11-04 9:07 ` [PATCH net-next 3/5] net: phy: Kconfig: Add ptp library support and 1588 optional flag in " Divya Koppera
` (2 subsequent siblings)
4 siblings, 2 replies; 15+ messages in thread
From: Divya Koppera @ 2024-11-04 9:07 UTC (permalink / raw)
To: andrew, arun.ramadoss, UNGLinuxDriver, hkallweit1, linux, davem,
edumazet, kuba, pabeni, netdev, linux-kernel, richardcochran
Add ptp library for Microchip phys
1-step and 2-step modes are supported, over Ethernet and UDP(ipv4, ipv6)
Signed-off-by: Divya Koppera <divya.koppera@microchip.com>
---
drivers/net/phy/microchip_ptp.c | 990 ++++++++++++++++++++++++++++++++
1 file changed, 990 insertions(+)
create mode 100644 drivers/net/phy/microchip_ptp.c
diff --git a/drivers/net/phy/microchip_ptp.c b/drivers/net/phy/microchip_ptp.c
new file mode 100644
index 000000000000..45000984858e
--- /dev/null
+++ b/drivers/net/phy/microchip_ptp.c
@@ -0,0 +1,990 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2024 Microchip Technology
+
+#include "microchip_ptp.h"
+
+static int mchp_ptp_flush_fifo(struct mchp_ptp_clock *ptp_clock,
+ enum ptp_fifo_dir dir)
+{
+ struct phy_device *phydev = ptp_clock->phydev;
+ int rc;
+
+ for (int i = 0; i < MCHP_PTP_FIFO_SIZE; ++i) {
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ dir == PTP_EGRESS_FIFO ?
+ MCHP_PTP_TX_MSG_HEADER2(BASE_PORT(ptp_clock)) :
+ MCHP_PTP_RX_MSG_HEADER2(BASE_PORT(ptp_clock)));
+ if (rc < 0)
+ return rc;
+ }
+ return phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_INT_STS(BASE_PORT(ptp_clock)));
+}
+
+static int mchp_ptp_config_intr(struct mchp_ptp_clock *ptp_clock,
+ bool enable)
+{
+ struct phy_device *phydev = ptp_clock->phydev;
+
+ /* Enable or disable ptp interrupts */
+ return phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_INT_EN(BASE_PORT(ptp_clock)),
+ enable ? MCHP_PTP_INT_ALL_MSK : 0);
+}
+
+static void mchp_ptp_txtstamp(struct mii_timestamper *mii_ts,
+ struct sk_buff *skb, int type)
+{
+ struct mchp_ptp_clock *ptp_clock = container_of(mii_ts,
+ struct mchp_ptp_clock,
+ mii_ts);
+
+ switch (ptp_clock->hwts_tx_type) {
+ case HWTSTAMP_TX_ONESTEP_SYNC:
+ if (ptp_msg_is_sync(skb, type)) {
+ kfree_skb(skb);
+ return;
+ }
+ fallthrough;
+ case HWTSTAMP_TX_ON:
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ skb_queue_tail(&ptp_clock->tx_queue, skb);
+ break;
+ case HWTSTAMP_TX_OFF:
+ default:
+ kfree_skb(skb);
+ break;
+ }
+}
+
+static bool mchp_ptp_get_sig_rx(struct sk_buff *skb, u16 *sig)
+{
+ struct ptp_header *ptp_header;
+ int type;
+
+ skb_push(skb, ETH_HLEN);
+ type = ptp_classify_raw(skb);
+ if (type == PTP_CLASS_NONE)
+ return false;
+
+ ptp_header = ptp_parse_header(skb, type);
+ if (!ptp_header)
+ return false;
+
+ skb_pull_inline(skb, ETH_HLEN);
+
+ *sig = ntohs(ptp_header->sequence_id);
+
+ return true;
+}
+
+static bool mchp_ptp_match_skb(struct mchp_ptp_clock *ptp_clock,
+ struct mchp_ptp_rx_ts *rx_ts)
+{
+ struct skb_shared_hwtstamps *shhwtstamps;
+ struct sk_buff *skb, *skb_tmp;
+ unsigned long flags;
+ bool rc = false;
+ u16 skb_sig;
+
+ spin_lock_irqsave(&ptp_clock->rx_queue.lock, flags);
+ skb_queue_walk_safe(&ptp_clock->rx_queue, skb, skb_tmp) {
+ if (!mchp_ptp_get_sig_rx(skb, &skb_sig))
+ continue;
+
+ if (memcmp(&skb_sig, &rx_ts->seq_id, sizeof(rx_ts->seq_id)))
+ continue;
+
+ __skb_unlink(skb, &ptp_clock->rx_queue);
+
+ rc = true;
+ break;
+ }
+ spin_unlock_irqrestore(&ptp_clock->rx_queue.lock, flags);
+
+ if (rc) {
+ shhwtstamps = skb_hwtstamps(skb);
+ memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+ shhwtstamps->hwtstamp = ktime_set(rx_ts->seconds, rx_ts->nsec);
+ netif_rx(skb);
+ }
+
+ return rc;
+}
+
+static void mchp_ptp_match_rx_ts(struct mchp_ptp_clock *ptp_clock,
+ struct mchp_ptp_rx_ts *rx_ts)
+{
+ unsigned long flags;
+
+ /* If we failed to match the skb add it to the queue for when
+ * the frame will come
+ */
+ if (!mchp_ptp_match_skb(ptp_clock, rx_ts)) {
+ spin_lock_irqsave(&ptp_clock->rx_ts_lock, flags);
+ list_add(&rx_ts->list, &ptp_clock->rx_ts_list);
+ spin_unlock_irqrestore(&ptp_clock->rx_ts_lock, flags);
+ } else {
+ kfree(rx_ts);
+ }
+}
+
+static void mchp_ptp_match_rx_skb(struct mchp_ptp_clock *ptp_clock,
+ struct sk_buff *skb)
+{
+ struct skb_shared_hwtstamps *shhwtstamps;
+ struct mchp_ptp_rx_ts *rx_ts, *tmp;
+ unsigned long flags;
+ bool match = false;
+ u16 skb_sig;
+
+ if (!mchp_ptp_get_sig_rx(skb, &skb_sig))
+ return;
+
+ /* Iterate over all RX timestamps and match it with the received skbs */
+ spin_lock_irqsave(&ptp_clock->rx_ts_lock, flags);
+ list_for_each_entry_safe(rx_ts, tmp, &ptp_clock->rx_ts_list, list) {
+ /* Check if we found the signature we were looking for. */
+ if (memcmp(&skb_sig, &rx_ts->seq_id, sizeof(rx_ts->seq_id)))
+ continue;
+
+ shhwtstamps = skb_hwtstamps(skb);
+ memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+ shhwtstamps->hwtstamp = ktime_set(rx_ts->seconds,
+ rx_ts->nsec);
+ netif_rx(skb);
+
+ list_del(&rx_ts->list);
+ kfree(rx_ts);
+
+ match = true;
+ break;
+ }
+ spin_unlock_irqrestore(&ptp_clock->rx_ts_lock, flags);
+
+ if (!match)
+ skb_queue_tail(&ptp_clock->rx_queue, skb);
+}
+
+static bool mchp_ptp_rxtstamp(struct mii_timestamper *mii_ts,
+ struct sk_buff *skb, int type)
+{
+ struct mchp_ptp_clock *ptp_clock = container_of(mii_ts,
+ struct mchp_ptp_clock,
+ mii_ts);
+
+ if (ptp_clock->rx_filter == HWTSTAMP_FILTER_NONE ||
+ type == PTP_CLASS_NONE)
+ return false;
+
+ if ((type & ptp_clock->version) == 0 || (type & ptp_clock->layer) == 0)
+ return false;
+
+ /* Here if match occurs skb is sent to application, If not skb is added
+ * to queue and sending skb to application will get handled when
+ * interrupt occurs i.e., it get handles in interrupt handler. By
+ * any means skb will reach the application so we should not return
+ * false here if skb doesn't matches.
+ */
+ mchp_ptp_match_rx_skb(ptp_clock, skb);
+
+ return true;
+}
+
+static int mchp_ptp_hwtstamp(struct mii_timestamper *mii_ts,
+ struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack *extack)
+{
+ struct mchp_ptp_clock *ptp_clock =
+ container_of(mii_ts, struct mchp_ptp_clock,
+ mii_ts);
+ struct phy_device *phydev = ptp_clock->phydev;
+ struct mchp_ptp_rx_ts *rx_ts, *tmp;
+ int txcfg = 0, rxcfg = 0;
+ int rc;
+
+ ptp_clock->hwts_tx_type = config->tx_type;
+ ptp_clock->rx_filter = config->rx_filter;
+
+ switch (config->rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ ptp_clock->layer = 0;
+ ptp_clock->version = 0;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ ptp_clock->layer = PTP_CLASS_L4;
+ ptp_clock->version = PTP_CLASS_V2;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ ptp_clock->layer = PTP_CLASS_L2;
+ ptp_clock->version = PTP_CLASS_V2;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ ptp_clock->layer = PTP_CLASS_L4 | PTP_CLASS_L2;
+ ptp_clock->version = PTP_CLASS_V2;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ /* Setup parsing of the frames and enable the timestamping for ptp
+ * frames
+ */
+ if (ptp_clock->layer & PTP_CLASS_L2) {
+ rxcfg = MCHP_PTP_PARSE_CONFIG_LAYER2_EN;
+ txcfg = MCHP_PTP_PARSE_CONFIG_LAYER2_EN;
+ }
+ if (ptp_clock->layer & PTP_CLASS_L4) {
+ rxcfg |= MCHP_PTP_PARSE_CONFIG_IPV4_EN |
+ MCHP_PTP_PARSE_CONFIG_IPV6_EN;
+ txcfg |= MCHP_PTP_PARSE_CONFIG_IPV4_EN |
+ MCHP_PTP_PARSE_CONFIG_IPV6_EN;
+ }
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_RX_PARSE_CONFIG(BASE_PORT(ptp_clock)),
+ rxcfg);
+ if (rc < 0)
+ return rc;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_PARSE_CONFIG(BASE_PORT(ptp_clock)),
+ txcfg);
+ if (rc < 0)
+ return rc;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_RX_TIMESTAMP_EN(BASE_PORT(ptp_clock)),
+ MCHP_PTP_TIMESTAMP_EN_ALL);
+ if (rc < 0)
+ return rc;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_TIMESTAMP_EN(BASE_PORT(ptp_clock)),
+ MCHP_PTP_TIMESTAMP_EN_ALL);
+ if (rc < 0)
+ return rc;
+
+ if (ptp_clock->hwts_tx_type == HWTSTAMP_TX_ONESTEP_SYNC)
+ /* Enable / disable of the TX timestamp in the SYNC frames */
+ rc = phy_modify_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_MOD(BASE_PORT(ptp_clock)),
+ MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT,
+ MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT);
+ else
+ rc = phy_modify_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_MOD(BASE_PORT(ptp_clock)),
+ MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT,
+ (u16)~MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT);
+
+ if (rc < 0)
+ return rc;
+
+ /* Now enable the timestamping interrupts */
+ rc = mchp_ptp_config_intr(ptp_clock,
+ config->rx_filter != HWTSTAMP_FILTER_NONE);
+ if (rc < 0)
+ return rc;
+
+ /* In case of multiple starts and stops, these needs to be cleared */
+ list_for_each_entry_safe(rx_ts, tmp, &ptp_clock->rx_ts_list, list) {
+ list_del(&rx_ts->list);
+ kfree(rx_ts);
+ }
+ skb_queue_purge(&ptp_clock->rx_queue);
+ skb_queue_purge(&ptp_clock->tx_queue);
+
+ rc = mchp_ptp_flush_fifo(ptp_clock, PTP_INGRESS_FIFO);
+ if (rc < 0)
+ return rc;
+
+ rc = mchp_ptp_flush_fifo(ptp_clock, PTP_EGRESS_FIFO);
+
+ return rc < 0 ? rc : 0;
+}
+
+static int mchp_ptp_ts_info(struct mii_timestamper *mii_ts,
+ struct kernel_ethtool_ts_info *info)
+{
+ struct mchp_ptp_clock *ptp_clock = container_of(mii_ts,
+ struct mchp_ptp_clock,
+ mii_ts);
+
+ info->phc_index =
+ ptp_clock->ptp_clock ? ptp_clock_index(ptp_clock->ptp_clock) : -1;
+ if (info->phc_index == -1)
+ return 0;
+
+ info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON) |
+ BIT(HWTSTAMP_TX_ONESTEP_SYNC);
+
+ info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
+
+ return 0;
+}
+
+static int mchp_ptp_ltc_adjtime(struct ptp_clock_info *info, s64 delta)
+{
+ struct mchp_ptp_clock *ptp_clock = container_of(info,
+ struct mchp_ptp_clock,
+ caps);
+ struct phy_device *phydev = ptp_clock->phydev;
+ struct timespec64 ts;
+ bool add = true;
+ int rc = 0;
+ u32 nsec;
+ s32 sec;
+
+ /* The HW allows up to 15 sec to adjust the time, but here we limit to
+ * 10 sec the adjustment. The reason is, in case the adjustment is 14
+ * sec and 999999999 nsec, then we add 8ns to compensate the actual
+ * increment so the value can be bigger than 15 sec. Therefore limit the
+ * possible adjustments so we will not have these corner cases
+ */
+ if (delta > 10000000000LL || delta < -10000000000LL) {
+ /* The timeadjustment is too big, so fall back using set time */
+ u64 now;
+
+ info->gettime64(info, &ts);
+
+ now = ktime_to_ns(timespec64_to_ktime(ts));
+ ts = ns_to_timespec64(now + delta);
+
+ info->settime64(info, &ts);
+ return 0;
+ }
+ sec = div_u64_rem(abs(delta), NSEC_PER_SEC, &nsec);
+ if (delta < 0 && nsec != 0) {
+ /* It is not allowed to adjust low the nsec part, therefore
+ * subtract more from second part and add to nanosecond such
+ * that would roll over, so the second part will increase
+ */
+ sec--;
+ nsec = NSEC_PER_SEC - nsec;
+ }
+
+ /* Calculate the adjustments and the direction */
+ if (delta < 0)
+ add = false;
+
+ if (nsec > 0) {
+ /* add 8 ns to cover the likely normal increment */
+ nsec += 8;
+
+ if (nsec >= NSEC_PER_SEC) {
+ /* carry into seconds */
+ sec++;
+ nsec -= NSEC_PER_SEC;
+ }
+ }
+
+ mutex_lock(&ptp_clock->ptp_lock);
+ if (sec) {
+ sec = abs(sec);
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_STEP_ADJ_LO(BASE_CLK(ptp_clock)),
+ sec);
+ if (rc < 0)
+ goto out_unlock;
+ rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_STEP_ADJ_HI(BASE_CLK(ptp_clock)),
+ ((add ? MCHP_PTP_LTC_STEP_ADJ_HI_DIR :
+ 0) | ((sec >> 16) & GENMASK(13, 0))));
+ if (rc < 0)
+ goto out_unlock;
+ rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
+ MCHP_PTP_CMD_CTL_LTC_STEP_SEC);
+ if (rc < 0)
+ goto out_unlock;
+ }
+
+ if (nsec) {
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_STEP_ADJ_LO(BASE_CLK(ptp_clock)),
+ nsec & GENMASK(15, 0));
+ if (rc < 0)
+ goto out_unlock;
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_STEP_ADJ_HI(BASE_CLK(ptp_clock)),
+ (nsec >> 16) & GENMASK(13, 0));
+ if (rc < 0)
+ goto out_unlock;
+ rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
+ MCHP_PTP_CMD_CTL_LTC_STEP_NSEC);
+ }
+
+out_unlock:
+ mutex_unlock(&ptp_clock->ptp_lock);
+
+ return rc;
+}
+
+static int mchp_ptp_ltc_adjfine(struct ptp_clock_info *info, long scaled_ppm)
+{
+ struct mchp_ptp_clock *ptp_clock = container_of(info,
+ struct mchp_ptp_clock,
+ caps);
+ struct phy_device *phydev = ptp_clock->phydev;
+ u16 rate_lo, rate_hi;
+ bool faster = true;
+ u32 rate;
+ int rc;
+
+ if (!scaled_ppm)
+ return 0;
+
+ if (scaled_ppm < 0) {
+ scaled_ppm = -scaled_ppm;
+ faster = false;
+ }
+
+ rate = MCHP_PTP_1PPM_FORMAT * (upper_16_bits(scaled_ppm));
+ rate += (MCHP_PTP_1PPM_FORMAT * (lower_16_bits(scaled_ppm))) >> 16;
+
+ rate_lo = rate & GENMASK(15, 0);
+ rate_hi = (rate >> 16) & GENMASK(13, 0);
+
+ if (faster)
+ rate_hi |= MCHP_PTP_LTC_RATE_ADJ_HI_DIR;
+
+ mutex_lock(&ptp_clock->ptp_lock);
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_RATE_ADJ_HI(BASE_CLK(ptp_clock)),
+ rate_hi);
+ if (rc < 0)
+ goto error;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_RATE_ADJ_LO(BASE_CLK(ptp_clock)),
+ rate_lo);
+ if (rc > 0)
+ rc = 0;
+error:
+ mutex_unlock(&ptp_clock->ptp_lock);
+
+ return rc;
+}
+
+static int mchp_ptp_ltc_gettime64(struct ptp_clock_info *info,
+ struct timespec64 *ts)
+{
+ struct mchp_ptp_clock *ptp_clock = container_of(info,
+ struct mchp_ptp_clock,
+ caps);
+ struct phy_device *phydev = ptp_clock->phydev;
+ time64_t secs;
+ int rc = 0;
+ s64 nsecs;
+
+ mutex_lock(&ptp_clock->ptp_lock);
+ /* Set read bit to 1 to save current values of 1588 local time counter
+ * into PTP LTC seconds and nanoseconds registers.
+ */
+ rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
+ MCHP_PTP_CMD_CTL_CLOCK_READ);
+ if (rc < 0)
+ goto out_unlock;
+
+ /* Get LTC clock values */
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_READ_SEC_HI(BASE_CLK(ptp_clock)));
+ if (rc < 0)
+ goto out_unlock;
+ secs = rc << 16;
+
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_READ_SEC_MID(BASE_CLK(ptp_clock)));
+ if (rc < 0)
+ goto out_unlock;
+ secs |= rc;
+ secs <<= 16;
+
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_READ_SEC_LO(BASE_CLK(ptp_clock)));
+ if (rc < 0)
+ goto out_unlock;
+ secs |= rc;
+
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_READ_NS_HI(BASE_CLK(ptp_clock)));
+ if (rc < 0)
+ goto out_unlock;
+ nsecs = (rc & GENMASK(13, 0));
+ nsecs <<= 16;
+
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_READ_NS_LO(BASE_CLK(ptp_clock)));
+ if (rc < 0)
+ goto out_unlock;
+ nsecs |= rc;
+
+ set_normalized_timespec64(ts, secs, nsecs);
+
+ if (rc > 0)
+ rc = 0;
+out_unlock:
+ mutex_unlock(&ptp_clock->ptp_lock);
+
+ return rc;
+}
+
+static int mchp_ptp_ltc_settime64(struct ptp_clock_info *info,
+ const struct timespec64 *ts)
+{
+ struct mchp_ptp_clock *ptp_clock = container_of(info,
+ struct mchp_ptp_clock,
+ caps);
+ struct phy_device *phydev = ptp_clock->phydev;
+ int rc;
+
+ mutex_lock(&ptp_clock->ptp_lock);
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_SEC_LO(BASE_CLK(ptp_clock)),
+ lower_16_bits(ts->tv_sec));
+ if (rc < 0)
+ goto out_unlock;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_SEC_MID(BASE_CLK(ptp_clock)),
+ upper_16_bits(ts->tv_sec));
+ if (rc < 0)
+ goto out_unlock;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_SEC_HI(BASE_CLK(ptp_clock)),
+ upper_32_bits(ts->tv_sec) & GENMASK(15, 0));
+ if (rc < 0)
+ goto out_unlock;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_NS_LO(BASE_CLK(ptp_clock)),
+ lower_16_bits(ts->tv_nsec));
+ if (rc < 0)
+ goto out_unlock;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LTC_NS_HI(BASE_CLK(ptp_clock)),
+ upper_16_bits(ts->tv_nsec) & GENMASK(13, 0));
+ if (rc < 0)
+ goto out_unlock;
+
+ /* Set load bit to 1 to write PTP LTC seconds and nanoseconds
+ * registers to 1588 local time counter.
+ */
+ rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
+ MCHP_PTP_CMD_CTL_CLOCK_LOAD);
+ if (rc > 0)
+ rc = 0;
+out_unlock:
+ mutex_unlock(&ptp_clock->ptp_lock);
+
+ return rc;
+}
+
+static bool mchp_ptp_get_sig_tx(struct sk_buff *skb, u16 *sig)
+{
+ struct ptp_header *ptp_header;
+ int type;
+
+ type = ptp_classify_raw(skb);
+ if (type == PTP_CLASS_NONE)
+ return false;
+
+ ptp_header = ptp_parse_header(skb, type);
+ if (!ptp_header)
+ return false;
+
+ *sig = htons(ptp_header->sequence_id);
+
+ return true;
+}
+
+static void mchp_ptp_match_tx_skb(struct mchp_ptp_clock *ptp_clock,
+ u32 seconds, u32 nsec, u16 seq_id)
+{
+ struct skb_shared_hwtstamps shhwtstamps;
+ struct sk_buff *skb, *skb_tmp;
+ unsigned long flags;
+ bool rc = false;
+ u16 skb_sig;
+
+ spin_lock_irqsave(&ptp_clock->tx_queue.lock, flags);
+ skb_queue_walk_safe(&ptp_clock->tx_queue, skb, skb_tmp) {
+ if (!mchp_ptp_get_sig_tx(skb, &skb_sig))
+ continue;
+
+ if (memcmp(&skb_sig, &seq_id, sizeof(seq_id)))
+ continue;
+
+ __skb_unlink(skb, &ptp_clock->tx_queue);
+ rc = true;
+ break;
+ }
+ spin_unlock_irqrestore(&ptp_clock->tx_queue.lock, flags);
+
+ if (rc) {
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ shhwtstamps.hwtstamp = ktime_set(seconds, nsec);
+ skb_complete_tx_timestamp(skb, &shhwtstamps);
+ }
+}
+
+static struct mchp_ptp_rx_ts *mchp_ptp_get_rx_ts(struct mchp_ptp_clock *ptp_clock)
+{
+ struct phy_device *phydev = ptp_clock->phydev;
+ struct mchp_ptp_rx_ts *rx_ts = NULL;
+ u32 sec, nsec;
+ u16 seq;
+ int rc;
+
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_RX_INGRESS_NS_HI(BASE_PORT(ptp_clock)));
+ if (rc < 0)
+ goto error;
+ if (!(rc & MCHP_PTP_RX_INGRESS_NS_HI_TS_VALID)) {
+ phydev_err(phydev, "RX Timestamp is not valid!\n");
+ goto error;
+ }
+ nsec = (rc & GENMASK(13, 0)) << 16;
+
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_RX_INGRESS_NS_LO(BASE_PORT(ptp_clock)));
+ if (rc < 0)
+ goto error;
+ nsec |= rc;
+
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_RX_INGRESS_SEC_HI(BASE_PORT(ptp_clock)));
+ if (rc < 0)
+ goto error;
+ sec = rc << 16;
+
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_RX_INGRESS_SEC_LO(BASE_PORT(ptp_clock)));
+ if (rc < 0)
+ goto error;
+ sec |= rc;
+
+ seq = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_RX_MSG_HEADER2(BASE_PORT(ptp_clock)));
+ if (seq < 0)
+ goto error;
+
+ rx_ts = kzalloc(sizeof(*rx_ts), GFP_KERNEL);
+ if (!rx_ts)
+ return NULL;
+
+ rx_ts->seconds = sec;
+ rx_ts->nsec = nsec;
+ rx_ts->seq_id = seq;
+
+error:
+ return rx_ts;
+}
+
+static void mchp_ptp_process_rx_ts(struct mchp_ptp_clock *ptp_clock)
+{
+ struct phy_device *phydev = ptp_clock->phydev;
+ int caps;
+
+ do {
+ struct mchp_ptp_rx_ts *rx_ts;
+
+ rx_ts = mchp_ptp_get_rx_ts(ptp_clock);
+ if (rx_ts)
+ mchp_ptp_match_rx_ts(ptp_clock, rx_ts);
+
+ caps = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_CAP_INFO(BASE_PORT(ptp_clock)));
+ if (caps < 0)
+ return;
+ } while (MCHP_PTP_RX_TS_CNT(caps) > 0);
+}
+
+static bool mchp_ptp_get_tx_ts(struct mchp_ptp_clock *ptp_clock,
+ u32 *sec, u32 *nsec, u16 *seq)
+{
+ struct phy_device *phydev = ptp_clock->phydev;
+ int rc;
+
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_EGRESS_NS_HI(BASE_PORT(ptp_clock)));
+ if (rc < 0)
+ return false;
+ if (!(rc & MCHP_PTP_TX_EGRESS_NS_HI_TS_VALID))
+ return false;
+ *nsec = (rc & GENMASK(13, 0)) << 16;
+
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_EGRESS_NS_LO(BASE_PORT(ptp_clock)));
+ if (rc < 0)
+ return false;
+ *nsec = *nsec | rc;
+
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_EGRESS_SEC_HI(BASE_PORT(ptp_clock)));
+ if (rc < 0)
+ return false;
+ *sec = rc << 16;
+
+ rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_EGRESS_SEC_LO(BASE_PORT(ptp_clock)));
+ if (rc < 0)
+ return false;
+ *sec = *sec | rc;
+
+ *seq = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_MSG_HEADER2(BASE_PORT(ptp_clock)));
+ if (*seq < 0)
+ return false;
+
+ return true;
+}
+
+static void mchp_ptp_process_tx_ts(struct mchp_ptp_clock *ptp_clock)
+{
+ struct phy_device *phydev = ptp_clock->phydev;
+ int caps;
+
+ do {
+ u32 sec, nsec;
+ u16 seq;
+
+ if (mchp_ptp_get_tx_ts(ptp_clock, &sec, &nsec, &seq))
+ mchp_ptp_match_tx_skb(ptp_clock, sec, nsec, seq);
+
+ caps = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_CAP_INFO(BASE_PORT(ptp_clock)));
+ if (caps < 0)
+ return;
+ } while (MCHP_PTP_TX_TS_CNT(caps) > 0);
+}
+
+int mchp_config_ptp_intr(struct mchp_ptp_clock *ptp_clock,
+ u16 reg, u16 val, bool clear)
+{
+ struct phy_device *phydev = ptp_clock->phydev;
+
+ if (clear)
+ return phy_clear_bits_mmd(phydev, PTP_MMD(ptp_clock), reg, val);
+ else
+ return phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock), reg, val);
+}
+EXPORT_SYMBOL_GPL(mchp_config_ptp_intr);
+
+irqreturn_t mchp_ptp_handle_interrupt(struct mchp_ptp_clock *ptp_clock)
+{
+ struct phy_device *phydev = ptp_clock->phydev;
+ int irq_status;
+
+ do {
+ irq_status = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_INT_STS(BASE_PORT(ptp_clock)));
+ if (irq_status < 0)
+ return IRQ_NONE;
+
+ if (irq_status & MCHP_PTP_INT_RX_TS_EN)
+ mchp_ptp_process_rx_ts(ptp_clock);
+
+ if (irq_status & MCHP_PTP_INT_TX_TS_EN)
+ mchp_ptp_process_tx_ts(ptp_clock);
+
+ if (irq_status & MCHP_PTP_INT_TX_TS_OVRFL_EN) {
+ mchp_ptp_flush_fifo(ptp_clock, PTP_EGRESS_FIFO);
+ skb_queue_purge(&ptp_clock->tx_queue);
+ }
+
+ if (irq_status & MCHP_PTP_INT_RX_TS_OVRFL_EN) {
+ mchp_ptp_flush_fifo(ptp_clock, PTP_INGRESS_FIFO);
+ skb_queue_purge(&ptp_clock->rx_queue);
+ }
+ } while (irq_status & (MCHP_PTP_INT_RX_TS_EN |
+ MCHP_PTP_INT_TX_TS_EN |
+ MCHP_PTP_INT_TX_TS_OVRFL_EN |
+ MCHP_PTP_INT_RX_TS_OVRFL_EN));
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(mchp_ptp_handle_interrupt);
+
+static int mchp_ptp_init(struct mchp_ptp_clock *ptp_clock)
+{
+ struct phy_device *phydev = ptp_clock->phydev;
+ int rc;
+
+ /* Disable PTP */
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
+ MCHP_PTP_CMD_CTL_DIS);
+ if (rc < 0)
+ return rc;
+
+ /* Disable TSU */
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TSU_GEN_CONFIG(BASE_PORT(ptp_clock)), 0);
+ if (rc < 0)
+ return rc;
+
+ /* Clear PTP interrupt status registers */
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TSU_HARD_RESET(BASE_PORT(ptp_clock)),
+ MCHP_PTP_TSU_HARDRESET);
+ if (rc < 0)
+ return rc;
+
+ /* Predictor enable */
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_LATENCY_CORRECTION_CTL(BASE_CLK(ptp_clock)),
+ MCHP_PTP_LATENCY_SETTING);
+ if (rc < 0)
+ return rc;
+
+ /* Configure PTP operational mode */
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_OP_MODE(BASE_CLK(ptp_clock)),
+ MCHP_PTP_OP_MODE_STANDALONE);
+ if (rc < 0)
+ return rc;
+
+ /* Reference clock configuration */
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_REF_CLK_CFG(BASE_CLK(ptp_clock)),
+ MCHP_PTP_REF_CLK_CFG_SET);
+ if (rc < 0)
+ return rc;
+
+ /* Classifier configurations */
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_RX_PARSE_CONFIG(BASE_PORT(ptp_clock)), 0);
+ if (rc < 0)
+ return rc;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_PARSE_CONFIG(BASE_PORT(ptp_clock)), 0);
+ if (rc < 0)
+ return rc;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_PARSE_L2_ADDR_EN(BASE_PORT(ptp_clock)),
+ 0);
+ if (rc < 0)
+ return rc;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_RX_PARSE_L2_ADDR_EN(BASE_PORT(ptp_clock)),
+ 0);
+ if (rc < 0)
+ return rc;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_RX_PARSE_IPV4_ADDR_EN(BASE_PORT(ptp_clock)),
+ 0);
+ if (rc < 0)
+ return rc;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_PARSE_IPV4_ADDR_EN(BASE_PORT(ptp_clock)),
+ 0);
+ if (rc < 0)
+ return rc;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_RX_VERSION(BASE_PORT(ptp_clock)),
+ MCHP_PTP_MAX_VERSION(0xff) | MCHP_PTP_MIN_VERSION(0x0));
+ if (rc < 0)
+ return rc;
+
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TX_VERSION(BASE_PORT(ptp_clock)),
+ MCHP_PTP_MAX_VERSION(0xff) | MCHP_PTP_MIN_VERSION(0x0));
+ if (rc < 0)
+ return rc;
+
+ /* Enable TSU */
+ rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_TSU_GEN_CONFIG(BASE_PORT(ptp_clock)),
+ MCHP_PTP_TSU_GEN_CFG_TSU_EN);
+ if (rc < 0)
+ return rc;
+
+ /* Enable PTP */
+ return phy_write_mmd(phydev, PTP_MMD(ptp_clock),
+ MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
+ MCHP_PTP_CMD_CTL_EN);
+}
+
+struct mchp_ptp_clock *mchp_ptp_probe(struct phy_device *phydev, u8 mmd,
+ u16 clk_base_addr, u16 port_base_addr)
+{
+ struct mchp_ptp_clock *clock;
+ int rc;
+
+ clock = devm_kzalloc(&phydev->mdio.dev, sizeof(*clock), GFP_KERNEL);
+ if (!clock)
+ return ERR_PTR(-ENOMEM);
+
+ clock->port_base_addr = port_base_addr;
+ clock->clk_base_addr = clk_base_addr;
+ clock->mmd = mmd;
+
+ /* Register PTP clock */
+ clock->caps.owner = THIS_MODULE;
+ snprintf(clock->caps.name, 30, "%s", phydev->drv->name);
+ clock->caps.max_adj = MCHP_PTP_MAX_ADJ;
+ clock->caps.n_ext_ts = 0;
+ clock->caps.pps = 0;
+ clock->caps.adjfine = mchp_ptp_ltc_adjfine;
+ clock->caps.adjtime = mchp_ptp_ltc_adjtime;
+ clock->caps.gettime64 = mchp_ptp_ltc_gettime64;
+ clock->caps.settime64 = mchp_ptp_ltc_settime64;
+ clock->ptp_clock = ptp_clock_register(&clock->caps,
+ &phydev->mdio.dev);
+ if (IS_ERR(clock->ptp_clock))
+ return ERR_PTR(-EINVAL);
+
+ /* Initialize the SW */
+ skb_queue_head_init(&clock->tx_queue);
+ skb_queue_head_init(&clock->rx_queue);
+ INIT_LIST_HEAD(&clock->rx_ts_list);
+ spin_lock_init(&clock->rx_ts_lock);
+ mutex_init(&clock->ptp_lock);
+
+ clock->mii_ts.rxtstamp = mchp_ptp_rxtstamp;
+ clock->mii_ts.txtstamp = mchp_ptp_txtstamp;
+ clock->mii_ts.hwtstamp = mchp_ptp_hwtstamp;
+ clock->mii_ts.ts_info = mchp_ptp_ts_info;
+
+ phydev->mii_ts = &clock->mii_ts;
+
+ /* Timestamp selected by default to keep legacy API */
+ phydev->default_timestamp = true;
+
+ clock->phydev = phydev;
+
+ rc = mchp_ptp_init(clock);
+ if (rc < 0)
+ return ERR_PTR(rc);
+
+ return clock;
+}
+EXPORT_SYMBOL_GPL(mchp_ptp_probe);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MICROCHIP PHY PTP driver");
+MODULE_AUTHOR("Divya Koppera");
--
2.17.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH net-next 3/5] net: phy: Kconfig: Add ptp library support and 1588 optional flag in Microchip phys
2024-11-04 9:07 [PATCH net-next 0/5] Add ptp library for Microchip phys Divya Koppera
2024-11-04 9:07 ` [PATCH net-next 1/5] net: phy: microchip_ptp : Add header file for Microchip ptp library Divya Koppera
2024-11-04 9:07 ` [PATCH net-next 2/5] net: phy: microchip_ptp : Add ptp library for Microchip phys Divya Koppera
@ 2024-11-04 9:07 ` Divya Koppera
2024-11-04 9:07 ` [PATCH net-next 4/5] net: phy: Makefile: Add makefile support for ptp " Divya Koppera
2024-11-04 9:07 ` [PATCH net-next 5/5] net: phy: microchip_t1 : Add initialization of ptp for lan887x Divya Koppera
4 siblings, 0 replies; 15+ messages in thread
From: Divya Koppera @ 2024-11-04 9:07 UTC (permalink / raw)
To: andrew, arun.ramadoss, UNGLinuxDriver, hkallweit1, linux, davem,
edumazet, kuba, pabeni, netdev, linux-kernel, richardcochran
Add ptp library support in Kconfig
As some of Microchip T1 phys support ptp, add dependency
of 1588 optional flag in Kconfig
Signed-off-by: Divya Koppera <divya.koppera@microchip.com>
---
drivers/net/phy/Kconfig | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index ee3ea0b56d48..22c274b42784 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -302,8 +302,15 @@ config MICROCHIP_PHY
config MICROCHIP_T1_PHY
tristate "Microchip T1 PHYs"
+ select MICROCHIP_PHYPTP if NETWORK_PHY_TIMESTAMPING
+ depends on PTP_1588_CLOCK_OPTIONAL
+ help
+ Supports the LAN8XXX PHYs.
+
+config MICROCHIP_PHYPTP
+ tristate "Microchip PHY PTP"
help
- Supports the LAN87XX PHYs.
+ Currently supports LAN887X T1 PHY
config MICROSEMI_PHY
tristate "Microsemi PHYs"
--
2.17.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH net-next 4/5] net: phy: Makefile: Add makefile support for ptp in Microchip phys
2024-11-04 9:07 [PATCH net-next 0/5] Add ptp library for Microchip phys Divya Koppera
` (2 preceding siblings ...)
2024-11-04 9:07 ` [PATCH net-next 3/5] net: phy: Kconfig: Add ptp library support and 1588 optional flag in " Divya Koppera
@ 2024-11-04 9:07 ` Divya Koppera
2024-11-05 1:40 ` kernel test robot
2024-11-05 3:57 ` kernel test robot
2024-11-04 9:07 ` [PATCH net-next 5/5] net: phy: microchip_t1 : Add initialization of ptp for lan887x Divya Koppera
4 siblings, 2 replies; 15+ messages in thread
From: Divya Koppera @ 2024-11-04 9:07 UTC (permalink / raw)
To: andrew, arun.ramadoss, UNGLinuxDriver, hkallweit1, linux, davem,
edumazet, kuba, pabeni, netdev, linux-kernel, richardcochran
Add makefile support for ptp library.
Signed-off-by: Divya Koppera <divya.koppera@microchip.com>
---
drivers/net/phy/Makefile | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 90f886844381..58a4a2953930 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o
obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
obj-$(CONFIG_MICROCHIP_PHY) += microchip.o
+obj-$(CONFIG_MICROCHIP_PHYPTP) += microchip_ptp.o
obj-$(CONFIG_MICROCHIP_T1_PHY) += microchip_t1.o
obj-$(CONFIG_MICROCHIP_T1S_PHY) += microchip_t1s.o
obj-$(CONFIG_MICROSEMI_PHY) += mscc/
--
2.17.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH net-next 5/5] net: phy: microchip_t1 : Add initialization of ptp for lan887x
2024-11-04 9:07 [PATCH net-next 0/5] Add ptp library for Microchip phys Divya Koppera
` (3 preceding siblings ...)
2024-11-04 9:07 ` [PATCH net-next 4/5] net: phy: Makefile: Add makefile support for ptp " Divya Koppera
@ 2024-11-04 9:07 ` Divya Koppera
2024-11-04 14:04 ` Andrew Lunn
2024-11-05 3:14 ` kernel test robot
4 siblings, 2 replies; 15+ messages in thread
From: Divya Koppera @ 2024-11-04 9:07 UTC (permalink / raw)
To: andrew, arun.ramadoss, UNGLinuxDriver, hkallweit1, linux, davem,
edumazet, kuba, pabeni, netdev, linux-kernel, richardcochran
Add initialization of ptp for lan887x.
Signed-off-by: Divya Koppera <divya.koppera@microchip.com>
---
drivers/net/phy/microchip_t1.c | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/drivers/net/phy/microchip_t1.c b/drivers/net/phy/microchip_t1.c
index 71d6050b2833..0a8b88d577c3 100644
--- a/drivers/net/phy/microchip_t1.c
+++ b/drivers/net/phy/microchip_t1.c
@@ -10,11 +10,15 @@
#include <linux/ethtool.h>
#include <linux/ethtool_netlink.h>
#include <linux/bitfield.h>
+#include "microchip_ptp.h"
#define PHY_ID_LAN87XX 0x0007c150
#define PHY_ID_LAN937X 0x0007c180
#define PHY_ID_LAN887X 0x0007c1f0
+#define MCHP_PTP_LTC_BASE_ADDR 0xe000
+#define MCHP_PTP_PORT_BASE_ADDR (MCHP_PTP_LTC_BASE_ADDR + 0x800)
+
/* External Register Control Register */
#define LAN87XX_EXT_REG_CTL (0x14)
#define LAN87XX_EXT_REG_CTL_RD_CTL (0x1000)
@@ -229,6 +233,7 @@
#define LAN887X_INT_STS 0xf000
#define LAN887X_INT_MSK 0xf001
+#define LAN887X_INT_MSK_P1588_MOD_INT_MSK BIT(3)
#define LAN887X_INT_MSK_T1_PHY_INT_MSK BIT(2)
#define LAN887X_INT_MSK_LINK_UP_MSK BIT(1)
#define LAN887X_INT_MSK_LINK_DOWN_MSK BIT(0)
@@ -319,6 +324,7 @@ struct lan887x_regwr_map {
struct lan887x_priv {
u64 stats[ARRAY_SIZE(lan887x_hw_stats)];
+ struct mchp_ptp_clock *clock;
};
static int lan937x_dsp_workaround(struct phy_device *phydev, u16 ereg, u8 bank)
@@ -1472,6 +1478,12 @@ static int lan887x_probe(struct phy_device *phydev)
phydev->priv = priv;
+ priv->clock = mchp_ptp_probe(phydev, MDIO_MMD_VEND1,
+ MCHP_PTP_LTC_BASE_ADDR,
+ MCHP_PTP_PORT_BASE_ADDR);
+ if (IS_ERR(priv->clock))
+ return PTR_ERR(priv->clock);
+
return lan887x_phy_setup(phydev);
}
@@ -1518,6 +1530,7 @@ static void lan887x_get_strings(struct phy_device *phydev, u8 *data)
static int lan887x_config_intr(struct phy_device *phydev)
{
+ struct lan887x_priv *priv = phydev->priv;
int rc;
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
@@ -1538,11 +1551,18 @@ static int lan887x_config_intr(struct phy_device *phydev)
rc = phy_read_mmd(phydev, MDIO_MMD_VEND1, LAN887X_INT_STS);
}
- return rc < 0 ? rc : 0;
+ if (rc < 0)
+ return rc;
+
+ return mchp_config_ptp_intr(priv->clock, LAN887X_INT_MSK,
+ LAN887X_INT_MSK_P1588_MOD_INT_MSK,
+ (phydev->interrupts == PHY_INTERRUPT_ENABLED));
}
static irqreturn_t lan887x_handle_interrupt(struct phy_device *phydev)
{
+ struct lan887x_priv *priv = phydev->priv;
+ int rc = IRQ_NONE;
int irq_status;
irq_status = phy_read_mmd(phydev, MDIO_MMD_VEND1, LAN887X_INT_STS);
@@ -1553,10 +1573,13 @@ static irqreturn_t lan887x_handle_interrupt(struct phy_device *phydev)
if (irq_status & LAN887X_MX_CHIP_TOP_LINK_MSK) {
phy_trigger_machine(phydev);
- return IRQ_HANDLED;
+ rc = IRQ_HANDLED;
}
- return IRQ_NONE;
+ if (irq_status & LAN887X_INT_MSK_P1588_MOD_INT_MSK)
+ rc = mchp_ptp_handle_interrupt(priv->clock);
+
+ return rc;
}
static int lan887x_cd_reset(struct phy_device *phydev,
--
2.17.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH net-next 2/5] net: phy: microchip_ptp : Add ptp library for Microchip phys
2024-11-04 9:07 ` [PATCH net-next 2/5] net: phy: microchip_ptp : Add ptp library for Microchip phys Divya Koppera
@ 2024-11-04 12:32 ` Vadim Fedorenko
2024-11-05 10:08 ` Divya.Koppera
2024-11-07 14:34 ` Simon Horman
1 sibling, 1 reply; 15+ messages in thread
From: Vadim Fedorenko @ 2024-11-04 12:32 UTC (permalink / raw)
To: Divya Koppera, andrew, arun.ramadoss, UNGLinuxDriver, hkallweit1,
linux, davem, edumazet, kuba, pabeni, netdev, linux-kernel,
richardcochran
On 04/11/2024 09:07, Divya Koppera wrote:
> Add ptp library for Microchip phys
> 1-step and 2-step modes are supported, over Ethernet and UDP(ipv4, ipv6)
>
> Signed-off-by: Divya Koppera <divya.koppera@microchip.com>
> ---
> drivers/net/phy/microchip_ptp.c | 990 ++++++++++++++++++++++++++++++++
> 1 file changed, 990 insertions(+)
> create mode 100644 drivers/net/phy/microchip_ptp.c
>
> diff --git a/drivers/net/phy/microchip_ptp.c b/drivers/net/phy/microchip_ptp.c
> new file mode 100644
> index 000000000000..45000984858e
> --- /dev/null
> +++ b/drivers/net/phy/microchip_ptp.c
> @@ -0,0 +1,990 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2024 Microchip Technology
> +
> +#include "microchip_ptp.h"
> +
> +static int mchp_ptp_flush_fifo(struct mchp_ptp_clock *ptp_clock,
> + enum ptp_fifo_dir dir)
> +{
> + struct phy_device *phydev = ptp_clock->phydev;
> + int rc;
> +
> + for (int i = 0; i < MCHP_PTP_FIFO_SIZE; ++i) {
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + dir == PTP_EGRESS_FIFO ?
> + MCHP_PTP_TX_MSG_HEADER2(BASE_PORT(ptp_clock)) :
> + MCHP_PTP_RX_MSG_HEADER2(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + return rc;
> + }
> + return phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_INT_STS(BASE_PORT(ptp_clock)));
> +}
> +
> +static int mchp_ptp_config_intr(struct mchp_ptp_clock *ptp_clock,
> + bool enable)
> +{
> + struct phy_device *phydev = ptp_clock->phydev;
> +
> + /* Enable or disable ptp interrupts */
> + return phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_INT_EN(BASE_PORT(ptp_clock)),
> + enable ? MCHP_PTP_INT_ALL_MSK : 0);
> +}
> +
> +static void mchp_ptp_txtstamp(struct mii_timestamper *mii_ts,
> + struct sk_buff *skb, int type)
> +{
> + struct mchp_ptp_clock *ptp_clock = container_of(mii_ts,
> + struct mchp_ptp_clock,
> + mii_ts);
> +
> + switch (ptp_clock->hwts_tx_type) {
> + case HWTSTAMP_TX_ONESTEP_SYNC:
> + if (ptp_msg_is_sync(skb, type)) {
> + kfree_skb(skb);
> + return;
> + }
> + fallthrough;
> + case HWTSTAMP_TX_ON:
> + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
> + skb_queue_tail(&ptp_clock->tx_queue, skb);
> + break;
> + case HWTSTAMP_TX_OFF:
> + default:
> + kfree_skb(skb);
> + break;
> + }
> +}
> +
> +static bool mchp_ptp_get_sig_rx(struct sk_buff *skb, u16 *sig)
> +{
> + struct ptp_header *ptp_header;
> + int type;
> +
> + skb_push(skb, ETH_HLEN);
> + type = ptp_classify_raw(skb);
> + if (type == PTP_CLASS_NONE)
> + return false;
> +
> + ptp_header = ptp_parse_header(skb, type);
> + if (!ptp_header)
> + return false;
> +
> + skb_pull_inline(skb, ETH_HLEN);
> +
> + *sig = ntohs(ptp_header->sequence_id);
> +
> + return true;
> +}
> +
> +static bool mchp_ptp_match_skb(struct mchp_ptp_clock *ptp_clock,
> + struct mchp_ptp_rx_ts *rx_ts)
> +{
> + struct skb_shared_hwtstamps *shhwtstamps;
> + struct sk_buff *skb, *skb_tmp;
> + unsigned long flags;
> + bool rc = false;
> + u16 skb_sig;
> +
> + spin_lock_irqsave(&ptp_clock->rx_queue.lock, flags);
> + skb_queue_walk_safe(&ptp_clock->rx_queue, skb, skb_tmp) {
> + if (!mchp_ptp_get_sig_rx(skb, &skb_sig))
> + continue;
> +
> + if (memcmp(&skb_sig, &rx_ts->seq_id, sizeof(rx_ts->seq_id)))
> + continue;
why do you use memcmp() instead of simple u16 comparison? It will be
optimized anyway, but still, why? The same question goes to other
comparisons futher in the file.
> +
> + __skb_unlink(skb, &ptp_clock->rx_queue);
> +
> + rc = true;
> + break;
> + }
> + spin_unlock_irqrestore(&ptp_clock->rx_queue.lock, flags);
> +
> + if (rc) {
> + shhwtstamps = skb_hwtstamps(skb);
> + memset(shhwtstamps, 0, sizeof(*shhwtstamps));
I don't think this memset is needed. hwtstamp is fully overwritten on
on the next line.
> + shhwtstamps->hwtstamp = ktime_set(rx_ts->seconds, rx_ts->nsec);
> + netif_rx(skb);
> + }
> +
> + return rc;
> +}
> +
> +static void mchp_ptp_match_rx_ts(struct mchp_ptp_clock *ptp_clock,
> + struct mchp_ptp_rx_ts *rx_ts)
> +{
> + unsigned long flags;
> +
> + /* If we failed to match the skb add it to the queue for when
> + * the frame will come
> + */
> + if (!mchp_ptp_match_skb(ptp_clock, rx_ts)) {
> + spin_lock_irqsave(&ptp_clock->rx_ts_lock, flags);
> + list_add(&rx_ts->list, &ptp_clock->rx_ts_list);
> + spin_unlock_irqrestore(&ptp_clock->rx_ts_lock, flags);
> + } else {
> + kfree(rx_ts);
> + }
> +}
> +
> +static void mchp_ptp_match_rx_skb(struct mchp_ptp_clock *ptp_clock,
> + struct sk_buff *skb)
> +{
> + struct skb_shared_hwtstamps *shhwtstamps;
> + struct mchp_ptp_rx_ts *rx_ts, *tmp;
> + unsigned long flags;
> + bool match = false;
> + u16 skb_sig;
> +
> + if (!mchp_ptp_get_sig_rx(skb, &skb_sig))
> + return;
> +
> + /* Iterate over all RX timestamps and match it with the received skbs */
> + spin_lock_irqsave(&ptp_clock->rx_ts_lock, flags);
> + list_for_each_entry_safe(rx_ts, tmp, &ptp_clock->rx_ts_list, list) {
> + /* Check if we found the signature we were looking for. */
> + if (memcmp(&skb_sig, &rx_ts->seq_id, sizeof(rx_ts->seq_id)))
> + continue;
> +
> + shhwtstamps = skb_hwtstamps(skb);
> + memset(shhwtstamps, 0, sizeof(*shhwtstamps));
and again - memset is useless here
> + shhwtstamps->hwtstamp = ktime_set(rx_ts->seconds,
> + rx_ts->nsec);
> + netif_rx(skb);
> +
> + list_del(&rx_ts->list);
> + kfree(rx_ts);
kfree can be done outside of spinlock as well as all other timestamp
manipulations to reduce spinlock scope.
> +
> + match = true;
> + break;
> + }
> + spin_unlock_irqrestore(&ptp_clock->rx_ts_lock, flags);
it's a good idea to think about RCU implementaton of the ts list as this
spinlock may become pretty hot on high packet rate.
> +
> + if (!match)
> + skb_queue_tail(&ptp_clock->rx_queue, skb);
> +}
> +
> +static bool mchp_ptp_rxtstamp(struct mii_timestamper *mii_ts,
> + struct sk_buff *skb, int type)
> +{
> + struct mchp_ptp_clock *ptp_clock = container_of(mii_ts,
> + struct mchp_ptp_clock,
> + mii_ts);
> +
> + if (ptp_clock->rx_filter == HWTSTAMP_FILTER_NONE ||
> + type == PTP_CLASS_NONE)
> + return false;
> +
> + if ((type & ptp_clock->version) == 0 || (type & ptp_clock->layer) == 0)
> + return false;
> +
> + /* Here if match occurs skb is sent to application, If not skb is added
> + * to queue and sending skb to application will get handled when
> + * interrupt occurs i.e., it get handles in interrupt handler. By
> + * any means skb will reach the application so we should not return
> + * false here if skb doesn't matches.
> + */
> + mchp_ptp_match_rx_skb(ptp_clock, skb);
> +
> + return true;
> +}
> +
> +static int mchp_ptp_hwtstamp(struct mii_timestamper *mii_ts,
> + struct kernel_hwtstamp_config *config,
> + struct netlink_ext_ack *extack)
> +{
> + struct mchp_ptp_clock *ptp_clock =
> + container_of(mii_ts, struct mchp_ptp_clock,
> + mii_ts);
> + struct phy_device *phydev = ptp_clock->phydev;
> + struct mchp_ptp_rx_ts *rx_ts, *tmp;
> + int txcfg = 0, rxcfg = 0;
> + int rc;
> +
> + ptp_clock->hwts_tx_type = config->tx_type;
> + ptp_clock->rx_filter = config->rx_filter;
> +
> + switch (config->rx_filter) {
> + case HWTSTAMP_FILTER_NONE:
> + ptp_clock->layer = 0;
> + ptp_clock->version = 0;
> + break;
> + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
> + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
> + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
> + ptp_clock->layer = PTP_CLASS_L4;
> + ptp_clock->version = PTP_CLASS_V2;
> + break;
> + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
> + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
> + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
> + ptp_clock->layer = PTP_CLASS_L2;
> + ptp_clock->version = PTP_CLASS_V2;
> + break;
> + case HWTSTAMP_FILTER_PTP_V2_EVENT:
> + case HWTSTAMP_FILTER_PTP_V2_SYNC:
> + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
> + ptp_clock->layer = PTP_CLASS_L4 | PTP_CLASS_L2;
> + ptp_clock->version = PTP_CLASS_V2;
> + break;
> + default:
> + return -ERANGE;
> + }
> +
> + /* Setup parsing of the frames and enable the timestamping for ptp
> + * frames
> + */
> + if (ptp_clock->layer & PTP_CLASS_L2) {
> + rxcfg = MCHP_PTP_PARSE_CONFIG_LAYER2_EN;
> + txcfg = MCHP_PTP_PARSE_CONFIG_LAYER2_EN;
> + }
> + if (ptp_clock->layer & PTP_CLASS_L4) {
> + rxcfg |= MCHP_PTP_PARSE_CONFIG_IPV4_EN |
> + MCHP_PTP_PARSE_CONFIG_IPV6_EN;
> + txcfg |= MCHP_PTP_PARSE_CONFIG_IPV4_EN |
> + MCHP_PTP_PARSE_CONFIG_IPV6_EN;
> + }
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_RX_PARSE_CONFIG(BASE_PORT(ptp_clock)),
> + rxcfg);
> + if (rc < 0)
> + return rc;
> +
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_TX_PARSE_CONFIG(BASE_PORT(ptp_clock)),
> + txcfg);
> + if (rc < 0)
> + return rc;
> +
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_RX_TIMESTAMP_EN(BASE_PORT(ptp_clock)),
> + MCHP_PTP_TIMESTAMP_EN_ALL);
> + if (rc < 0)
> + return rc;
> +
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_TX_TIMESTAMP_EN(BASE_PORT(ptp_clock)),
> + MCHP_PTP_TIMESTAMP_EN_ALL);
> + if (rc < 0)
> + return rc;
> +
> + if (ptp_clock->hwts_tx_type == HWTSTAMP_TX_ONESTEP_SYNC)
> + /* Enable / disable of the TX timestamp in the SYNC frames */
> + rc = phy_modify_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_TX_MOD(BASE_PORT(ptp_clock)),
> + MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT,
> + MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT);
> + else
> + rc = phy_modify_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_TX_MOD(BASE_PORT(ptp_clock)),
> + MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT,
> + (u16)~MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT);
> +
> + if (rc < 0)
> + return rc;
> +
> + /* Now enable the timestamping interrupts */
> + rc = mchp_ptp_config_intr(ptp_clock,
> + config->rx_filter != HWTSTAMP_FILTER_NONE);
> + if (rc < 0)
> + return rc;
> +
> + /* In case of multiple starts and stops, these needs to be cleared */
> + list_for_each_entry_safe(rx_ts, tmp, &ptp_clock->rx_ts_list, list) {
> + list_del(&rx_ts->list);
> + kfree(rx_ts);
> + }
I think this list clearing should be done under spinlock too.
> + skb_queue_purge(&ptp_clock->rx_queue);
> + skb_queue_purge(&ptp_clock->tx_queue);
> +
> + rc = mchp_ptp_flush_fifo(ptp_clock, PTP_INGRESS_FIFO);
> + if (rc < 0)
> + return rc;
> +
> + rc = mchp_ptp_flush_fifo(ptp_clock, PTP_EGRESS_FIFO);
> +
> + return rc < 0 ? rc : 0;
> +}
> +
> +static int mchp_ptp_ts_info(struct mii_timestamper *mii_ts,
> + struct kernel_ethtool_ts_info *info)
> +{
> + struct mchp_ptp_clock *ptp_clock = container_of(mii_ts,
> + struct mchp_ptp_clock,
> + mii_ts);
> +
> + info->phc_index =
> + ptp_clock->ptp_clock ? ptp_clock_index(ptp_clock->ptp_clock) : -1;
> + if (info->phc_index == -1)
> + return 0;
> +
> + info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
> + SOF_TIMESTAMPING_RX_HARDWARE |
> + SOF_TIMESTAMPING_RAW_HARDWARE;
> +
> + info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON) |
> + BIT(HWTSTAMP_TX_ONESTEP_SYNC);
> +
> + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
> + BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
> + BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
> + BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
> +
> + return 0;
> +}
> +
> +static int mchp_ptp_ltc_adjtime(struct ptp_clock_info *info, s64 delta)
> +{
> + struct mchp_ptp_clock *ptp_clock = container_of(info,
> + struct mchp_ptp_clock,
> + caps);
> + struct phy_device *phydev = ptp_clock->phydev;
> + struct timespec64 ts;
> + bool add = true;
> + int rc = 0;
> + u32 nsec;
> + s32 sec;
> +
> + /* The HW allows up to 15 sec to adjust the time, but here we limit to
> + * 10 sec the adjustment. The reason is, in case the adjustment is 14
> + * sec and 999999999 nsec, then we add 8ns to compensate the actual
> + * increment so the value can be bigger than 15 sec. Therefore limit the
> + * possible adjustments so we will not have these corner cases
> + */
> + if (delta > 10000000000LL || delta < -10000000000LL) {
> + /* The timeadjustment is too big, so fall back using set time */
> + u64 now;
> +
> + info->gettime64(info, &ts);
> +
> + now = ktime_to_ns(timespec64_to_ktime(ts));
> + ts = ns_to_timespec64(now + delta);
> +
> + info->settime64(info, &ts);
> + return 0;
> + }
> + sec = div_u64_rem(abs(delta), NSEC_PER_SEC, &nsec);
> + if (delta < 0 && nsec != 0) {
> + /* It is not allowed to adjust low the nsec part, therefore
> + * subtract more from second part and add to nanosecond such
> + * that would roll over, so the second part will increase
> + */
> + sec--;
> + nsec = NSEC_PER_SEC - nsec;
> + }
> +
> + /* Calculate the adjustments and the direction */
> + if (delta < 0)
> + add = false;
> +
> + if (nsec > 0) {
> + /* add 8 ns to cover the likely normal increment */
> + nsec += 8;
> +
> + if (nsec >= NSEC_PER_SEC) {
> + /* carry into seconds */
> + sec++;
> + nsec -= NSEC_PER_SEC;
> + }
> + }
> +
> + mutex_lock(&ptp_clock->ptp_lock);
> + if (sec) {
> + sec = abs(sec);
> +
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_STEP_ADJ_LO(BASE_CLK(ptp_clock)),
> + sec);
> + if (rc < 0)
> + goto out_unlock;
> + rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_STEP_ADJ_HI(BASE_CLK(ptp_clock)),
> + ((add ? MCHP_PTP_LTC_STEP_ADJ_HI_DIR :
> + 0) | ((sec >> 16) & GENMASK(13, 0))));
> + if (rc < 0)
> + goto out_unlock;
> + rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
> + MCHP_PTP_CMD_CTL_LTC_STEP_SEC);
> + if (rc < 0)
> + goto out_unlock;
> + }
> +
> + if (nsec) {
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_STEP_ADJ_LO(BASE_CLK(ptp_clock)),
> + nsec & GENMASK(15, 0));
> + if (rc < 0)
> + goto out_unlock;
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_STEP_ADJ_HI(BASE_CLK(ptp_clock)),
> + (nsec >> 16) & GENMASK(13, 0));
> + if (rc < 0)
> + goto out_unlock;
> + rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
> + MCHP_PTP_CMD_CTL_LTC_STEP_NSEC);
> + }
> +
> +out_unlock:
> + mutex_unlock(&ptp_clock->ptp_lock);
> +
> + return rc;
> +}
> +
> +static int mchp_ptp_ltc_adjfine(struct ptp_clock_info *info, long scaled_ppm)
> +{
> + struct mchp_ptp_clock *ptp_clock = container_of(info,
> + struct mchp_ptp_clock,
> + caps);
> + struct phy_device *phydev = ptp_clock->phydev;
> + u16 rate_lo, rate_hi;
> + bool faster = true;
> + u32 rate;
> + int rc;
> +
> + if (!scaled_ppm)
> + return 0;
> +
> + if (scaled_ppm < 0) {
> + scaled_ppm = -scaled_ppm;
> + faster = false;
> + }
> +
> + rate = MCHP_PTP_1PPM_FORMAT * (upper_16_bits(scaled_ppm));
> + rate += (MCHP_PTP_1PPM_FORMAT * (lower_16_bits(scaled_ppm))) >> 16;
> +
> + rate_lo = rate & GENMASK(15, 0);
> + rate_hi = (rate >> 16) & GENMASK(13, 0);
> +
> + if (faster)
> + rate_hi |= MCHP_PTP_LTC_RATE_ADJ_HI_DIR;
> +
> + mutex_lock(&ptp_clock->ptp_lock);
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_RATE_ADJ_HI(BASE_CLK(ptp_clock)),
> + rate_hi);
> + if (rc < 0)
> + goto error;
> +
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_RATE_ADJ_LO(BASE_CLK(ptp_clock)),
> + rate_lo);
> + if (rc > 0)
> + rc = 0;
> +error:
> + mutex_unlock(&ptp_clock->ptp_lock);
> +
> + return rc;
> +}
> +
> +static int mchp_ptp_ltc_gettime64(struct ptp_clock_info *info,
> + struct timespec64 *ts)
> +{
> + struct mchp_ptp_clock *ptp_clock = container_of(info,
> + struct mchp_ptp_clock,
> + caps);
> + struct phy_device *phydev = ptp_clock->phydev;
> + time64_t secs;
> + int rc = 0;
> + s64 nsecs;
> +
> + mutex_lock(&ptp_clock->ptp_lock);
> + /* Set read bit to 1 to save current values of 1588 local time counter
> + * into PTP LTC seconds and nanoseconds registers.
> + */
> + rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
> + MCHP_PTP_CMD_CTL_CLOCK_READ);
> + if (rc < 0)
> + goto out_unlock;
> +
> + /* Get LTC clock values */
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_READ_SEC_HI(BASE_CLK(ptp_clock)));
> + if (rc < 0)
> + goto out_unlock;
> + secs = rc << 16;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_READ_SEC_MID(BASE_CLK(ptp_clock)));
> + if (rc < 0)
> + goto out_unlock;
> + secs |= rc;
> + secs <<= 16;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_READ_SEC_LO(BASE_CLK(ptp_clock)));
> + if (rc < 0)
> + goto out_unlock;
> + secs |= rc;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_READ_NS_HI(BASE_CLK(ptp_clock)));
> + if (rc < 0)
> + goto out_unlock;
> + nsecs = (rc & GENMASK(13, 0));
> + nsecs <<= 16;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_READ_NS_LO(BASE_CLK(ptp_clock)));
> + if (rc < 0)
> + goto out_unlock;
> + nsecs |= rc;
> +
> + set_normalized_timespec64(ts, secs, nsecs);
> +
> + if (rc > 0)
> + rc = 0;
> +out_unlock:
> + mutex_unlock(&ptp_clock->ptp_lock);
That's interesting, but could the overwrapping happen to seconds counter
while reading nanoseconds? Usually high bits reading is wrapped into
while() loop to advoid such cases.
> +
> + return rc;
> +}
> +
> +static int mchp_ptp_ltc_settime64(struct ptp_clock_info *info,
> + const struct timespec64 *ts)
> +{
> + struct mchp_ptp_clock *ptp_clock = container_of(info,
> + struct mchp_ptp_clock,
> + caps);
> + struct phy_device *phydev = ptp_clock->phydev;
> + int rc;
> +
> + mutex_lock(&ptp_clock->ptp_lock);
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_SEC_LO(BASE_CLK(ptp_clock)),
> + lower_16_bits(ts->tv_sec));
> + if (rc < 0)
> + goto out_unlock;
> +
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_SEC_MID(BASE_CLK(ptp_clock)),
> + upper_16_bits(ts->tv_sec));
> + if (rc < 0)
> + goto out_unlock;
> +
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_SEC_HI(BASE_CLK(ptp_clock)),
> + upper_32_bits(ts->tv_sec) & GENMASK(15, 0));
> + if (rc < 0)
> + goto out_unlock;
> +
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_NS_LO(BASE_CLK(ptp_clock)),
> + lower_16_bits(ts->tv_nsec));
> + if (rc < 0)
> + goto out_unlock;
> +
> + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_LTC_NS_HI(BASE_CLK(ptp_clock)),
> + upper_16_bits(ts->tv_nsec) & GENMASK(13, 0));
> + if (rc < 0)
> + goto out_unlock;
> +
> + /* Set load bit to 1 to write PTP LTC seconds and nanoseconds
> + * registers to 1588 local time counter.
> + */
> + rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
> + MCHP_PTP_CMD_CTL_CLOCK_LOAD);
> + if (rc > 0)
> + rc = 0;
> +out_unlock:
> + mutex_unlock(&ptp_clock->ptp_lock);
> +
> + return rc;
> +}
> +
> +static bool mchp_ptp_get_sig_tx(struct sk_buff *skb, u16 *sig)
> +{
> + struct ptp_header *ptp_header;
> + int type;
> +
> + type = ptp_classify_raw(skb);
> + if (type == PTP_CLASS_NONE)
> + return false;
> +
> + ptp_header = ptp_parse_header(skb, type);
> + if (!ptp_header)
> + return false;
> +
> + *sig = htons(ptp_header->sequence_id);
> +
> + return true;
> +}
> +
> +static void mchp_ptp_match_tx_skb(struct mchp_ptp_clock *ptp_clock,
> + u32 seconds, u32 nsec, u16 seq_id)
> +{
> + struct skb_shared_hwtstamps shhwtstamps;
> + struct sk_buff *skb, *skb_tmp;
> + unsigned long flags;
> + bool rc = false;
> + u16 skb_sig;
> +
> + spin_lock_irqsave(&ptp_clock->tx_queue.lock, flags);
> + skb_queue_walk_safe(&ptp_clock->tx_queue, skb, skb_tmp) {
> + if (!mchp_ptp_get_sig_tx(skb, &skb_sig))
> + continue;
> +
> + if (memcmp(&skb_sig, &seq_id, sizeof(seq_id)))
> + continue;
> +
> + __skb_unlink(skb, &ptp_clock->tx_queue);
> + rc = true;
> + break;
> + }
> + spin_unlock_irqrestore(&ptp_clock->tx_queue.lock, flags);
> +
> + if (rc) {
> + memset(&shhwtstamps, 0, sizeof(shhwtstamps));
> + shhwtstamps.hwtstamp = ktime_set(seconds, nsec);
> + skb_complete_tx_timestamp(skb, &shhwtstamps);
> + }
> +}
> +
> +static struct mchp_ptp_rx_ts *mchp_ptp_get_rx_ts(struct mchp_ptp_clock *ptp_clock)
> +{
> + struct phy_device *phydev = ptp_clock->phydev;
> + struct mchp_ptp_rx_ts *rx_ts = NULL;
> + u32 sec, nsec;
> + u16 seq;
> + int rc;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_RX_INGRESS_NS_HI(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + goto error;
> + if (!(rc & MCHP_PTP_RX_INGRESS_NS_HI_TS_VALID)) {
> + phydev_err(phydev, "RX Timestamp is not valid!\n");
> + goto error;
> + }
> + nsec = (rc & GENMASK(13, 0)) << 16;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_RX_INGRESS_NS_LO(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + goto error;
> + nsec |= rc;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_RX_INGRESS_SEC_HI(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + goto error;
> + sec = rc << 16;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_RX_INGRESS_SEC_LO(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + goto error;
> + sec |= rc;
> +
> + seq = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_RX_MSG_HEADER2(BASE_PORT(ptp_clock)));
> + if (seq < 0)
> + goto error;
> +
> + rx_ts = kzalloc(sizeof(*rx_ts), GFP_KERNEL);
why zero out allocation? all fields of this structure are rewritten
unconditionally later (list_add happens in mchp_ptp_match_rx_ts) ...
> + if (!rx_ts)
> + return NULL;
> +
> + rx_ts->seconds = sec;
> + rx_ts->nsec = nsec;
> + rx_ts->seq_id = seq;
> +
> +error:
> + return rx_ts;
> +}
> +
> +static void mchp_ptp_process_rx_ts(struct mchp_ptp_clock *ptp_clock)
> +{
> + struct phy_device *phydev = ptp_clock->phydev;
> + int caps;
> +
> + do {
> + struct mchp_ptp_rx_ts *rx_ts;
> +
> + rx_ts = mchp_ptp_get_rx_ts(ptp_clock);
> + if (rx_ts)
> + mchp_ptp_match_rx_ts(ptp_clock, rx_ts);
> +
> + caps = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_CAP_INFO(BASE_PORT(ptp_clock)));
> + if (caps < 0)
> + return;
> + } while (MCHP_PTP_RX_TS_CNT(caps) > 0);
> +}
> +
[ ... ]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH net-next 5/5] net: phy: microchip_t1 : Add initialization of ptp for lan887x
2024-11-04 9:07 ` [PATCH net-next 5/5] net: phy: microchip_t1 : Add initialization of ptp for lan887x Divya Koppera
@ 2024-11-04 14:04 ` Andrew Lunn
2024-11-05 6:17 ` Divya.Koppera
2024-11-05 3:14 ` kernel test robot
1 sibling, 1 reply; 15+ messages in thread
From: Andrew Lunn @ 2024-11-04 14:04 UTC (permalink / raw)
To: Divya Koppera
Cc: arun.ramadoss, UNGLinuxDriver, hkallweit1, linux, davem, edumazet,
kuba, pabeni, netdev, linux-kernel, richardcochran
> static int lan937x_dsp_workaround(struct phy_device *phydev, u16 ereg, u8 bank)
> @@ -1472,6 +1478,12 @@ static int lan887x_probe(struct phy_device *phydev)
>
> phydev->priv = priv;
>
> + priv->clock = mchp_ptp_probe(phydev, MDIO_MMD_VEND1,
> + MCHP_PTP_LTC_BASE_ADDR,
> + MCHP_PTP_PORT_BASE_ADDR);
In general, PHY interrupts are optional, since phylib will poll the
PHY once per second for changes in link etc. Does mchp_ptp_probe() do
the right thing if the PHY does not have an interrupt?
Andrew
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH net-next 4/5] net: phy: Makefile: Add makefile support for ptp in Microchip phys
2024-11-04 9:07 ` [PATCH net-next 4/5] net: phy: Makefile: Add makefile support for ptp " Divya Koppera
@ 2024-11-05 1:40 ` kernel test robot
2024-11-05 3:57 ` kernel test robot
1 sibling, 0 replies; 15+ messages in thread
From: kernel test robot @ 2024-11-05 1:40 UTC (permalink / raw)
To: Divya Koppera, andrew, arun.ramadoss, UNGLinuxDriver, hkallweit1,
linux, davem, edumazet, kuba, pabeni, netdev, linux-kernel,
richardcochran
Cc: oe-kbuild-all
Hi Divya,
kernel test robot noticed the following build errors:
[auto build test ERROR on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/Divya-Koppera/net-phy-microchip_ptp-Add-header-file-for-Microchip-ptp-library/20241104-171132
base: net-next/main
patch link: https://lore.kernel.org/r/20241104090750.12942-5-divya.koppera%40microchip.com
patch subject: [PATCH net-next 4/5] net: phy: Makefile: Add makefile support for ptp in Microchip phys
config: i386-randconfig-052-20241105 (https://download.01.org/0day-ci/archive/20241105/202411050939.88HGuanR-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241105/202411050939.88HGuanR-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202411050939.88HGuanR-lkp@intel.com/
All error/warnings (new ones prefixed by >>):
In file included from drivers/net/phy/microchip_ptp.c:4:
>> drivers/net/phy/microchip_ptp.h:197:60: warning: declaration of 'struct phy_device' will not be visible outside of this function [-Wvisibility]
197 | static inline struct mchp_ptp_clock *mchp_ptp_probe(struct phy_device *phydev,
| ^
>> drivers/net/phy/microchip_ptp.h:198:11: error: unknown type name 'u8'
198 | u8 mmd, u16 clk_base,
| ^
>> drivers/net/phy/microchip_ptp.h:198:19: error: unknown type name 'u16'
198 | u8 mmd, u16 clk_base,
| ^
drivers/net/phy/microchip_ptp.h:199:11: error: unknown type name 'u16'
199 | u16 port_base)
| ^
drivers/net/phy/microchip_ptp.h:205:12: error: unknown type name 'u16'
205 | u16 reg, u16 val, bool enable)
| ^
drivers/net/phy/microchip_ptp.h:205:21: error: unknown type name 'u16'
205 | u16 reg, u16 val, bool enable)
| ^
>> drivers/net/phy/microchip_ptp.h:205:30: error: unknown type name 'bool'
205 | u16 reg, u16 val, bool enable)
| ^
>> drivers/net/phy/microchip_ptp.h:210:15: error: unknown type name 'irqreturn_t'
210 | static inline irqreturn_t mchp_ptp_handle_interrupt(struct mchp_ptp_clock *ptp_clock)
| ^
>> drivers/net/phy/microchip_ptp.h:212:9: error: use of undeclared identifier 'IRQ_NONE'
212 | return IRQ_NONE;
| ^
>> drivers/net/phy/microchip_ptp.c:7:16: warning: declaration of 'enum ptp_fifo_dir' will not be visible outside of this function [-Wvisibility]
7 | enum ptp_fifo_dir dir)
| ^
>> drivers/net/phy/microchip_ptp.c:7:29: error: variable has incomplete type 'enum ptp_fifo_dir'
7 | enum ptp_fifo_dir dir)
| ^
drivers/net/phy/microchip_ptp.c:7:16: note: forward declaration of 'enum ptp_fifo_dir'
7 | enum ptp_fifo_dir dir)
| ^
>> drivers/net/phy/microchip_ptp.c:9:39: error: incomplete definition of type 'struct mchp_ptp_clock'
9 | struct phy_device *phydev = ptp_clock->phydev;
| ~~~~~~~~~^
drivers/net/phy/microchip_ptp.h:197:22: note: forward declaration of 'struct mchp_ptp_clock'
197 | static inline struct mchp_ptp_clock *mchp_ptp_probe(struct phy_device *phydev,
| ^
>> drivers/net/phy/microchip_ptp.c:12:22: error: use of undeclared identifier 'MCHP_PTP_FIFO_SIZE'
12 | for (int i = 0; i < MCHP_PTP_FIFO_SIZE; ++i) {
| ^
>> drivers/net/phy/microchip_ptp.c:13:8: error: call to undeclared function 'phy_read_mmd'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
13 | rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
| ^
>> drivers/net/phy/microchip_ptp.c:13:29: error: call to undeclared function 'PTP_MMD'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
13 | rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
| ^
>> drivers/net/phy/microchip_ptp.c:15:7: error: call to undeclared function 'MCHP_PTP_TX_MSG_HEADER2'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
15 | MCHP_PTP_TX_MSG_HEADER2(BASE_PORT(ptp_clock)) :
| ^
>> drivers/net/phy/microchip_ptp.c:15:31: error: call to undeclared function 'BASE_PORT'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
15 | MCHP_PTP_TX_MSG_HEADER2(BASE_PORT(ptp_clock)) :
| ^
>> drivers/net/phy/microchip_ptp.c:16:7: error: call to undeclared function 'MCHP_PTP_RX_MSG_HEADER2'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
16 | MCHP_PTP_RX_MSG_HEADER2(BASE_PORT(ptp_clock)));
| ^
>> drivers/net/phy/microchip_ptp.c:14:14: error: use of undeclared identifier 'PTP_EGRESS_FIFO'
14 | dir == PTP_EGRESS_FIFO ?
| ^
drivers/net/phy/microchip_ptp.c:20:9: error: call to undeclared function 'phy_read_mmd'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
20 | return phy_read_mmd(phydev, PTP_MMD(ptp_clock),
| ^
drivers/net/phy/microchip_ptp.c:20:30: error: call to undeclared function 'PTP_MMD'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
20 | return phy_read_mmd(phydev, PTP_MMD(ptp_clock),
| ^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
2 warnings and 20 errors generated.
vim +/u8 +198 drivers/net/phy/microchip_ptp.h
ca38715fe9dd463 Divya Koppera 2024-11-04 196
ca38715fe9dd463 Divya Koppera 2024-11-04 @197 static inline struct mchp_ptp_clock *mchp_ptp_probe(struct phy_device *phydev,
ca38715fe9dd463 Divya Koppera 2024-11-04 @198 u8 mmd, u16 clk_base,
ca38715fe9dd463 Divya Koppera 2024-11-04 199 u16 port_base)
ca38715fe9dd463 Divya Koppera 2024-11-04 200 {
ca38715fe9dd463 Divya Koppera 2024-11-04 201 return 0;
ca38715fe9dd463 Divya Koppera 2024-11-04 202 }
ca38715fe9dd463 Divya Koppera 2024-11-04 203
ca38715fe9dd463 Divya Koppera 2024-11-04 204 static inline int mchp_config_ptp_intr(struct mchp_ptp_clock *ptp_clock,
ca38715fe9dd463 Divya Koppera 2024-11-04 @205 u16 reg, u16 val, bool enable)
ca38715fe9dd463 Divya Koppera 2024-11-04 206 {
ca38715fe9dd463 Divya Koppera 2024-11-04 207 return 0;
ca38715fe9dd463 Divya Koppera 2024-11-04 208 }
ca38715fe9dd463 Divya Koppera 2024-11-04 209
ca38715fe9dd463 Divya Koppera 2024-11-04 @210 static inline irqreturn_t mchp_ptp_handle_interrupt(struct mchp_ptp_clock *ptp_clock)
ca38715fe9dd463 Divya Koppera 2024-11-04 211 {
ca38715fe9dd463 Divya Koppera 2024-11-04 @212 return IRQ_NONE;
ca38715fe9dd463 Divya Koppera 2024-11-04 213 }
ca38715fe9dd463 Divya Koppera 2024-11-04 214
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH net-next 5/5] net: phy: microchip_t1 : Add initialization of ptp for lan887x
2024-11-04 9:07 ` [PATCH net-next 5/5] net: phy: microchip_t1 : Add initialization of ptp for lan887x Divya Koppera
2024-11-04 14:04 ` Andrew Lunn
@ 2024-11-05 3:14 ` kernel test robot
1 sibling, 0 replies; 15+ messages in thread
From: kernel test robot @ 2024-11-05 3:14 UTC (permalink / raw)
To: Divya Koppera, andrew, arun.ramadoss, UNGLinuxDriver, hkallweit1,
linux, davem, edumazet, kuba, pabeni, netdev, linux-kernel,
richardcochran
Cc: oe-kbuild-all
Hi Divya,
kernel test robot noticed the following build warnings:
[auto build test WARNING on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/Divya-Koppera/net-phy-microchip_ptp-Add-header-file-for-Microchip-ptp-library/20241104-171132
base: net-next/main
patch link: https://lore.kernel.org/r/20241104090750.12942-6-divya.koppera%40microchip.com
patch subject: [PATCH net-next 5/5] net: phy: microchip_t1 : Add initialization of ptp for lan887x
config: x86_64-randconfig-121-20241105 (https://download.01.org/0day-ci/archive/20241105/202411051039.Yz1kJCOl-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241105/202411051039.Yz1kJCOl-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202411051039.Yz1kJCOl-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
drivers/net/phy/microchip_t1.c: note: in included file:
>> drivers/net/phy/microchip_ptp.h:201:16: sparse: sparse: Using plain integer as NULL pointer
vim +201 drivers/net/phy/microchip_ptp.h
ca38715fe9dd46 Divya Koppera 2024-11-04 196
ca38715fe9dd46 Divya Koppera 2024-11-04 197 static inline struct mchp_ptp_clock *mchp_ptp_probe(struct phy_device *phydev,
ca38715fe9dd46 Divya Koppera 2024-11-04 198 u8 mmd, u16 clk_base,
ca38715fe9dd46 Divya Koppera 2024-11-04 199 u16 port_base)
ca38715fe9dd46 Divya Koppera 2024-11-04 200 {
ca38715fe9dd46 Divya Koppera 2024-11-04 @201 return 0;
ca38715fe9dd46 Divya Koppera 2024-11-04 202 }
ca38715fe9dd46 Divya Koppera 2024-11-04 203
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH net-next 4/5] net: phy: Makefile: Add makefile support for ptp in Microchip phys
2024-11-04 9:07 ` [PATCH net-next 4/5] net: phy: Makefile: Add makefile support for ptp " Divya Koppera
2024-11-05 1:40 ` kernel test robot
@ 2024-11-05 3:57 ` kernel test robot
1 sibling, 0 replies; 15+ messages in thread
From: kernel test robot @ 2024-11-05 3:57 UTC (permalink / raw)
To: Divya Koppera, andrew, arun.ramadoss, UNGLinuxDriver, hkallweit1,
linux, davem, edumazet, kuba, pabeni, netdev, linux-kernel,
richardcochran
Cc: oe-kbuild-all
Hi Divya,
kernel test robot noticed the following build errors:
[auto build test ERROR on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/Divya-Koppera/net-phy-microchip_ptp-Add-header-file-for-Microchip-ptp-library/20241104-171132
base: net-next/main
patch link: https://lore.kernel.org/r/20241104090750.12942-5-divya.koppera%40microchip.com
patch subject: [PATCH net-next 4/5] net: phy: Makefile: Add makefile support for ptp in Microchip phys
config: powerpc64-randconfig-r063-20241105 (https://download.01.org/0day-ci/archive/20241105/202411051137.XUgYrwtP-lkp@intel.com/config)
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241105/202411051137.XUgYrwtP-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202411051137.XUgYrwtP-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from drivers/net/phy/microchip_ptp.c:4:
drivers/net/phy/microchip_ptp.h:197:60: warning: declaration of 'struct phy_device' will not be visible outside of this function [-Wvisibility]
static inline struct mchp_ptp_clock *mchp_ptp_probe(struct phy_device *phydev,
^
drivers/net/phy/microchip_ptp.h:198:11: error: unknown type name 'u8'
u8 mmd, u16 clk_base,
^
drivers/net/phy/microchip_ptp.h:198:19: error: unknown type name 'u16'
u8 mmd, u16 clk_base,
^
drivers/net/phy/microchip_ptp.h:199:11: error: unknown type name 'u16'
u16 port_base)
^
drivers/net/phy/microchip_ptp.h:205:12: error: unknown type name 'u16'
u16 reg, u16 val, bool enable)
^
drivers/net/phy/microchip_ptp.h:205:21: error: unknown type name 'u16'
u16 reg, u16 val, bool enable)
^
drivers/net/phy/microchip_ptp.h:205:30: error: unknown type name 'bool'
u16 reg, u16 val, bool enable)
^
drivers/net/phy/microchip_ptp.h:210:15: error: unknown type name 'irqreturn_t'
static inline irqreturn_t mchp_ptp_handle_interrupt(struct mchp_ptp_clock *ptp_clock)
^
drivers/net/phy/microchip_ptp.h:212:9: error: use of undeclared identifier 'IRQ_NONE'
return IRQ_NONE;
^
drivers/net/phy/microchip_ptp.c:7:16: warning: declaration of 'enum ptp_fifo_dir' will not be visible outside of this function [-Wvisibility]
enum ptp_fifo_dir dir)
^
drivers/net/phy/microchip_ptp.c:7:29: error: variable has incomplete type 'enum ptp_fifo_dir'
enum ptp_fifo_dir dir)
^
drivers/net/phy/microchip_ptp.c:7:16: note: forward declaration of 'enum ptp_fifo_dir'
enum ptp_fifo_dir dir)
^
drivers/net/phy/microchip_ptp.c:9:39: error: incomplete definition of type 'struct mchp_ptp_clock'
struct phy_device *phydev = ptp_clock->phydev;
~~~~~~~~~^
drivers/net/phy/microchip_ptp.h:197:22: note: forward declaration of 'struct mchp_ptp_clock'
static inline struct mchp_ptp_clock *mchp_ptp_probe(struct phy_device *phydev,
^
drivers/net/phy/microchip_ptp.c:12:22: error: use of undeclared identifier 'MCHP_PTP_FIFO_SIZE'
for (int i = 0; i < MCHP_PTP_FIFO_SIZE; ++i) {
^
>> drivers/net/phy/microchip_ptp.c:13:8: error: implicit declaration of function 'phy_read_mmd' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
^
>> drivers/net/phy/microchip_ptp.c:13:29: error: implicit declaration of function 'PTP_MMD' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
^
drivers/net/phy/microchip_ptp.c:14:14: error: use of undeclared identifier 'PTP_EGRESS_FIFO'
dir == PTP_EGRESS_FIFO ?
^
>> drivers/net/phy/microchip_ptp.c:15:7: error: implicit declaration of function 'MCHP_PTP_TX_MSG_HEADER2' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
MCHP_PTP_TX_MSG_HEADER2(BASE_PORT(ptp_clock)) :
^
>> drivers/net/phy/microchip_ptp.c:15:31: error: implicit declaration of function 'BASE_PORT' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
MCHP_PTP_TX_MSG_HEADER2(BASE_PORT(ptp_clock)) :
^
>> drivers/net/phy/microchip_ptp.c:16:7: error: implicit declaration of function 'MCHP_PTP_RX_MSG_HEADER2' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
MCHP_PTP_RX_MSG_HEADER2(BASE_PORT(ptp_clock)));
^
drivers/net/phy/microchip_ptp.c:16:7: note: did you mean 'MCHP_PTP_TX_MSG_HEADER2'?
drivers/net/phy/microchip_ptp.c:15:7: note: 'MCHP_PTP_TX_MSG_HEADER2' declared here
MCHP_PTP_TX_MSG_HEADER2(BASE_PORT(ptp_clock)) :
^
drivers/net/phy/microchip_ptp.c:20:9: error: implicit declaration of function 'phy_read_mmd' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
return phy_read_mmd(phydev, PTP_MMD(ptp_clock),
^
drivers/net/phy/microchip_ptp.c:20:30: error: implicit declaration of function 'PTP_MMD' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
return phy_read_mmd(phydev, PTP_MMD(ptp_clock),
^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
2 warnings and 20 errors generated.
vim +/phy_read_mmd +13 drivers/net/phy/microchip_ptp.c
cf630bd2326111 Divya Koppera 2024-11-04 5
cf630bd2326111 Divya Koppera 2024-11-04 6 static int mchp_ptp_flush_fifo(struct mchp_ptp_clock *ptp_clock,
cf630bd2326111 Divya Koppera 2024-11-04 7 enum ptp_fifo_dir dir)
cf630bd2326111 Divya Koppera 2024-11-04 8 {
cf630bd2326111 Divya Koppera 2024-11-04 9 struct phy_device *phydev = ptp_clock->phydev;
cf630bd2326111 Divya Koppera 2024-11-04 10 int rc;
cf630bd2326111 Divya Koppera 2024-11-04 11
cf630bd2326111 Divya Koppera 2024-11-04 12 for (int i = 0; i < MCHP_PTP_FIFO_SIZE; ++i) {
cf630bd2326111 Divya Koppera 2024-11-04 @13 rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
cf630bd2326111 Divya Koppera 2024-11-04 14 dir == PTP_EGRESS_FIFO ?
cf630bd2326111 Divya Koppera 2024-11-04 @15 MCHP_PTP_TX_MSG_HEADER2(BASE_PORT(ptp_clock)) :
cf630bd2326111 Divya Koppera 2024-11-04 @16 MCHP_PTP_RX_MSG_HEADER2(BASE_PORT(ptp_clock)));
cf630bd2326111 Divya Koppera 2024-11-04 17 if (rc < 0)
cf630bd2326111 Divya Koppera 2024-11-04 18 return rc;
cf630bd2326111 Divya Koppera 2024-11-04 19 }
cf630bd2326111 Divya Koppera 2024-11-04 20 return phy_read_mmd(phydev, PTP_MMD(ptp_clock),
cf630bd2326111 Divya Koppera 2024-11-04 21 MCHP_PTP_INT_STS(BASE_PORT(ptp_clock)));
cf630bd2326111 Divya Koppera 2024-11-04 22 }
cf630bd2326111 Divya Koppera 2024-11-04 23
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 15+ messages in thread
* RE: [PATCH net-next 5/5] net: phy: microchip_t1 : Add initialization of ptp for lan887x
2024-11-04 14:04 ` Andrew Lunn
@ 2024-11-05 6:17 ` Divya.Koppera
0 siblings, 0 replies; 15+ messages in thread
From: Divya.Koppera @ 2024-11-05 6:17 UTC (permalink / raw)
To: andrew
Cc: Arun.Ramadoss, UNGLinuxDriver, hkallweit1, linux, davem, edumazet,
kuba, pabeni, netdev, linux-kernel, richardcochran
Hi Andrew,
Thanks for the comments.
> -----Original Message-----
> From: Andrew Lunn <andrew@lunn.ch>
> Sent: Monday, November 4, 2024 7:34 PM
> To: Divya Koppera - I30481 <Divya.Koppera@microchip.com>
> Cc: Arun Ramadoss - I17769 <Arun.Ramadoss@microchip.com>;
> UNGLinuxDriver <UNGLinuxDriver@microchip.com>; hkallweit1@gmail.com;
> linux@armlinux.org.uk; davem@davemloft.net; edumazet@google.com;
> kuba@kernel.org; pabeni@redhat.com; netdev@vger.kernel.org; linux-
> kernel@vger.kernel.org; richardcochran@gmail.com
> Subject: Re: [PATCH net-next 5/5] net: phy: microchip_t1 : Add initialization of
> ptp for lan887x
>
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the
> content is safe
>
> > static int lan937x_dsp_workaround(struct phy_device *phydev, u16
> > ereg, u8 bank) @@ -1472,6 +1478,12 @@ static int lan887x_probe(struct
> > phy_device *phydev)
> >
> > phydev->priv = priv;
> >
> > + priv->clock = mchp_ptp_probe(phydev, MDIO_MMD_VEND1,
> > + MCHP_PTP_LTC_BASE_ADDR,
> > + MCHP_PTP_PORT_BASE_ADDR);
>
> In general, PHY interrupts are optional, since phylib will poll the PHY once per
> second for changes in link etc. Does mchp_ptp_probe() do the right thing if
> the PHY does not have an interrupt?
>
Interrupts must be enabled by integrating platform(MAC/Switch).
Currently mchp_ptp_probe() is not checking for interrupts flag and also irq might not be initialized by the time probe is called.
To handle this, mchp_ptp_probe need to be called once from config_init instead of probe where a valid irq is available.
Based on IRQ number, we can skip ptp enabling from config_init and set default_timestamp=false.
Let me know if this approach is acceptable in interrupts disabled case.
> Andrew
Thanks,
Divya
^ permalink raw reply [flat|nested] 15+ messages in thread
* RE: [PATCH net-next 2/5] net: phy: microchip_ptp : Add ptp library for Microchip phys
2024-11-04 12:32 ` Vadim Fedorenko
@ 2024-11-05 10:08 ` Divya.Koppera
0 siblings, 0 replies; 15+ messages in thread
From: Divya.Koppera @ 2024-11-05 10:08 UTC (permalink / raw)
To: vadim.fedorenko, andrew, Arun.Ramadoss, UNGLinuxDriver,
hkallweit1, linux, davem, edumazet, kuba, pabeni, netdev,
linux-kernel, richardcochran
Hi @Vadim Fedorenko,
Thanks for your comments.
> -----Original Message-----
> From: Vadim Fedorenko <vadim.fedorenko@linux.dev>
> Sent: Monday, November 4, 2024 6:03 PM
> To: Divya Koppera - I30481 <Divya.Koppera@microchip.com>;
> andrew@lunn.ch; Arun Ramadoss - I17769
> <Arun.Ramadoss@microchip.com>; UNGLinuxDriver
> <UNGLinuxDriver@microchip.com>; hkallweit1@gmail.com;
> linux@armlinux.org.uk; davem@davemloft.net; edumazet@google.com;
> kuba@kernel.org; pabeni@redhat.com; netdev@vger.kernel.org; linux-
> kernel@vger.kernel.org; richardcochran@gmail.com
> Subject: Re: [PATCH net-next 2/5] net: phy: microchip_ptp : Add ptp library for
> Microchip phys
>
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the
> content is safe
>
> On 04/11/2024 09:07, Divya Koppera wrote:
> > Add ptp library for Microchip phys
> > 1-step and 2-step modes are supported, over Ethernet and UDP(ipv4,
> > ipv6)
> >
> > Signed-off-by: Divya Koppera <divya.koppera@microchip.com>
> > ---
> > drivers/net/phy/microchip_ptp.c | 990
> ++++++++++++++++++++++++++++++++
> > 1 file changed, 990 insertions(+)
> > create mode 100644 drivers/net/phy/microchip_ptp.c
> >
> > diff --git a/drivers/net/phy/microchip_ptp.c
> > b/drivers/net/phy/microchip_ptp.c new file mode 100644 index
> > 000000000000..45000984858e
> > --- /dev/null
> > +++ b/drivers/net/phy/microchip_ptp.c
> > @@ -0,0 +1,990 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +// Copyright (C) 2024 Microchip Technology
> > +
> > +#include "microchip_ptp.h"
> > +
> > +static int mchp_ptp_flush_fifo(struct mchp_ptp_clock *ptp_clock,
> > + enum ptp_fifo_dir dir) {
> > + struct phy_device *phydev = ptp_clock->phydev;
> > + int rc;
> > +
> > + for (int i = 0; i < MCHP_PTP_FIFO_SIZE; ++i) {
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + dir == PTP_EGRESS_FIFO ?
> > + MCHP_PTP_TX_MSG_HEADER2(BASE_PORT(ptp_clock)) :
> > + MCHP_PTP_RX_MSG_HEADER2(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + return rc;
> > + }
> > + return phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_INT_STS(BASE_PORT(ptp_clock)));
> > +}
> > +
> > +static int mchp_ptp_config_intr(struct mchp_ptp_clock *ptp_clock,
> > + bool enable) {
> > + struct phy_device *phydev = ptp_clock->phydev;
> > +
> > + /* Enable or disable ptp interrupts */
> > + return phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_INT_EN(BASE_PORT(ptp_clock)),
> > + enable ? MCHP_PTP_INT_ALL_MSK : 0); }
> > +
> > +static void mchp_ptp_txtstamp(struct mii_timestamper *mii_ts,
> > + struct sk_buff *skb, int type) {
> > + struct mchp_ptp_clock *ptp_clock = container_of(mii_ts,
> > + struct mchp_ptp_clock,
> > + mii_ts);
> > +
> > + switch (ptp_clock->hwts_tx_type) {
> > + case HWTSTAMP_TX_ONESTEP_SYNC:
> > + if (ptp_msg_is_sync(skb, type)) {
> > + kfree_skb(skb);
> > + return;
> > + }
> > + fallthrough;
> > + case HWTSTAMP_TX_ON:
> > + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
> > + skb_queue_tail(&ptp_clock->tx_queue, skb);
> > + break;
> > + case HWTSTAMP_TX_OFF:
> > + default:
> > + kfree_skb(skb);
> > + break;
> > + }
> > +}
> > +
> > +static bool mchp_ptp_get_sig_rx(struct sk_buff *skb, u16 *sig) {
> > + struct ptp_header *ptp_header;
> > + int type;
> > +
> > + skb_push(skb, ETH_HLEN);
> > + type = ptp_classify_raw(skb);
> > + if (type == PTP_CLASS_NONE)
> > + return false;
> > +
> > + ptp_header = ptp_parse_header(skb, type);
> > + if (!ptp_header)
> > + return false;
> > +
> > + skb_pull_inline(skb, ETH_HLEN);
> > +
> > + *sig = ntohs(ptp_header->sequence_id);
> > +
> > + return true;
> > +}
> > +
> > +static bool mchp_ptp_match_skb(struct mchp_ptp_clock *ptp_clock,
> > + struct mchp_ptp_rx_ts *rx_ts) {
> > + struct skb_shared_hwtstamps *shhwtstamps;
> > + struct sk_buff *skb, *skb_tmp;
> > + unsigned long flags;
> > + bool rc = false;
> > + u16 skb_sig;
> > +
> > + spin_lock_irqsave(&ptp_clock->rx_queue.lock, flags);
> > + skb_queue_walk_safe(&ptp_clock->rx_queue, skb, skb_tmp) {
> > + if (!mchp_ptp_get_sig_rx(skb, &skb_sig))
> > + continue;
> > +
> > + if (memcmp(&skb_sig, &rx_ts->seq_id, sizeof(rx_ts->seq_id)))
> > + continue;
>
> why do you use memcmp() instead of simple u16 comparison? It will be
> optimized anyway, but still, why? The same question goes to other
> comparisons futher in the file.
>
Yes, need to simplify it. Will change in next revision at all the required places.
> > +
> > + __skb_unlink(skb, &ptp_clock->rx_queue);
> > +
> > + rc = true;
> > + break;
> > + }
> > + spin_unlock_irqrestore(&ptp_clock->rx_queue.lock, flags);
> > +
> > + if (rc) {
> > + shhwtstamps = skb_hwtstamps(skb);
> > + memset(shhwtstamps, 0, sizeof(*shhwtstamps));
>
> I don't think this memset is needed. hwtstamp is fully overwritten on on the
> next line.
>
I Will check on this and update.
> > + shhwtstamps->hwtstamp = ktime_set(rx_ts->seconds, rx_ts->nsec);
> > + netif_rx(skb);
> > + }
> > +
> > + return rc;
> > +}
> > +
> > +static void mchp_ptp_match_rx_ts(struct mchp_ptp_clock *ptp_clock,
> > + struct mchp_ptp_rx_ts *rx_ts) {
> > + unsigned long flags;
> > +
> > + /* If we failed to match the skb add it to the queue for when
> > + * the frame will come
> > + */
> > + if (!mchp_ptp_match_skb(ptp_clock, rx_ts)) {
> > + spin_lock_irqsave(&ptp_clock->rx_ts_lock, flags);
> > + list_add(&rx_ts->list, &ptp_clock->rx_ts_list);
> > + spin_unlock_irqrestore(&ptp_clock->rx_ts_lock, flags);
> > + } else {
> > + kfree(rx_ts);
> > + }
> > +}
> > +
> > +static void mchp_ptp_match_rx_skb(struct mchp_ptp_clock *ptp_clock,
> > + struct sk_buff *skb) {
> > + struct skb_shared_hwtstamps *shhwtstamps;
> > + struct mchp_ptp_rx_ts *rx_ts, *tmp;
> > + unsigned long flags;
> > + bool match = false;
> > + u16 skb_sig;
> > +
> > + if (!mchp_ptp_get_sig_rx(skb, &skb_sig))
> > + return;
> > +
> > + /* Iterate over all RX timestamps and match it with the received skbs */
> > + spin_lock_irqsave(&ptp_clock->rx_ts_lock, flags);
> > + list_for_each_entry_safe(rx_ts, tmp, &ptp_clock->rx_ts_list, list) {
> > + /* Check if we found the signature we were looking for. */
> > + if (memcmp(&skb_sig, &rx_ts->seq_id, sizeof(rx_ts->seq_id)))
> > + continue;
> > +
> > + shhwtstamps = skb_hwtstamps(skb);
> > + memset(shhwtstamps, 0, sizeof(*shhwtstamps));
>
> and again - memset is useless here
>
> > + shhwtstamps->hwtstamp = ktime_set(rx_ts->seconds,
> > + rx_ts->nsec);
> > + netif_rx(skb);
> > +
> > + list_del(&rx_ts->list);
> > + kfree(rx_ts);
>
> kfree can be done outside of spinlock as well as all other timestamp
> manipulations to reduce spinlock scope.
Ok. Will change.
> > +
> > + match = true;
> > + break;
> > + }
> > + spin_unlock_irqrestore(&ptp_clock->rx_ts_lock, flags);
>
> it's a good idea to think about RCU implementaton of the ts list as this
> spinlock may become pretty hot on high packet rate.
>
I'm new to this RCU, at present will continue using this. Will take care in further new developments.
> > +
> > + if (!match)
> > + skb_queue_tail(&ptp_clock->rx_queue, skb); }
> > +
> > +static bool mchp_ptp_rxtstamp(struct mii_timestamper *mii_ts,
> > + struct sk_buff *skb, int type) {
> > + struct mchp_ptp_clock *ptp_clock = container_of(mii_ts,
> > + struct mchp_ptp_clock,
> > + mii_ts);
> > +
> > + if (ptp_clock->rx_filter == HWTSTAMP_FILTER_NONE ||
> > + type == PTP_CLASS_NONE)
> > + return false;
> > +
> > + if ((type & ptp_clock->version) == 0 || (type & ptp_clock->layer) == 0)
> > + return false;
> > +
> > + /* Here if match occurs skb is sent to application, If not skb is added
> > + * to queue and sending skb to application will get handled when
> > + * interrupt occurs i.e., it get handles in interrupt handler. By
> > + * any means skb will reach the application so we should not return
> > + * false here if skb doesn't matches.
> > + */
> > + mchp_ptp_match_rx_skb(ptp_clock, skb);
> > +
> > + return true;
> > +}
> > +
> > +static int mchp_ptp_hwtstamp(struct mii_timestamper *mii_ts,
> > + struct kernel_hwtstamp_config *config,
> > + struct netlink_ext_ack *extack) {
> > + struct mchp_ptp_clock *ptp_clock =
> > + container_of(mii_ts, struct mchp_ptp_clock,
> > + mii_ts);
> > + struct phy_device *phydev = ptp_clock->phydev;
> > + struct mchp_ptp_rx_ts *rx_ts, *tmp;
> > + int txcfg = 0, rxcfg = 0;
> > + int rc;
> > +
> > + ptp_clock->hwts_tx_type = config->tx_type;
> > + ptp_clock->rx_filter = config->rx_filter;
> > +
> > + switch (config->rx_filter) {
> > + case HWTSTAMP_FILTER_NONE:
> > + ptp_clock->layer = 0;
> > + ptp_clock->version = 0;
> > + break;
> > + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
> > + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
> > + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
> > + ptp_clock->layer = PTP_CLASS_L4;
> > + ptp_clock->version = PTP_CLASS_V2;
> > + break;
> > + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
> > + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
> > + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
> > + ptp_clock->layer = PTP_CLASS_L2;
> > + ptp_clock->version = PTP_CLASS_V2;
> > + break;
> > + case HWTSTAMP_FILTER_PTP_V2_EVENT:
> > + case HWTSTAMP_FILTER_PTP_V2_SYNC:
> > + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
> > + ptp_clock->layer = PTP_CLASS_L4 | PTP_CLASS_L2;
> > + ptp_clock->version = PTP_CLASS_V2;
> > + break;
> > + default:
> > + return -ERANGE;
> > + }
> > +
> > + /* Setup parsing of the frames and enable the timestamping for ptp
> > + * frames
> > + */
> > + if (ptp_clock->layer & PTP_CLASS_L2) {
> > + rxcfg = MCHP_PTP_PARSE_CONFIG_LAYER2_EN;
> > + txcfg = MCHP_PTP_PARSE_CONFIG_LAYER2_EN;
> > + }
> > + if (ptp_clock->layer & PTP_CLASS_L4) {
> > + rxcfg |= MCHP_PTP_PARSE_CONFIG_IPV4_EN |
> > + MCHP_PTP_PARSE_CONFIG_IPV6_EN;
> > + txcfg |= MCHP_PTP_PARSE_CONFIG_IPV4_EN |
> > + MCHP_PTP_PARSE_CONFIG_IPV6_EN;
> > + }
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_RX_PARSE_CONFIG(BASE_PORT(ptp_clock)),
> > + rxcfg);
> > + if (rc < 0)
> > + return rc;
> > +
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_TX_PARSE_CONFIG(BASE_PORT(ptp_clock)),
> > + txcfg);
> > + if (rc < 0)
> > + return rc;
> > +
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_RX_TIMESTAMP_EN(BASE_PORT(ptp_clock)),
> > + MCHP_PTP_TIMESTAMP_EN_ALL);
> > + if (rc < 0)
> > + return rc;
> > +
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_TX_TIMESTAMP_EN(BASE_PORT(ptp_clock)),
> > + MCHP_PTP_TIMESTAMP_EN_ALL);
> > + if (rc < 0)
> > + return rc;
> > +
> > + if (ptp_clock->hwts_tx_type == HWTSTAMP_TX_ONESTEP_SYNC)
> > + /* Enable / disable of the TX timestamp in the SYNC frames */
> > + rc = phy_modify_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_TX_MOD(BASE_PORT(ptp_clock)),
> > + MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT,
> > + MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT);
> > + else
> > + rc = phy_modify_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_TX_MOD(BASE_PORT(ptp_clock)),
> > + MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT,
> > +
> > + (u16)~MCHP_PTP_TX_MOD_PTP_SYNC_TS_INSERT);
> > +
> > + if (rc < 0)
> > + return rc;
> > +
> > + /* Now enable the timestamping interrupts */
> > + rc = mchp_ptp_config_intr(ptp_clock,
> > + config->rx_filter != HWTSTAMP_FILTER_NONE);
> > + if (rc < 0)
> > + return rc;
> > +
> > + /* In case of multiple starts and stops, these needs to be cleared */
> > + list_for_each_entry_safe(rx_ts, tmp, &ptp_clock->rx_ts_list, list) {
> > + list_del(&rx_ts->list);
> > + kfree(rx_ts);
> > + }
>
> I think this list clearing should be done under spinlock too.
>
Yes, will update.
> > + skb_queue_purge(&ptp_clock->rx_queue);
> > + skb_queue_purge(&ptp_clock->tx_queue);
> > +
> > + rc = mchp_ptp_flush_fifo(ptp_clock, PTP_INGRESS_FIFO);
> > + if (rc < 0)
> > + return rc;
> > +
> > + rc = mchp_ptp_flush_fifo(ptp_clock, PTP_EGRESS_FIFO);
> > +
> > + return rc < 0 ? rc : 0;
> > +}
> > +
> > +static int mchp_ptp_ts_info(struct mii_timestamper *mii_ts,
> > + struct kernel_ethtool_ts_info *info) {
> > + struct mchp_ptp_clock *ptp_clock = container_of(mii_ts,
> > + struct mchp_ptp_clock,
> > + mii_ts);
> > +
> > + info->phc_index =
> > + ptp_clock->ptp_clock ? ptp_clock_index(ptp_clock->ptp_clock) : -1;
> > + if (info->phc_index == -1)
> > + return 0;
> > +
> > + info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
> > + SOF_TIMESTAMPING_RX_HARDWARE |
> > + SOF_TIMESTAMPING_RAW_HARDWARE;
> > +
> > + info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON) |
> > + BIT(HWTSTAMP_TX_ONESTEP_SYNC);
> > +
> > + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
> > + BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
> > + BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
> > + BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
> > +
> > + return 0;
> > +}
> > +
> > +static int mchp_ptp_ltc_adjtime(struct ptp_clock_info *info, s64
> > +delta) {
> > + struct mchp_ptp_clock *ptp_clock = container_of(info,
> > + struct mchp_ptp_clock,
> > + caps);
> > + struct phy_device *phydev = ptp_clock->phydev;
> > + struct timespec64 ts;
> > + bool add = true;
> > + int rc = 0;
> > + u32 nsec;
> > + s32 sec;
> > +
> > + /* The HW allows up to 15 sec to adjust the time, but here we limit to
> > + * 10 sec the adjustment. The reason is, in case the adjustment is 14
> > + * sec and 999999999 nsec, then we add 8ns to compensate the actual
> > + * increment so the value can be bigger than 15 sec. Therefore limit the
> > + * possible adjustments so we will not have these corner cases
> > + */
> > + if (delta > 10000000000LL || delta < -10000000000LL) {
> > + /* The timeadjustment is too big, so fall back using set time */
> > + u64 now;
> > +
> > + info->gettime64(info, &ts);
> > +
> > + now = ktime_to_ns(timespec64_to_ktime(ts));
> > + ts = ns_to_timespec64(now + delta);
> > +
> > + info->settime64(info, &ts);
> > + return 0;
> > + }
> > + sec = div_u64_rem(abs(delta), NSEC_PER_SEC, &nsec);
> > + if (delta < 0 && nsec != 0) {
> > + /* It is not allowed to adjust low the nsec part, therefore
> > + * subtract more from second part and add to nanosecond such
> > + * that would roll over, so the second part will increase
> > + */
> > + sec--;
> > + nsec = NSEC_PER_SEC - nsec;
> > + }
> > +
> > + /* Calculate the adjustments and the direction */
> > + if (delta < 0)
> > + add = false;
> > +
> > + if (nsec > 0) {
> > + /* add 8 ns to cover the likely normal increment */
> > + nsec += 8;
> > +
> > + if (nsec >= NSEC_PER_SEC) {
> > + /* carry into seconds */
> > + sec++;
> > + nsec -= NSEC_PER_SEC;
> > + }
> > + }
> > +
> > + mutex_lock(&ptp_clock->ptp_lock);
> > + if (sec) {
> > + sec = abs(sec);
> > +
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_STEP_ADJ_LO(BASE_CLK(ptp_clock)),
> > + sec);
> > + if (rc < 0)
> > + goto out_unlock;
> > + rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_STEP_ADJ_HI(BASE_CLK(ptp_clock)),
> > + ((add ? MCHP_PTP_LTC_STEP_ADJ_HI_DIR :
> > + 0) | ((sec >> 16) & GENMASK(13, 0))));
> > + if (rc < 0)
> > + goto out_unlock;
> > + rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
> > + MCHP_PTP_CMD_CTL_LTC_STEP_SEC);
> > + if (rc < 0)
> > + goto out_unlock;
> > + }
> > +
> > + if (nsec) {
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_STEP_ADJ_LO(BASE_CLK(ptp_clock)),
> > + nsec & GENMASK(15, 0));
> > + if (rc < 0)
> > + goto out_unlock;
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_STEP_ADJ_HI(BASE_CLK(ptp_clock)),
> > + (nsec >> 16) & GENMASK(13, 0));
> > + if (rc < 0)
> > + goto out_unlock;
> > + rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
> > + MCHP_PTP_CMD_CTL_LTC_STEP_NSEC);
> > + }
> > +
> > +out_unlock:
> > + mutex_unlock(&ptp_clock->ptp_lock);
> > +
> > + return rc;
> > +}
> > +
> > +static int mchp_ptp_ltc_adjfine(struct ptp_clock_info *info, long
> > +scaled_ppm) {
> > + struct mchp_ptp_clock *ptp_clock = container_of(info,
> > + struct mchp_ptp_clock,
> > + caps);
> > + struct phy_device *phydev = ptp_clock->phydev;
> > + u16 rate_lo, rate_hi;
> > + bool faster = true;
> > + u32 rate;
> > + int rc;
> > +
> > + if (!scaled_ppm)
> > + return 0;
> > +
> > + if (scaled_ppm < 0) {
> > + scaled_ppm = -scaled_ppm;
> > + faster = false;
> > + }
> > +
> > + rate = MCHP_PTP_1PPM_FORMAT * (upper_16_bits(scaled_ppm));
> > + rate += (MCHP_PTP_1PPM_FORMAT * (lower_16_bits(scaled_ppm))) >>
> > + 16;
> > +
> > + rate_lo = rate & GENMASK(15, 0);
> > + rate_hi = (rate >> 16) & GENMASK(13, 0);
> > +
> > + if (faster)
> > + rate_hi |= MCHP_PTP_LTC_RATE_ADJ_HI_DIR;
> > +
> > + mutex_lock(&ptp_clock->ptp_lock);
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_RATE_ADJ_HI(BASE_CLK(ptp_clock)),
> > + rate_hi);
> > + if (rc < 0)
> > + goto error;
> > +
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_RATE_ADJ_LO(BASE_CLK(ptp_clock)),
> > + rate_lo);
> > + if (rc > 0)
> > + rc = 0;
> > +error:
> > + mutex_unlock(&ptp_clock->ptp_lock);
> > +
> > + return rc;
> > +}
> > +
> > +static int mchp_ptp_ltc_gettime64(struct ptp_clock_info *info,
> > + struct timespec64 *ts) {
> > + struct mchp_ptp_clock *ptp_clock = container_of(info,
> > + struct mchp_ptp_clock,
> > + caps);
> > + struct phy_device *phydev = ptp_clock->phydev;
> > + time64_t secs;
> > + int rc = 0;
> > + s64 nsecs;
> > +
> > + mutex_lock(&ptp_clock->ptp_lock);
> > + /* Set read bit to 1 to save current values of 1588 local time counter
> > + * into PTP LTC seconds and nanoseconds registers.
> > + */
> > + rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
> > + MCHP_PTP_CMD_CTL_CLOCK_READ);
> > + if (rc < 0)
> > + goto out_unlock;
> > +
> > + /* Get LTC clock values */
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_READ_SEC_HI(BASE_CLK(ptp_clock)));
> > + if (rc < 0)
> > + goto out_unlock;
> > + secs = rc << 16;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_READ_SEC_MID(BASE_CLK(ptp_clock)));
> > + if (rc < 0)
> > + goto out_unlock;
> > + secs |= rc;
> > + secs <<= 16;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_READ_SEC_LO(BASE_CLK(ptp_clock)));
> > + if (rc < 0)
> > + goto out_unlock;
> > + secs |= rc;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_READ_NS_HI(BASE_CLK(ptp_clock)));
> > + if (rc < 0)
> > + goto out_unlock;
> > + nsecs = (rc & GENMASK(13, 0));
> > + nsecs <<= 16;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_READ_NS_LO(BASE_CLK(ptp_clock)));
> > + if (rc < 0)
> > + goto out_unlock;
> > + nsecs |= rc;
> > +
> > + set_normalized_timespec64(ts, secs, nsecs);
> > +
> > + if (rc > 0)
> > + rc = 0;
> > +out_unlock:
> > + mutex_unlock(&ptp_clock->ptp_lock);
>
> That's interesting, but could the overwrapping happen to seconds counter
> while reading nanoseconds? Usually high bits reading is wrapped into
> while() loop to advoid such cases.
>
We are reading the static values that are written in register at particular time when read bit is set.
Nsecs will not be more than 1000000000, which further will not increment or decrement secs.
So overwrapping to seconds counter while reading nanoseconds will not happen.
Safer way we can assign the values directly.
> > +
> > + return rc;
> > +}
> > +
> > +static int mchp_ptp_ltc_settime64(struct ptp_clock_info *info,
> > + const struct timespec64 *ts) {
> > + struct mchp_ptp_clock *ptp_clock = container_of(info,
> > + struct mchp_ptp_clock,
> > + caps);
> > + struct phy_device *phydev = ptp_clock->phydev;
> > + int rc;
> > +
> > + mutex_lock(&ptp_clock->ptp_lock);
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_SEC_LO(BASE_CLK(ptp_clock)),
> > + lower_16_bits(ts->tv_sec));
> > + if (rc < 0)
> > + goto out_unlock;
> > +
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_SEC_MID(BASE_CLK(ptp_clock)),
> > + upper_16_bits(ts->tv_sec));
> > + if (rc < 0)
> > + goto out_unlock;
> > +
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_SEC_HI(BASE_CLK(ptp_clock)),
> > + upper_32_bits(ts->tv_sec) & GENMASK(15, 0));
> > + if (rc < 0)
> > + goto out_unlock;
> > +
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_NS_LO(BASE_CLK(ptp_clock)),
> > + lower_16_bits(ts->tv_nsec));
> > + if (rc < 0)
> > + goto out_unlock;
> > +
> > + rc = phy_write_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_LTC_NS_HI(BASE_CLK(ptp_clock)),
> > + upper_16_bits(ts->tv_nsec) & GENMASK(13, 0));
> > + if (rc < 0)
> > + goto out_unlock;
> > +
> > + /* Set load bit to 1 to write PTP LTC seconds and nanoseconds
> > + * registers to 1588 local time counter.
> > + */
> > + rc = phy_set_bits_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_CMD_CTL(BASE_CLK(ptp_clock)),
> > + MCHP_PTP_CMD_CTL_CLOCK_LOAD);
> > + if (rc > 0)
> > + rc = 0;
> > +out_unlock:
> > + mutex_unlock(&ptp_clock->ptp_lock);
> > +
> > + return rc;
> > +}
> > +
> > +static bool mchp_ptp_get_sig_tx(struct sk_buff *skb, u16 *sig) {
> > + struct ptp_header *ptp_header;
> > + int type;
> > +
> > + type = ptp_classify_raw(skb);
> > + if (type == PTP_CLASS_NONE)
> > + return false;
> > +
> > + ptp_header = ptp_parse_header(skb, type);
> > + if (!ptp_header)
> > + return false;
> > +
> > + *sig = htons(ptp_header->sequence_id);
> > +
> > + return true;
> > +}
> > +
> > +static void mchp_ptp_match_tx_skb(struct mchp_ptp_clock *ptp_clock,
> > + u32 seconds, u32 nsec, u16 seq_id) {
> > + struct skb_shared_hwtstamps shhwtstamps;
> > + struct sk_buff *skb, *skb_tmp;
> > + unsigned long flags;
> > + bool rc = false;
> > + u16 skb_sig;
> > +
> > + spin_lock_irqsave(&ptp_clock->tx_queue.lock, flags);
> > + skb_queue_walk_safe(&ptp_clock->tx_queue, skb, skb_tmp) {
> > + if (!mchp_ptp_get_sig_tx(skb, &skb_sig))
> > + continue;
> > +
> > + if (memcmp(&skb_sig, &seq_id, sizeof(seq_id)))
> > + continue;
> > +
> > + __skb_unlink(skb, &ptp_clock->tx_queue);
> > + rc = true;
> > + break;
> > + }
> > + spin_unlock_irqrestore(&ptp_clock->tx_queue.lock, flags);
> > +
> > + if (rc) {
> > + memset(&shhwtstamps, 0, sizeof(shhwtstamps));
> > + shhwtstamps.hwtstamp = ktime_set(seconds, nsec);
> > + skb_complete_tx_timestamp(skb, &shhwtstamps);
> > + }
> > +}
> > +
> > +static struct mchp_ptp_rx_ts *mchp_ptp_get_rx_ts(struct
> > +mchp_ptp_clock *ptp_clock) {
> > + struct phy_device *phydev = ptp_clock->phydev;
> > + struct mchp_ptp_rx_ts *rx_ts = NULL;
> > + u32 sec, nsec;
> > + u16 seq;
> > + int rc;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_RX_INGRESS_NS_HI(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + goto error;
> > + if (!(rc & MCHP_PTP_RX_INGRESS_NS_HI_TS_VALID)) {
> > + phydev_err(phydev, "RX Timestamp is not valid!\n");
> > + goto error;
> > + }
> > + nsec = (rc & GENMASK(13, 0)) << 16;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_RX_INGRESS_NS_LO(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + goto error;
> > + nsec |= rc;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_RX_INGRESS_SEC_HI(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + goto error;
> > + sec = rc << 16;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_RX_INGRESS_SEC_LO(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + goto error;
> > + sec |= rc;
> > +
> > + seq = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_RX_MSG_HEADER2(BASE_PORT(ptp_clock)));
> > + if (seq < 0)
> > + goto error;
> > +
> > + rx_ts = kzalloc(sizeof(*rx_ts), GFP_KERNEL);
>
> why zero out allocation? all fields of this structure are rewritten
> unconditionally later (list_add happens in mchp_ptp_match_rx_ts) ...
>
I will recheck and update this.
> > + if (!rx_ts)
> > + return NULL;
> > +
> > + rx_ts->seconds = sec;
> > + rx_ts->nsec = nsec;
> > + rx_ts->seq_id = seq;
> > +
> > +error:
> > + return rx_ts;
> > +}
> > +
> > +static void mchp_ptp_process_rx_ts(struct mchp_ptp_clock *ptp_clock)
> > +{
> > + struct phy_device *phydev = ptp_clock->phydev;
> > + int caps;
> > +
> > + do {
> > + struct mchp_ptp_rx_ts *rx_ts;
> > +
> > + rx_ts = mchp_ptp_get_rx_ts(ptp_clock);
> > + if (rx_ts)
> > + mchp_ptp_match_rx_ts(ptp_clock, rx_ts);
> > +
> > + caps = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_CAP_INFO(BASE_PORT(ptp_clock)));
> > + if (caps < 0)
> > + return;
> > + } while (MCHP_PTP_RX_TS_CNT(caps) > 0); }
> > +
>
> [ ... ]
Thanks,
Divya
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH net-next 2/5] net: phy: microchip_ptp : Add ptp library for Microchip phys
2024-11-04 9:07 ` [PATCH net-next 2/5] net: phy: microchip_ptp : Add ptp library for Microchip phys Divya Koppera
2024-11-04 12:32 ` Vadim Fedorenko
@ 2024-11-07 14:34 ` Simon Horman
2024-11-11 4:55 ` Divya.Koppera
1 sibling, 1 reply; 15+ messages in thread
From: Simon Horman @ 2024-11-07 14:34 UTC (permalink / raw)
To: Divya Koppera
Cc: andrew, arun.ramadoss, UNGLinuxDriver, hkallweit1, linux, davem,
edumazet, kuba, pabeni, netdev, linux-kernel, richardcochran
On Mon, Nov 04, 2024 at 02:37:47PM +0530, Divya Koppera wrote:
> Add ptp library for Microchip phys
> 1-step and 2-step modes are supported, over Ethernet and UDP(ipv4, ipv6)
>
> Signed-off-by: Divya Koppera <divya.koppera@microchip.com>
> ---
> drivers/net/phy/microchip_ptp.c | 990 ++++++++++++++++++++++++++++++++
> 1 file changed, 990 insertions(+)
> create mode 100644 drivers/net/phy/microchip_ptp.c
>
> diff --git a/drivers/net/phy/microchip_ptp.c b/drivers/net/phy/microchip_ptp.c
...
> +static bool mchp_ptp_get_sig_tx(struct sk_buff *skb, u16 *sig)
> +{
> + struct ptp_header *ptp_header;
> + int type;
> +
> + type = ptp_classify_raw(skb);
> + if (type == PTP_CLASS_NONE)
> + return false;
> +
> + ptp_header = ptp_parse_header(skb, type);
> + if (!ptp_header)
> + return false;
> +
> + *sig = htons(ptp_header->sequence_id);
Hi Divya,
The type of *sig is u16, a host-byte order integer.
But htons() returns __be16, a big-endian integer.
This does not seem right.
Likewise, in the caller, and beyond, if these are big-endian integers
then appropriate types - probably __be16 - should be used.
Flagged by Sparse.
> +
> + return true;
> +}
...
> +static struct mchp_ptp_rx_ts *mchp_ptp_get_rx_ts(struct mchp_ptp_clock *ptp_clock)
> +{
> + struct phy_device *phydev = ptp_clock->phydev;
> + struct mchp_ptp_rx_ts *rx_ts = NULL;
> + u32 sec, nsec;
> + u16 seq;
> + int rc;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_RX_INGRESS_NS_HI(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + goto error;
> + if (!(rc & MCHP_PTP_RX_INGRESS_NS_HI_TS_VALID)) {
> + phydev_err(phydev, "RX Timestamp is not valid!\n");
> + goto error;
> + }
> + nsec = (rc & GENMASK(13, 0)) << 16;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_RX_INGRESS_NS_LO(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + goto error;
> + nsec |= rc;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_RX_INGRESS_SEC_HI(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + goto error;
> + sec = rc << 16;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_RX_INGRESS_SEC_LO(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + goto error;
> + sec |= rc;
> +
> + seq = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_RX_MSG_HEADER2(BASE_PORT(ptp_clock)));
> + if (seq < 0)
seq is unsigned; it can never be less than 0.
Flagged by Smatch.
> + goto error;
> +
> + rx_ts = kzalloc(sizeof(*rx_ts), GFP_KERNEL);
> + if (!rx_ts)
> + return NULL;
> +
> + rx_ts->seconds = sec;
> + rx_ts->nsec = nsec;
> + rx_ts->seq_id = seq;
> +
> +error:
> + return rx_ts;
> +}
...
> +static bool mchp_ptp_get_tx_ts(struct mchp_ptp_clock *ptp_clock,
> + u32 *sec, u32 *nsec, u16 *seq)
> +{
> + struct phy_device *phydev = ptp_clock->phydev;
> + int rc;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_TX_EGRESS_NS_HI(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + return false;
> + if (!(rc & MCHP_PTP_TX_EGRESS_NS_HI_TS_VALID))
> + return false;
> + *nsec = (rc & GENMASK(13, 0)) << 16;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_TX_EGRESS_NS_LO(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + return false;
> + *nsec = *nsec | rc;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_TX_EGRESS_SEC_HI(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + return false;
> + *sec = rc << 16;
> +
> + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_TX_EGRESS_SEC_LO(BASE_PORT(ptp_clock)));
> + if (rc < 0)
> + return false;
> + *sec = *sec | rc;
> +
> + *seq = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> + MCHP_PTP_TX_MSG_HEADER2(BASE_PORT(ptp_clock)));
> + if (*seq < 0)
Likewise, *seq is unsigned; it can never be less than 0.
> + return false;
> +
> + return true;
> +}
...
^ permalink raw reply [flat|nested] 15+ messages in thread
* RE: [PATCH net-next 2/5] net: phy: microchip_ptp : Add ptp library for Microchip phys
2024-11-07 14:34 ` Simon Horman
@ 2024-11-11 4:55 ` Divya.Koppera
0 siblings, 0 replies; 15+ messages in thread
From: Divya.Koppera @ 2024-11-11 4:55 UTC (permalink / raw)
To: horms
Cc: andrew, Arun.Ramadoss, UNGLinuxDriver, hkallweit1, linux, davem,
edumazet, kuba, pabeni, netdev, linux-kernel, richardcochran
Hi Simon,
Thanks for your comments. I will take care all in next revision.
Thanks and Regards,
Divya
> -----Original Message-----
> From: Simon Horman <horms@kernel.org>
> Sent: Thursday, November 7, 2024 8:04 PM
> To: Divya Koppera - I30481 <Divya.Koppera@microchip.com>
> Cc: andrew@lunn.ch; Arun Ramadoss - I17769
> <Arun.Ramadoss@microchip.com>; UNGLinuxDriver
> <UNGLinuxDriver@microchip.com>; hkallweit1@gmail.com;
> linux@armlinux.org.uk; davem@davemloft.net; edumazet@google.com;
> kuba@kernel.org; pabeni@redhat.com; netdev@vger.kernel.org; linux-
> kernel@vger.kernel.org; richardcochran@gmail.com
> Subject: Re: [PATCH net-next 2/5] net: phy: microchip_ptp : Add ptp library for
> Microchip phys
>
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the
> content is safe
>
> On Mon, Nov 04, 2024 at 02:37:47PM +0530, Divya Koppera wrote:
> > Add ptp library for Microchip phys
> > 1-step and 2-step modes are supported, over Ethernet and UDP(ipv4,
> > ipv6)
> >
> > Signed-off-by: Divya Koppera <divya.koppera@microchip.com>
> > ---
> > drivers/net/phy/microchip_ptp.c | 990
> > ++++++++++++++++++++++++++++++++
> > 1 file changed, 990 insertions(+)
> > create mode 100644 drivers/net/phy/microchip_ptp.c
> >
> > diff --git a/drivers/net/phy/microchip_ptp.c
> > b/drivers/net/phy/microchip_ptp.c
>
> ...
>
> > +static bool mchp_ptp_get_sig_tx(struct sk_buff *skb, u16 *sig) {
> > + struct ptp_header *ptp_header;
> > + int type;
> > +
> > + type = ptp_classify_raw(skb);
> > + if (type == PTP_CLASS_NONE)
> > + return false;
> > +
> > + ptp_header = ptp_parse_header(skb, type);
> > + if (!ptp_header)
> > + return false;
> > +
> > + *sig = htons(ptp_header->sequence_id);
>
> Hi Divya,
>
> The type of *sig is u16, a host-byte order integer.
> But htons() returns __be16, a big-endian integer.
> This does not seem right.
>
> Likewise, in the caller, and beyond, if these are big-endian integers then
> appropriate types - probably __be16 - should be used.
>
> Flagged by Sparse.
>
> > +
> > + return true;
> > +}
>
> ...
>
> > +static struct mchp_ptp_rx_ts *mchp_ptp_get_rx_ts(struct
> > +mchp_ptp_clock *ptp_clock) {
> > + struct phy_device *phydev = ptp_clock->phydev;
> > + struct mchp_ptp_rx_ts *rx_ts = NULL;
> > + u32 sec, nsec;
> > + u16 seq;
> > + int rc;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_RX_INGRESS_NS_HI(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + goto error;
> > + if (!(rc & MCHP_PTP_RX_INGRESS_NS_HI_TS_VALID)) {
> > + phydev_err(phydev, "RX Timestamp is not valid!\n");
> > + goto error;
> > + }
> > + nsec = (rc & GENMASK(13, 0)) << 16;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_RX_INGRESS_NS_LO(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + goto error;
> > + nsec |= rc;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_RX_INGRESS_SEC_HI(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + goto error;
> > + sec = rc << 16;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_RX_INGRESS_SEC_LO(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + goto error;
> > + sec |= rc;
> > +
> > + seq = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_RX_MSG_HEADER2(BASE_PORT(ptp_clock)));
> > + if (seq < 0)
>
> seq is unsigned; it can never be less than 0.
>
> Flagged by Smatch.
>
> > + goto error;
> > +
> > + rx_ts = kzalloc(sizeof(*rx_ts), GFP_KERNEL);
> > + if (!rx_ts)
> > + return NULL;
> > +
> > + rx_ts->seconds = sec;
> > + rx_ts->nsec = nsec;
> > + rx_ts->seq_id = seq;
> > +
> > +error:
> > + return rx_ts;
> > +}
>
> ...
>
> > +static bool mchp_ptp_get_tx_ts(struct mchp_ptp_clock *ptp_clock,
> > + u32 *sec, u32 *nsec, u16 *seq) {
> > + struct phy_device *phydev = ptp_clock->phydev;
> > + int rc;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_TX_EGRESS_NS_HI(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + return false;
> > + if (!(rc & MCHP_PTP_TX_EGRESS_NS_HI_TS_VALID))
> > + return false;
> > + *nsec = (rc & GENMASK(13, 0)) << 16;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_TX_EGRESS_NS_LO(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + return false;
> > + *nsec = *nsec | rc;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_TX_EGRESS_SEC_HI(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + return false;
> > + *sec = rc << 16;
> > +
> > + rc = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_TX_EGRESS_SEC_LO(BASE_PORT(ptp_clock)));
> > + if (rc < 0)
> > + return false;
> > + *sec = *sec | rc;
> > +
> > + *seq = phy_read_mmd(phydev, PTP_MMD(ptp_clock),
> > + MCHP_PTP_TX_MSG_HEADER2(BASE_PORT(ptp_clock)));
> > + if (*seq < 0)
>
> Likewise, *seq is unsigned; it can never be less than 0.
>
> > + return false;
> > +
> > + return true;
> > +}
>
> ...
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2024-11-11 4:55 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-04 9:07 [PATCH net-next 0/5] Add ptp library for Microchip phys Divya Koppera
2024-11-04 9:07 ` [PATCH net-next 1/5] net: phy: microchip_ptp : Add header file for Microchip ptp library Divya Koppera
2024-11-04 9:07 ` [PATCH net-next 2/5] net: phy: microchip_ptp : Add ptp library for Microchip phys Divya Koppera
2024-11-04 12:32 ` Vadim Fedorenko
2024-11-05 10:08 ` Divya.Koppera
2024-11-07 14:34 ` Simon Horman
2024-11-11 4:55 ` Divya.Koppera
2024-11-04 9:07 ` [PATCH net-next 3/5] net: phy: Kconfig: Add ptp library support and 1588 optional flag in " Divya Koppera
2024-11-04 9:07 ` [PATCH net-next 4/5] net: phy: Makefile: Add makefile support for ptp " Divya Koppera
2024-11-05 1:40 ` kernel test robot
2024-11-05 3:57 ` kernel test robot
2024-11-04 9:07 ` [PATCH net-next 5/5] net: phy: microchip_t1 : Add initialization of ptp for lan887x Divya Koppera
2024-11-04 14:04 ` Andrew Lunn
2024-11-05 6:17 ` Divya.Koppera
2024-11-05 3:14 ` kernel test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).