From patchwork Fri Oct 14 15:28:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arun Ramadoss X-Patchwork-Id: 13007115 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BCC14C4332F for ; Fri, 14 Oct 2022 15:29:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230398AbiJNP32 (ORCPT ); Fri, 14 Oct 2022 11:29:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55098 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229798AbiJNP3Z (ORCPT ); Fri, 14 Oct 2022 11:29:25 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C97D91D3EB5; Fri, 14 Oct 2022 08:29:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1665761363; x=1697297363; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=GFO5B/TBiuI1kXgFuapjcQD6QaRC4LsZQuzGyAZVNjY=; b=2DICIAOWezNlIZwnCJ84LYDEpY9a/8W/LJjSm3siN7S59N23wDrbGfkg f2knwcOJHPQbGKNwSZFZ0qgC9a0zsa2fkmTfWrkMxl6mziUKFfy5G44li RlnhkfCmQrlCoWGrEtuC4XX0z+J6K5MSqZRksFawvjqPMV0TQa2xiXNpL Z1OnrJngqsIrQo9Y3J9o03Fd+KukGgElyPilc7Pc7fO+dlMVilRQDi4KZ cn1dga+0Y4hUuA2zPC9Cr7CCzQfNdu1CPjeCW1fGUtnb5lyuDjGlLN/Ew JWz0l7Q/b4jn9kZOIlseXwoY1jgQH14cJkws1MFjcwZZwvRc6/4wHeNvj A==; X-IronPort-AV: E=Sophos;i="5.95,184,1661842800"; d="scan'208";a="178786930" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 14 Oct 2022 08:29:22 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Fri, 14 Oct 2022 08:29:21 -0700 Received: from CHE-LT-I17769U.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Fri, 14 Oct 2022 08:29:16 -0700 From: Arun Ramadoss To: , CC: , , , , , , , , , , , , Subject: [RFC Patch net-next 1/6] net: dsa: microchip: adding the posix clock support Date: Fri, 14 Oct 2022 20:58:52 +0530 Message-ID: <20221014152857.32645-2-arun.ramadoss@microchip.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20221014152857.32645-1-arun.ramadoss@microchip.com> References: <20221014152857.32645-1-arun.ramadoss@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This patch implement routines (adjfine, adjtime, gettime and settime) for manipulating the chip's PTP clock. It registers the ptp caps to posix clock register. Signed-off-by: Arun Ramadoss --- drivers/net/dsa/microchip/Kconfig | 10 + drivers/net/dsa/microchip/Makefile | 1 + drivers/net/dsa/microchip/ksz_common.c | 14 +- drivers/net/dsa/microchip/ksz_common.h | 17 ++ drivers/net/dsa/microchip/ksz_ptp.c | 269 ++++++++++++++++++++++++ drivers/net/dsa/microchip/ksz_ptp.h | 43 ++++ drivers/net/dsa/microchip/ksz_ptp_reg.h | 52 +++++ 7 files changed, 405 insertions(+), 1 deletion(-) create mode 100644 drivers/net/dsa/microchip/ksz_ptp.c create mode 100644 drivers/net/dsa/microchip/ksz_ptp.h create mode 100644 drivers/net/dsa/microchip/ksz_ptp_reg.h diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig index 06b1efdb5e7d..1e9712ff64e2 100644 --- a/drivers/net/dsa/microchip/Kconfig +++ b/drivers/net/dsa/microchip/Kconfig @@ -21,6 +21,16 @@ config NET_DSA_MICROCHIP_KSZ_SPI help Select to enable support for registering switches configured through SPI. +config NET_DSA_MICROCHIP_KSZ_PTP + bool "Support for the PTP clock on the KSZ9563/LAN937x Ethernet Switch" + depends on NET_DSA_MICROCHIP_KSZ_COMMON && PTP_1588_CLOCK + help + This enables support for timestamping & PTP clock manipulation + in the KSZ9563/LAN937x Ethernet switch + + Select to enable support for PTP feature for KSZ9563/lan937x series + of switch. + config NET_DSA_MICROCHIP_KSZ8863_SMI tristate "KSZ series SMI connected switch driver" depends on NET_DSA_MICROCHIP_KSZ_COMMON diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile index 28873559efc2..29d2d00ea27f 100644 --- a/drivers/net/dsa/microchip/Makefile +++ b/drivers/net/dsa/microchip/Makefile @@ -6,4 +6,5 @@ ksz_switch-objs += ksz8795.o ksz_switch-objs += lan937x_main.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C) += ksz9477_i2c.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_SPI) += ksz_spi.o +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_PTP) += ksz_ptp.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI) += ksz8863_smi.o diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index d612181b3226..084563e80660 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -27,6 +27,7 @@ #include "ksz8.h" #include "ksz9477.h" #include "lan937x.h" +#include "ksz_ptp.h" #define MIB_COUNTER_NUM 0x20 @@ -1990,10 +1991,16 @@ static int ksz_setup(struct dsa_switch *ds) } } + ret = ksz_ptp_clock_register(ds); + if (ret) { + dev_err(dev->dev, "Failed to register PTP clock: %d\n", ret); + goto out_pirq; + } + ret = ksz_mdio_register(dev); if (ret < 0) { dev_err(dev->dev, "failed to register the mdio"); - goto out_pirq; + goto out_ptp_clock_unregister; } /* start switch */ @@ -2002,6 +2009,8 @@ static int ksz_setup(struct dsa_switch *ds) return 0; +out_ptp_clock_unregister: + ksz_ptp_clock_unregister(ds); out_pirq: if (dev->irq > 0) dsa_switch_for_each_user_port(dp, dev->ds) @@ -2018,6 +2027,8 @@ static void ksz_teardown(struct dsa_switch *ds) struct ksz_device *dev = ds->priv; struct dsa_port *dp; + ksz_ptp_clock_unregister(ds); + if (dev->irq > 0) { dsa_switch_for_each_user_port(dp, dev->ds) ksz_irq_free(&dev->ports[dp->index].pirq); @@ -2831,6 +2842,7 @@ static const struct dsa_switch_ops ksz_switch_ops = { .get_pause_stats = ksz_get_pause_stats, .port_change_mtu = ksz_change_mtu, .port_max_mtu = ksz_max_mtu, + .get_ts_info = ksz_get_ts_info, }; struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 9cfa179575ce..f936a4100423 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -14,6 +14,9 @@ #include #include #include +#include + +#include "ksz_ptp.h" #define KSZ_MAX_NUM_PORTS 8 @@ -141,6 +144,7 @@ struct ksz_device { u16 port_mask; struct mutex lock_irq; /* IRQ Access */ struct ksz_irq girq; + struct ksz_ptp_data ptp_data; }; /* List of supported models */ @@ -442,6 +446,19 @@ static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value) return ret; } +static inline int ksz_rmw16(struct ksz_device *dev, u32 reg, u16 mask, + u16 value) +{ + int ret; + + ret = regmap_update_bits(dev->regmap[1], reg, mask, value); + if (ret) + dev_err(dev->dev, "can't rmw 16bit reg: 0x%x %pe\n", reg, + ERR_PTR(ret)); + + return ret; +} + static inline int ksz_write64(struct ksz_device *dev, u32 reg, u64 value) { u32 val[2]; diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c new file mode 100644 index 000000000000..0ead0e097ed5 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Microchip LAN937X PTP Implementation + * Copyright (C) 2021-2022 Microchip Technology Inc. + */ + +#include +#include +#include + +#include "ksz_common.h" +#include "ksz_ptp.h" +#include "ksz_ptp_reg.h" + +#define ptp_caps_to_data(d) \ + container_of((d), struct ksz_ptp_data, caps) +#define ptp_data_to_ksz_dev(d) \ + container_of((d), struct ksz_device, ptp_data) + +#define MAX_DRIFT_CORR 6250000 + +#define KSZ_PTP_INC_NS 40 /* HW clock is incremented every 40 ns (by 40) */ +#define KSZ_PTP_SUBNS_BITS 32 /* Number of bits in sub-nanoseconds counter */ + +/* The function is return back the capability of timestamping feature when + * requested through ethtool -T utility + */ +int ksz_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts) +{ + struct ksz_device *dev = ds->priv; + struct ksz_ptp_data *ptp_data = &dev->ptp_data; + + ts->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + ts->tx_types = (1 << HWTSTAMP_TX_OFF); + + ts->rx_filters = (1 << HWTSTAMP_FILTER_NONE); + + ts->phc_index = ptp_clock_index(ptp_data->clock); + + return 0; +} + +/* These are function related to the ptp clock info */ +static int _ksz_ptp_gettime(struct ksz_device *dev, struct timespec64 *ts) +{ + u32 nanoseconds; + u32 seconds; + u8 phase; + int ret; + + /* Copy current PTP clock into shadow registers */ + ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_READ_TIME, PTP_READ_TIME); + if (ret) + return ret; + + /* Read from shadow registers */ + ret = ksz_read8(dev, REG_PTP_RTC_SUB_NANOSEC__2, &phase); + if (ret) + return ret; + + ret = ksz_read32(dev, REG_PTP_RTC_NANOSEC, &nanoseconds); + if (ret) + return ret; + + ret = ksz_read32(dev, REG_PTP_RTC_SEC, &seconds); + if (ret) + return ret; + + ts->tv_sec = seconds; + ts->tv_nsec = nanoseconds + phase * 8; + + return 0; +} + +static int ksz_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) +{ + struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data); + int ret; + + mutex_lock(&ptp_data->lock); + ret = _ksz_ptp_gettime(dev, ts); + mutex_unlock(&ptp_data->lock); + + return ret; +} + +static int ksz_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data); + int ret; + + mutex_lock(&ptp_data->lock); + + /* Write to shadow registers */ + + /* Write 0 to clock phase */ + ret = ksz_write16(dev, REG_PTP_RTC_SUB_NANOSEC__2, PTP_RTC_0NS); + if (ret) + goto error_return; + + /* nanoseconds */ + ret = ksz_write32(dev, REG_PTP_RTC_NANOSEC, ts->tv_nsec); + if (ret) + goto error_return; + + /* seconds */ + ret = ksz_write32(dev, REG_PTP_RTC_SEC, ts->tv_sec); + if (ret) + goto error_return; + + /* Load PTP clock from shadow registers */ + ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_LOAD_TIME, PTP_LOAD_TIME); + +error_return: + mutex_unlock(&ptp_data->lock); + + return ret; +} + +static int ksz_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data); + int ret; + + mutex_lock(&ptp_data->lock); + + if (scaled_ppm) { + s64 ppb, adj; + u32 data32; + + /* see scaled_ppm_to_ppb() in ptp_clock.c for details */ + ppb = 1 + scaled_ppm; + ppb *= 125; + ppb *= KSZ_PTP_INC_NS; + ppb <<= KSZ_PTP_SUBNS_BITS - 13; + adj = div_s64(ppb, NSEC_PER_SEC); + + data32 = abs(adj); + data32 &= PTP_SUBNANOSEC_M; + if (adj >= 0) + data32 |= PTP_RATE_DIR; + + ret = ksz_write32(dev, REG_PTP_SUBNANOSEC_RATE, data32); + if (ret) + goto error_return; + + ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_CLK_ADJ_ENABLE, + PTP_CLK_ADJ_ENABLE); + if (ret) + goto error_return; + } else { + ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_CLK_ADJ_ENABLE, 0); + if (ret) + goto error_return; + } + +error_return: + mutex_unlock(&ptp_data->lock); + return ret; +} + +static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data); + s32 sec, nsec; + u16 data16; + int ret; + + mutex_lock(&ptp_data->lock); + + /* do not use ns_to_timespec64(), + * both sec and nsec are subtracted by hw + */ + sec = div_s64_rem(delta, NSEC_PER_SEC, &nsec); + + ret = ksz_write32(dev, REG_PTP_RTC_NANOSEC, abs(nsec)); + if (ret) + goto error_return; + + ret = ksz_write32(dev, REG_PTP_RTC_SEC, abs(sec)); + if (ret) + goto error_return; + + ret = ksz_read16(dev, REG_PTP_CLK_CTRL, &data16); + if (ret) + goto error_return; + + data16 |= PTP_STEP_ADJ; + + /*PTP_STEP_DIR -- 0: subtract, 1: add */ + if (delta < 0) + data16 &= ~PTP_STEP_DIR; + else + data16 |= PTP_STEP_DIR; + + ret = ksz_write16(dev, REG_PTP_CLK_CTRL, data16); + +error_return: + mutex_unlock(&ptp_data->lock); + return ret; +} + +static int ksz_ptp_start_clock(struct ksz_device *dev) +{ + return ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_CLK_ENABLE, PTP_CLK_ENABLE); +} + +static const struct ptp_clock_info ksz_ptp_caps = { + .owner = THIS_MODULE, + .name = "Microchip Clock", + .max_adj = MAX_DRIFT_CORR, + .gettime64 = ksz_ptp_gettime, + .settime64 = ksz_ptp_settime, + .adjfine = ksz_ptp_adjfine, + .adjtime = ksz_ptp_adjtime, +}; + +int ksz_ptp_clock_register(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + struct ksz_ptp_data *ptp_data = &dev->ptp_data; + int ret; + + mutex_init(&ptp_data->lock); + + ptp_data->caps = ksz_ptp_caps; + + /* Start hardware counter */ + ret = ksz_ptp_start_clock(dev); + if (ret) + return ret; + + /* Register the PTP Clock */ + ptp_data->clock = ptp_clock_register(&ptp_data->caps, dev->dev); + if (IS_ERR_OR_NULL(ptp_data->clock)) + return PTR_ERR(ptp_data->clock); + + ret = ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_802_1AS, PTP_802_1AS); + if (ret) + goto error_unregister_clock; + + return 0; + +error_unregister_clock: + ptp_clock_unregister(ptp_data->clock); + return ret; +} + +void ksz_ptp_clock_unregister(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + struct ksz_ptp_data *ptp_data = &dev->ptp_data; + + if (IS_ERR_OR_NULL(ptp_data->clock)) + return; + + ptp_clock_unregister(ptp_data->clock); +} + +MODULE_AUTHOR("Arun Ramadoss "); +MODULE_DESCRIPTION("PTP support for KSZ switch"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchip/ksz_ptp.h new file mode 100644 index 000000000000..ac53b0df2733 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz_ptp.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Microchip LAN937X PTP Implementation + * Copyright (C) 2020-2021 Microchip Technology Inc. + */ + +#ifndef _NET_DSA_DRIVERS_KSZ_PTP_H +#define _NET_DSA_DRIVERS_KSZ_PTP_H + +#if IS_ENABLED(CONFIG_NET_DSA_MICROCHIP_KSZ_PTP) + +struct ksz_ptp_data { + struct ptp_clock_info caps; + struct ptp_clock *clock; + /* Serializes all operations on the PTP hardware clock */ + struct mutex lock; +}; + +int ksz_ptp_clock_register(struct dsa_switch *ds); + +void ksz_ptp_clock_unregister(struct dsa_switch *ds); + +int ksz_get_ts_info(struct dsa_switch *ds, int port, + struct ethtool_ts_info *ts); + +#else + +struct ksz_ptp_data { + /* Serializes all operations on the PTP hardware clock */ + struct mutex lock; +}; + +static inline int ksz_ptp_clock_register(struct dsa_switch *ds) +{ + return 0; +} + +static inline void ksz_ptp_clock_unregister(struct dsa_switch *ds) { } + +#define ksz_get_ts_info NULL + +#endif /* End of CONFIG_NET_DSA_MICROCHIOP_KSZ_PTP */ + +#endif diff --git a/drivers/net/dsa/microchip/ksz_ptp_reg.h b/drivers/net/dsa/microchip/ksz_ptp_reg.h new file mode 100644 index 000000000000..2bf8395475b9 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz_ptp_reg.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Microchip KSZ PTP register definitions + * Copyright (C) 2019-2021 Microchip Technology Inc. + */ + +/* 5 - PTP Clock */ +#define REG_PTP_CLK_CTRL 0x0500 + +#define PTP_STEP_ADJ BIT(6) +#define PTP_STEP_DIR BIT(5) +#define PTP_READ_TIME BIT(4) +#define PTP_LOAD_TIME BIT(3) +#define PTP_CLK_ADJ_ENABLE BIT(2) +#define PTP_CLK_ENABLE BIT(1) +#define PTP_CLK_RESET BIT(0) + +#define REG_PTP_RTC_SUB_NANOSEC__2 0x0502 + +#define PTP_RTC_SUB_NANOSEC_M 0x0007 +#define PTP_RTC_0NS 0x00 + +#define REG_PTP_RTC_NANOSEC 0x0504 +#define REG_PTP_RTC_NANOSEC_H 0x0504 +#define REG_PTP_RTC_NANOSEC_L 0x0506 + +#define REG_PTP_RTC_SEC 0x0508 +#define REG_PTP_RTC_SEC_H 0x0508 +#define REG_PTP_RTC_SEC_L 0x050A + +#define REG_PTP_SUBNANOSEC_RATE 0x050C +#define REG_PTP_SUBNANOSEC_RATE_H 0x050C +#define PTP_SUBNANOSEC_M 0x3FFFFFFF + +#define PTP_RATE_DIR BIT(31) +#define PTP_TMP_RATE_ENABLE BIT(30) + +#define REG_PTP_SUBNANOSEC_RATE_L 0x050E + +#define REG_PTP_RATE_DURATION 0x0510 +#define REG_PTP_RATE_DURATION_H 0x0510 +#define REG_PTP_RATE_DURATION_L 0x0512 + +#define REG_PTP_MSG_CONF1 0x0514 + +#define PTP_802_1AS BIT(7) +#define PTP_ENABLE BIT(6) +#define PTP_ETH_ENABLE BIT(5) +#define PTP_IPV4_UDP_ENABLE BIT(4) +#define PTP_IPV6_UDP_ENABLE BIT(3) +#define PTP_TC_P2P BIT(2) +#define PTP_MASTER BIT(1) +#define PTP_1STEP BIT(0) From patchwork Fri Oct 14 15:28:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arun Ramadoss X-Patchwork-Id: 13007116 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DFE74C4332F for ; Fri, 14 Oct 2022 15:29:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230405AbiJNP3v (ORCPT ); Fri, 14 Oct 2022 11:29:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56410 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230442AbiJNP3p (ORCPT ); Fri, 14 Oct 2022 11:29:45 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2043C1D5869; Fri, 14 Oct 2022 08:29:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1665761371; x=1697297371; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=n94UfcLFyhyFfsXtdP6iBggIHqYSJYVNV6N2/pYkpEg=; b=W9RNDZQTNdcHTQMbWxNJpo9A5C6++sR77bmcK/F3rlct7tywgVGsnqwT CJ2h3c19X3zhEPkcPn4AWgK64DtQE9Y7IYZCbSHhnPI1srOs2sWH6nYnm OXytYFyRMhdzrIKklakaxUMf3Tuz5QmPLnnxSIApPaAZ82A3YBczWZHZo vhjr9E75Pn+Bksb22xVcruAF4W+EJt7SUrmMmDRe1eR8aZvnBlUZoDnlX dy3KVZfZ7se2VtK9Q9/r/VwmDzLpcmMF1rOvBnkuU5gJ00Yra3OksGgLB PH8J+wa+EQemQU8i7sgfJXS2qWY3atbHnHbqSoGkK6nSBM5+rYKcuhEcu A==; X-IronPort-AV: E=Sophos;i="5.95,184,1661842800"; d="scan'208";a="195427833" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 14 Oct 2022 08:29:29 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Fri, 14 Oct 2022 08:29:29 -0700 Received: from CHE-LT-I17769U.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Fri, 14 Oct 2022 08:29:24 -0700 From: Arun Ramadoss To: , CC: , , , , , , , , , , , , Subject: [RFC Patch net-next 2/6] net: dsa: microchip: Initial hardware time stamping support Date: Fri, 14 Oct 2022 20:58:53 +0530 Message-ID: <20221014152857.32645-3-arun.ramadoss@microchip.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20221014152857.32645-1-arun.ramadoss@microchip.com> References: <20221014152857.32645-1-arun.ramadoss@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This patch adds the routine for get_ts_info, hwstamp_get, set. This enables the PTP support towards userspace applications such as linuxptp. Tx timestamping can be enabled per port and Rx timestamping enabled globally. Signed-off-by: Arun Ramadoss --- drivers/net/dsa/microchip/ksz_common.c | 2 + drivers/net/dsa/microchip/ksz_common.h | 3 + drivers/net/dsa/microchip/ksz_ptp.c | 111 ++++++++++++++++++++++++- drivers/net/dsa/microchip/ksz_ptp.h | 14 ++++ include/linux/dsa/ksz_common.h | 23 +++++ net/dsa/tag_ksz.c | 59 +++++++++++++ 6 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 include/linux/dsa/ksz_common.h diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 084563e80660..d8ec5b641b89 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2843,6 +2843,8 @@ static const struct dsa_switch_ops ksz_switch_ops = { .port_change_mtu = ksz_change_mtu, .port_max_mtu = ksz_max_mtu, .get_ts_info = ksz_get_ts_info, + .port_hwtstamp_get = ksz_hwtstamp_get, + .port_hwtstamp_set = ksz_hwtstamp_set, }; struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index f936a4100423..0e5f02d3992e 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -104,6 +104,9 @@ struct ksz_port { struct ksz_device *ksz_dev; struct ksz_irq pirq; u8 num; +#if IS_ENABLED(CONFIG_NET_DSA_MICROCHIP_KSZ_PTP) + bool hwts_tx_en; +#endif }; struct ksz_device { diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index 0ead0e097ed5..5199840377aa 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -3,6 +3,7 @@ * Copyright (C) 2021-2022 Microchip Technology Inc. */ +#include #include #include #include @@ -21,6 +22,17 @@ #define KSZ_PTP_INC_NS 40 /* HW clock is incremented every 40 ns (by 40) */ #define KSZ_PTP_SUBNS_BITS 32 /* Number of bits in sub-nanoseconds counter */ +static int ksz_ptp_enable_mode(struct ksz_device *dev, bool enable) +{ + u16 data = 0; + + /* Enable PTP mode */ + if (enable) + data = PTP_ENABLE; + + return ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_ENABLE, data); +} + /* The function is return back the capability of timestamping feature when * requested through ethtool -T utility */ @@ -33,15 +45,110 @@ int ksz_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts) SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE; - ts->tx_types = (1 << HWTSTAMP_TX_OFF); + ts->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); - ts->rx_filters = (1 << HWTSTAMP_FILTER_NONE); + ts->rx_filters = + (1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_ALL); ts->phc_index = ptp_clock_index(ptp_data->clock); return 0; } +int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr) +{ + struct ksz_tagger_data *tagger_data = ksz_tagger_data(ds); + struct ksz_device *dev = ds->priv; + struct hwtstamp_config config; + + config.flags = 0; + + if (dev->ports[port].hwts_tx_en) + config.tx_type = HWTSTAMP_TX_ON; + else + config.tx_type = HWTSTAMP_TX_OFF; + + if (tagger_data->hwtstamp_get_state(ds)) + config.rx_filter = HWTSTAMP_FILTER_ALL; + else + config.rx_filter = HWTSTAMP_FILTER_NONE; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + +static int ksz_set_hwtstamp_config(struct ksz_device *dev, int port, + struct hwtstamp_config *config) +{ + struct ksz_tagger_data *tagger_data = ksz_tagger_data(dev->ds); + struct ksz_port *prt = &dev->ports[port]; + bool rx_on; + + /* reserved for future extensions */ + if (config->flags) + return -EINVAL; + + switch (config->tx_type) { + case HWTSTAMP_TX_OFF: + prt->hwts_tx_en = false; + break; + case HWTSTAMP_TX_ON: + prt->hwts_tx_en = true; + break; + default: + return -ERANGE; + } + + switch (config->rx_filter) { + case HWTSTAMP_FILTER_NONE: + rx_on = false; + break; + default: + rx_on = true; + break; + } + + if (rx_on != tagger_data->hwtstamp_get_state(dev->ds)) { + int ret; + + tagger_data->hwtstamp_set_state(dev->ds, false); + + ret = ksz_ptp_enable_mode(dev, rx_on); + if (ret) + return ret; + + if (rx_on) + tagger_data->hwtstamp_set_state(dev->ds, true); + } + + return 0; +} + +int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr) +{ + struct ksz_device *dev = ds->priv; + struct ksz_ptp_data *ptp_data = &dev->ptp_data; + struct hwtstamp_config config; + int ret; + + mutex_lock(&ptp_data->lock); + + ret = copy_from_user(&config, ifr->ifr_data, sizeof(config)); + if (ret) + goto error_return; + + ret = ksz_set_hwtstamp_config(dev, port, &config); + if (ret) + goto error_return; + + /* Save the chosen configuration to be returned later. */ + ret = copy_to_user(ifr->ifr_data, &config, sizeof(config)); + +error_return: + mutex_unlock(&ptp_data->lock); + return ret; +} + /* These are function related to the ptp clock info */ static int _ksz_ptp_gettime(struct ksz_device *dev, struct timespec64 *ts) { diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchip/ksz_ptp.h index ac53b0df2733..4c024cc9d935 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.h +++ b/drivers/net/dsa/microchip/ksz_ptp.h @@ -21,6 +21,8 @@ void ksz_ptp_clock_unregister(struct dsa_switch *ds); int ksz_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts); +int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr); +int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr); #else @@ -38,6 +40,18 @@ static inline void ksz_ptp_clock_unregister(struct dsa_switch *ds) { } #define ksz_get_ts_info NULL +static inline int ksz_hwtstamp_get(struct dsa_switch *ds, int port, + struct ifreq *ifr) +{ + return -EOPNOTSUPP; +} + +static inline int ksz_hwtstamp_set(struct dsa_switch *ds, int port, + struct ifreq *ifr) +{ + return -EOPNOTSUPP; +} + #endif /* End of CONFIG_NET_DSA_MICROCHIOP_KSZ_PTP */ #endif diff --git a/include/linux/dsa/ksz_common.h b/include/linux/dsa/ksz_common.h new file mode 100644 index 000000000000..8903bce4753b --- /dev/null +++ b/include/linux/dsa/ksz_common.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Microchip switch tag common header + * + * Copyright (C) 2021-2022 Microchip Technology Inc. + */ + +#ifndef _NET_DSA_KSZ_COMMON_H_ +#define _NET_DSA_KSZ_COMMON_H_ + +#include + +struct ksz_tagger_data { + bool (*hwtstamp_get_state)(struct dsa_switch *ds); + void (*hwtstamp_set_state)(struct dsa_switch *ds, bool on); +}; + +static inline struct ksz_tagger_data * +ksz_tagger_data(struct dsa_switch *ds) +{ + return ds->tagger_data; +} + +#endif /* _NET_DSA_KSZ_COMMON_H_ */ diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 38fa19c1e2d5..ca1261b04fe7 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -4,6 +4,7 @@ * Copyright (c) 2017 Microchip Technology */ +#include #include #include #include @@ -13,6 +14,62 @@ #define KSZ_EGRESS_TAG_LEN 1 #define KSZ_INGRESS_TAG_LEN 1 +#define KSZ_HWTS_EN 0 + +struct ksz_tagger_private { + struct ksz_tagger_data data; /* Must be first */ + unsigned long state; +}; + +static struct ksz_tagger_private * +ksz_tagger_private(struct dsa_switch *ds) +{ + return ds->tagger_data; +} + +static bool ksz_hwtstamp_get_state(struct dsa_switch *ds) +{ + struct ksz_tagger_private *priv = ksz_tagger_private(ds); + + return test_bit(KSZ_HWTS_EN, &priv->state); +} + +static void ksz_hwtstamp_set_state(struct dsa_switch *ds, bool on) +{ + struct ksz_tagger_private *priv = ksz_tagger_private(ds); + + if (on) + set_bit(KSZ_HWTS_EN, &priv->state); + else + clear_bit(KSZ_HWTS_EN, &priv->state); +} + +static void ksz_disconnect(struct dsa_switch *ds) +{ + struct ksz_tagger_private *priv = ds->tagger_data; + + kfree(priv); + ds->tagger_data = NULL; +} + +static int ksz_connect(struct dsa_switch *ds) +{ + struct ksz_tagger_data *tagger_data; + struct ksz_tagger_private *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Export functions for switch driver use */ + tagger_data = &priv->data; + tagger_data->hwtstamp_get_state = ksz_hwtstamp_get_state; + tagger_data->hwtstamp_set_state = ksz_hwtstamp_set_state; + ds->tagger_data = priv; + + return 0; +} + static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, struct net_device *dev, unsigned int port, unsigned int len) @@ -245,6 +302,8 @@ static const struct dsa_device_ops lan937x_netdev_ops = { .proto = DSA_TAG_PROTO_LAN937X, .xmit = lan937x_xmit, .rcv = ksz9477_rcv, + .connect = ksz_connect, + .disconnect = ksz_disconnect, .needed_tailroom = LAN937X_EGRESS_TAG_LEN, }; From patchwork Fri Oct 14 15:28:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arun Ramadoss X-Patchwork-Id: 13007118 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2F996C43217 for ; Fri, 14 Oct 2022 15:30:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230461AbiJNPaS (ORCPT ); Fri, 14 Oct 2022 11:30:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57062 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230456AbiJNP3x (ORCPT ); Fri, 14 Oct 2022 11:29:53 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 129E5F002; Fri, 14 Oct 2022 08:29:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1665761383; x=1697297383; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=LR20ISPZTVlIw7Mi+HJrgiQ6JDULKdv0p1mwU3lq/O4=; b=W1Czk0+6fmkB2PKOMKm5JfVm/E/X33XcW17aqyxU/zRDScqj+bmxL0T/ uMsxr6oBMI/vegh3BYl9UmloFaCY1EZR6WUqT3upSphzIHNTXKu7YxpmR 0UKso1e+XJPetNgjEJNM13GPhbQcTXXkyAKBPZCTYnfQNIMdE8JP7h7i6 OLH55UvTa6is01SUPOhfOQCZ/P5CpEd+TnJYaLf/AZjV+QsZV+20T5VPc Y6Fe9GZBDE2HuqseMqOSIfwwtM9xy7gbsrrTfr3wr7ciQ5PBF9RvJIZvR YI40ew3bARw0eI6BjPXcg6yBba6TwijtRTEP2OfWgvPnlHIclR50IHk7X Q==; X-IronPort-AV: E=Sophos;i="5.95,184,1661842800"; d="scan'208";a="195427909" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 14 Oct 2022 08:29:41 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Fri, 14 Oct 2022 08:29:36 -0700 Received: from CHE-LT-I17769U.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Fri, 14 Oct 2022 08:29:31 -0700 From: Arun Ramadoss To: , CC: , , , , , , , , , , , , Subject: [RFC Patch net-next 3/6] net: dsa: microchip: Manipulating absolute time using ptp hw clock Date: Fri, 14 Oct 2022 20:58:54 +0530 Message-ID: <20221014152857.32645-4-arun.ramadoss@microchip.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20221014152857.32645-1-arun.ramadoss@microchip.com> References: <20221014152857.32645-1-arun.ramadoss@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This patch is used for reconstructing the absolute time from the 32bit hardware time stamping value. The do_aux ioctl is used for reading the ptp hardware clock and store it to global variable. The timestamped value in tail tag during rx and register during tx are 32 bit value (2 bit seconds and 30 bit nanoseconds). The time taken to read entire ptp clock will be time consuming. In order to speed up, the software clock is maintained. This clock time will be added to 32 bit timestamp to get the absolute time stamp. Signed-off-by: Arun Ramadoss --- drivers/net/dsa/microchip/ksz_common.h | 1 + drivers/net/dsa/microchip/ksz_ptp.c | 55 +++++++++++++++++++++++++- drivers/net/dsa/microchip/ksz_ptp.h | 3 ++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 0e5f02d3992e..b15bcb6251e9 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -7,6 +7,7 @@ #ifndef __KSZ_COMMON_H #define __KSZ_COMMON_H +#include #include #include #include diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index 5199840377aa..c4cef3884a4d 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -24,12 +24,22 @@ static int ksz_ptp_enable_mode(struct ksz_device *dev, bool enable) { + struct ksz_ptp_data *ptp_data = &dev->ptp_data; u16 data = 0; + int ret; /* Enable PTP mode */ - if (enable) + if (enable) { data = PTP_ENABLE; + /* Schedule cyclic call of ksz_ptp_do_aux_work() */ + ret = ptp_schedule_worker(ptp_data->clock, 0); + if (ret) + return ret; + } else { + ptp_cancel_worker_sync(ptp_data->clock); + } + return ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_ENABLE, data); } @@ -223,6 +233,10 @@ static int ksz_ptp_settime(struct ptp_clock_info *ptp, /* Load PTP clock from shadow registers */ ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_LOAD_TIME, PTP_LOAD_TIME); + spin_lock_bh(&ptp_data->clock_lock); + ptp_data->clock_time = *ts; + spin_unlock_bh(&ptp_data->clock_lock); + error_return: mutex_unlock(&ptp_data->lock); @@ -276,6 +290,7 @@ static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp); struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data); + struct timespec64 delta64 = ns_to_timespec64(delta); s32 sec, nsec; u16 data16; int ret; @@ -309,14 +324,48 @@ static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) ret = ksz_write16(dev, REG_PTP_CLK_CTRL, data16); + spin_lock_bh(&ptp_data->clock_lock); + ptp_data->clock_time = timespec64_add(ptp_data->clock_time, delta64); + spin_unlock_bh(&ptp_data->clock_lock); + error_return: mutex_unlock(&ptp_data->lock); return ret; } +/* Function is pointer to the do_aux_work in the ptp_clock capability */ +static long ksz_ptp_do_aux_work(struct ptp_clock_info *ptp) +{ + struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data); + struct timespec64 ts; + + mutex_lock(&ptp_data->lock); + _ksz_ptp_gettime(dev, &ts); + mutex_unlock(&ptp_data->lock); + + spin_lock_bh(&ptp_data->clock_lock); + ptp_data->clock_time = ts; + spin_unlock_bh(&ptp_data->clock_lock); + + return HZ; /* reschedule in 1 second */ +} + static int ksz_ptp_start_clock(struct ksz_device *dev) { - return ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_CLK_ENABLE, PTP_CLK_ENABLE); + struct ksz_ptp_data *ptp_data = &dev->ptp_data; + int ret; + + ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_CLK_ENABLE, PTP_CLK_ENABLE); + if (ret) + return ret; + + spin_lock_bh(&ptp_data->clock_lock); + ptp_data->clock_time.tv_sec = 0; + ptp_data->clock_time.tv_nsec = 0; + spin_unlock_bh(&ptp_data->clock_lock); + + return 0; } static const struct ptp_clock_info ksz_ptp_caps = { @@ -327,6 +376,7 @@ static const struct ptp_clock_info ksz_ptp_caps = { .settime64 = ksz_ptp_settime, .adjfine = ksz_ptp_adjfine, .adjtime = ksz_ptp_adjtime, + .do_aux_work = ksz_ptp_do_aux_work, }; int ksz_ptp_clock_register(struct dsa_switch *ds) @@ -336,6 +386,7 @@ int ksz_ptp_clock_register(struct dsa_switch *ds) int ret; mutex_init(&ptp_data->lock); + spin_lock_init(&ptp_data->clock_lock); ptp_data->caps = ksz_ptp_caps; diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchip/ksz_ptp.h index 4c024cc9d935..09c0e58c365e 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.h +++ b/drivers/net/dsa/microchip/ksz_ptp.h @@ -13,6 +13,9 @@ struct ksz_ptp_data { struct ptp_clock *clock; /* Serializes all operations on the PTP hardware clock */ struct mutex lock; + /* lock for accessing the clock_time */ + spinlock_t clock_lock; + struct timespec64 clock_time; }; int ksz_ptp_clock_register(struct dsa_switch *ds); From patchwork Fri Oct 14 15:28:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arun Ramadoss X-Patchwork-Id: 13007117 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 78755C4332F for ; Fri, 14 Oct 2022 15:30:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231129AbiJNPaR (ORCPT ); Fri, 14 Oct 2022 11:30:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55114 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230458AbiJNP3z (ORCPT ); Fri, 14 Oct 2022 11:29:55 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AD54F2F3BF; Fri, 14 Oct 2022 08:29:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1665761386; x=1697297386; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=uSg5YnsO9BGIGbS+I/MnKCIlJmFCS7N6esnp7SrL+5Q=; b=G2aH1KhY1JW0jvzCuOSS+T1LGITDma1xC7lh+5g+CNMtGqa+HClfpClc SSmQ4031zU/yzm8yL4IHU/KmfxtqSzoPuBzu3zqQYVlzoJ57OkyhEwkO8 SCAW0K8Xnu5RgObhULqFnY5dmz6tidrDCCgRLub6IZRk/yLRf5ddWXBeC Xv+9jnrT1F6jcDP37AWTI62N9VqT3tX0h7F4yI2gLHniTcfuW6hABsezp 0Y3KVZB1tfle0pC5ql3eipDdjnW7cyAs3Dm/z7ryowFwc8W8q8KJPb2Fx LLJajO5RTeCpgjexuu+n5QgG0iy9nf0b+4UZPejnL5oevBFRrT6hGpmuz Q==; X-IronPort-AV: E=Sophos;i="5.95,184,1661842800"; d="scan'208";a="184851375" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa3.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 14 Oct 2022 08:29:43 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Fri, 14 Oct 2022 08:29:43 -0700 Received: from CHE-LT-I17769U.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Fri, 14 Oct 2022 08:29:38 -0700 From: Arun Ramadoss To: , CC: , , , , , , , , , , , , Subject: [RFC Patch net-next 4/6] net: dsa: microchip: enable the ptp interrupt for timestamping Date: Fri, 14 Oct 2022 20:58:55 +0530 Message-ID: <20221014152857.32645-5-arun.ramadoss@microchip.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20221014152857.32645-1-arun.ramadoss@microchip.com> References: <20221014152857.32645-1-arun.ramadoss@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC PTP Interrupt mask and status register differ from the global and port interrupt mechanism by two methods. One is that for global/port interrupt enabling we have to clear the bit but for ptp interrupt we have to set the bit. And other is bit12:0 is reserver in ptp interrupt registers. This forced to not use the generic implementation of global/port interrupt method routine. This patch implement the ptp interrupt mechanism to read the timestamp register for sync, pdelay_req and pdelay_resp. Signed-off-by: Arun Ramadoss --- drivers/net/dsa/microchip/ksz_common.c | 15 +- drivers/net/dsa/microchip/ksz_common.h | 10 ++ drivers/net/dsa/microchip/ksz_ptp.c | 201 ++++++++++++++++++++++++ drivers/net/dsa/microchip/ksz_ptp.h | 9 ++ drivers/net/dsa/microchip/ksz_ptp_reg.h | 16 ++ 5 files changed, 249 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index d8ec5b641b89..0c0fdb7b7879 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1988,13 +1988,17 @@ static int ksz_setup(struct dsa_switch *ds) ret = ksz_pirq_setup(dev, dp->index); if (ret) goto out_girq; + + ret = ksz_ptp_irq_setup(ds, dp->index); + if (ret) + goto out_pirq; } } ret = ksz_ptp_clock_register(ds); if (ret) { dev_err(dev->dev, "Failed to register PTP clock: %d\n", ret); - goto out_pirq; + goto out_ptpirq; } ret = ksz_mdio_register(dev); @@ -2011,6 +2015,10 @@ static int ksz_setup(struct dsa_switch *ds) out_ptp_clock_unregister: ksz_ptp_clock_unregister(ds); +out_ptpirq: + if (dev->irq > 0) + dsa_switch_for_each_user_port(dp, dev->ds) + ksz_ptp_irq_free(ds, dp->index); out_pirq: if (dev->irq > 0) dsa_switch_for_each_user_port(dp, dev->ds) @@ -2030,8 +2038,11 @@ static void ksz_teardown(struct dsa_switch *ds) ksz_ptp_clock_unregister(ds); if (dev->irq > 0) { - dsa_switch_for_each_user_port(dp, dev->ds) + dsa_switch_for_each_user_port(dp, dev->ds) { + ksz_ptp_irq_free(ds, dp->index); + ksz_irq_free(&dev->ports[dp->index].pirq); + } ksz_irq_free(&dev->girq); } diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index b15bcb6251e9..3a640ca4f7e1 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -85,6 +85,13 @@ struct ksz_irq { struct ksz_device *dev; }; +struct ksz_ptp_irq { + struct ksz_device *dev; + u16 ts_reg; + char name[16]; + int irq_num; +}; + struct ksz_port { bool remove_tag; /* Remove Tag flag set, for ksz8795 only */ bool learning; @@ -106,6 +113,8 @@ struct ksz_port { struct ksz_irq pirq; u8 num; #if IS_ENABLED(CONFIG_NET_DSA_MICROCHIP_KSZ_PTP) + struct ksz_irq ptpirq; + struct ksz_ptp_irq ptpmsg_irq[3]; bool hwts_tx_en; #endif }; @@ -605,6 +614,7 @@ static inline int is_lan937x(struct ksz_device *dev) #define REG_PORT_INT_MASK 0x001F #define PORT_SRC_PHY_INT 1 +#define PORT_SRC_PTP_INT 2 /* Regmap tables generation */ #define KSZ_SPI_OP_RD 3 diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index c4cef3884a4d..2cae543f7e0b 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -4,6 +4,8 @@ */ #include +#include +#include #include #include #include @@ -22,6 +24,8 @@ #define KSZ_PTP_INC_NS 40 /* HW clock is incremented every 40 ns (by 40) */ #define KSZ_PTP_SUBNS_BITS 32 /* Number of bits in sub-nanoseconds counter */ +#define KSZ_PTP_INT_START 13 + static int ksz_ptp_enable_mode(struct ksz_device *dev, bool enable) { struct ksz_ptp_data *ptp_data = &dev->ptp_data; @@ -422,6 +426,203 @@ void ksz_ptp_clock_unregister(struct dsa_switch *ds) ptp_clock_unregister(ptp_data->clock); } +static irqreturn_t ksz_ptp_msg_thread_fn(int irq, void *dev_id) +{ + return IRQ_NONE; +} + +static irqreturn_t ksz_ptp_irq_thread_fn(int irq, void *dev_id) +{ + struct ksz_irq *ptpirq = dev_id; + unsigned int nhandled = 0; + struct ksz_device *dev; + unsigned int sub_irq; + u16 data; + int ret; + u8 n; + + dev = ptpirq->dev; + + /* Read interrupt status register */ + ret = ksz_read16(dev, ptpirq->reg_status, &data); + if (ret) + goto out; + + for (n = 0; n < ptpirq->nirqs; ++n) { + if (data & BIT(n + KSZ_PTP_INT_START)) { + sub_irq = irq_find_mapping(ptpirq->domain, n); + handle_nested_irq(sub_irq); + ++nhandled; + } + } + + //Clear the interrupts W1C + ret = ksz_write16(dev, ptpirq->reg_status, data); + if (ret) + return IRQ_NONE; + +out: + return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); +} + +static void ksz_ptp_irq_mask(struct irq_data *d) +{ + struct ksz_irq *kirq = irq_data_get_irq_chip_data(d); + + kirq->masked &= ~BIT(d->hwirq + KSZ_PTP_INT_START); +} + +static void ksz_ptp_irq_unmask(struct irq_data *d) +{ + struct ksz_irq *kirq = irq_data_get_irq_chip_data(d); + + kirq->masked |= BIT(d->hwirq + KSZ_PTP_INT_START); +} + +static void ksz_ptp_irq_bus_lock(struct irq_data *d) +{ + struct ksz_irq *kirq = irq_data_get_irq_chip_data(d); + + mutex_lock(&kirq->dev->lock_irq); +} + +static void ksz_ptp_irq_bus_sync_unlock(struct irq_data *d) +{ + struct ksz_irq *kirq = irq_data_get_irq_chip_data(d); + struct ksz_device *dev = kirq->dev; + int ret; + + ret = ksz_write16(dev, kirq->reg_mask, kirq->masked); + if (ret) + dev_err(dev->dev, "failed to change IRQ mask\n"); + + mutex_unlock(&dev->lock_irq); +} + +static const struct irq_chip ksz_ptp_irq_chip = { + .name = "ksz-irq", + .irq_mask = ksz_ptp_irq_mask, + .irq_unmask = ksz_ptp_irq_unmask, + .irq_bus_lock = ksz_ptp_irq_bus_lock, + .irq_bus_sync_unlock = ksz_ptp_irq_bus_sync_unlock, +}; + +static int ksz_ptp_irq_domain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) +{ + irq_set_chip_data(irq, d->host_data); + irq_set_chip_and_handler(irq, &ksz_ptp_irq_chip, handle_level_irq); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops ksz_ptp_irq_domain_ops = { + .map = ksz_ptp_irq_domain_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int ksz_ptp_msg_irq_setup(struct ksz_port *port) +{ + u16 ts_reg[] = {REG_PTP_PORT_PDRESP_TS, REG_PTP_PORT_XDELAY_TS, + REG_PTP_PORT_SYNC_TS}; + struct ksz_device *dev = port->ksz_dev; + struct ksz_irq *ptpirq = &port->ptpirq; + struct ksz_ptp_irq *ptpmsg_irq; + int ret; + u8 n; + + for (n = 0; n < ptpirq->nirqs; n++) { + ptpmsg_irq = &port->ptpmsg_irq[n]; + + ptpmsg_irq->dev = port->ksz_dev; + ptpmsg_irq->ts_reg = dev->dev_ops->get_port_addr(port->num, + ts_reg[n]); + ptpmsg_irq->irq_num = irq_create_mapping(ptpirq->domain, n); + if (ptpmsg_irq->irq_num < 0) { + ret = ptpmsg_irq->irq_num; + goto out; + } + + snprintf(ptpmsg_irq->name, sizeof(ptpmsg_irq->name), + "PTP-MSG-%d", n); + + ret = request_threaded_irq(ptpmsg_irq->irq_num, NULL, + ksz_ptp_msg_thread_fn, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + ptpmsg_irq->name, ptpmsg_irq); + if (ret) + goto out; + } + + return 0; + +out: + while (n--) + irq_dispose_mapping(port->ptpmsg_irq[n].irq_num); + + return ret; +} + +int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p) +{ + struct ksz_device *dev = ds->priv; + const struct ksz_dev_ops *ops = dev->dev_ops; + struct ksz_port *port = &dev->ports[p]; + struct ksz_irq *ptpirq = &port->ptpirq; + int ret; + + ptpirq->dev = dev; + ptpirq->masked = 0; + ptpirq->nirqs = 3; + ptpirq->reg_mask = ops->get_port_addr(p, REG_PTP_PORT_TX_INT_ENABLE__2); + ptpirq->reg_status = ops->get_port_addr(p, + REG_PTP_PORT_TX_INT_STATUS__2); + snprintf(ptpirq->name, sizeof(ptpirq->name), "ptp_irq-%d", p); + + ptpirq->irq_num = irq_find_mapping(port->pirq.domain, PORT_SRC_PTP_INT); + if (ptpirq->irq_num < 0) + return ptpirq->irq_num; + + ptpirq->domain = irq_domain_add_simple(dev->dev->of_node, ptpirq->nirqs, + 0, &ksz_ptp_irq_domain_ops, + ptpirq); + if (!ptpirq->domain) + return -ENOMEM; + + ret = request_threaded_irq(ptpirq->irq_num, NULL, ksz_ptp_irq_thread_fn, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + ptpirq->name, ptpirq); + if (ret) + goto out; + + ret = ksz_ptp_msg_irq_setup(port); + if (ret) + goto out; + + return 0; + +out: + irq_dispose_mapping(ptpirq->irq_num); + + return ret; +} + +void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port *port = &dev->ports[p]; + struct ksz_irq *ptpirq = &port->ptpirq; + u8 n; + + free_irq(ptpirq->irq_num, ptpirq); + + for (n = 0; n < ptpirq->nirqs; n++) + irq_dispose_mapping(port->ptpmsg_irq[n].irq_num); + + irq_domain_remove(ptpirq->domain); +} + MODULE_AUTHOR("Arun Ramadoss "); MODULE_DESCRIPTION("PTP support for KSZ switch"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchip/ksz_ptp.h index 09c0e58c365e..7e5d374d2acf 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.h +++ b/drivers/net/dsa/microchip/ksz_ptp.h @@ -26,6 +26,8 @@ int ksz_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts); int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr); int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr); +int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p); +void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p); #else @@ -55,6 +57,13 @@ static inline int ksz_hwtstamp_set(struct dsa_switch *ds, int port, return -EOPNOTSUPP; } +static inline int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p) +{ + return 0; +} + +static inline void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p) {} + #endif /* End of CONFIG_NET_DSA_MICROCHIOP_KSZ_PTP */ #endif diff --git a/drivers/net/dsa/microchip/ksz_ptp_reg.h b/drivers/net/dsa/microchip/ksz_ptp_reg.h index 2bf8395475b9..2ae6c8b01b00 100644 --- a/drivers/net/dsa/microchip/ksz_ptp_reg.h +++ b/drivers/net/dsa/microchip/ksz_ptp_reg.h @@ -50,3 +50,19 @@ #define PTP_TC_P2P BIT(2) #define PTP_MASTER BIT(1) #define PTP_1STEP BIT(0) + +/* Port PTP Register */ +#define REG_PTP_PORT_RX_DELAY__2 0x0C00 +#define REG_PTP_PORT_TX_DELAY__2 0x0C02 +#define REG_PTP_PORT_ASYM_DELAY__2 0x0C04 + +#define REG_PTP_PORT_XDELAY_TS 0x0C08 +#define REG_PTP_PORT_SYNC_TS 0x0C0C +#define REG_PTP_PORT_PDRESP_TS 0x0C10 + +#define REG_PTP_PORT_TX_INT_STATUS__2 0x0C14 +#define REG_PTP_PORT_TX_INT_ENABLE__2 0x0C16 + +#define PTP_PORT_SYNC_INT BIT(15) +#define PTP_PORT_XDELAY_REQ_INT BIT(14) +#define PTP_PORT_PDELAY_RESP_INT BIT(13) From patchwork Fri Oct 14 15:28:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arun Ramadoss X-Patchwork-Id: 13007120 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 21F12C43219 for ; Fri, 14 Oct 2022 15:30:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230490AbiJNPa0 (ORCPT ); Fri, 14 Oct 2022 11:30:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56758 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230414AbiJNPaC (ORCPT ); Fri, 14 Oct 2022 11:30:02 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4C7B636BE2; Fri, 14 Oct 2022 08:29:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1665761393; x=1697297393; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=jK8z94O3baWwUdnBW8BYIUHIgd+YLU3a+lUHwKmvqNQ=; b=C5ZD1EJe7k40LbEqNZoNealGnf0vwj8Ohs02tEnQrhBzt5RW4Tci/hym HmLoGU4BbvYn77O3P+2OIsUWfTBuYI7S5wp1pfupP7N5GgJEknk6vC8bh S0PLuygO3bBOWTPCS1QSqZFd9Qx5CNxRLfMn+rMRODvXgv95bqgPrUoWQ nWxulfe1g9lR/eQE+9WO60TGpp1H3KdySGPWkLWrow27OpWnwwkKbRbuM ppLCUAsRCd5fb4GaCtLZctone5ShQxyvH3GATbuBnaEgogPd615bR9GGT 49LnXvD5pD0ukDL9sL5z9XifUU2MZY9Rwei69xiVz6FZ/EfZq8Y4BLqlR A==; X-IronPort-AV: E=Sophos;i="5.95,184,1661842800"; d="scan'208";a="184851379" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa3.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 14 Oct 2022 08:29:50 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Fri, 14 Oct 2022 08:29:50 -0700 Received: from CHE-LT-I17769U.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Fri, 14 Oct 2022 08:29:45 -0700 From: Arun Ramadoss To: , CC: , , , , , , , , , , , , Subject: [RFC Patch net-next 5/6] net: dsa: microchip: Adding the ptp packet reception logic Date: Fri, 14 Oct 2022 20:58:56 +0530 Message-ID: <20221014152857.32645-6-arun.ramadoss@microchip.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20221014152857.32645-1-arun.ramadoss@microchip.com> References: <20221014152857.32645-1-arun.ramadoss@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This patch adds the routines for timestamping received ptp packets. Whenever the ptp packet is received, the 4 byte hardware time stamped value is append to its packet. This 4 byte value is extracted from the tail tag and reconstructed to absolute time and assigned to skb hwtstamp. Signed-off-by: Arun Ramadoss --- drivers/net/dsa/microchip/ksz_common.c | 12 +++++++++++ drivers/net/dsa/microchip/ksz_ptp.c | 25 +++++++++++++++++++++ drivers/net/dsa/microchip/ksz_ptp.h | 6 ++++++ include/linux/dsa/ksz_common.h | 15 +++++++++++++ net/dsa/tag_ksz.c | 30 ++++++++++++++++++++++---- 5 files changed, 84 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 0c0fdb7b7879..388731959b23 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2426,6 +2426,17 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, return proto; } +static int ksz_connect_tag_protocol(struct dsa_switch *ds, + enum dsa_tag_protocol proto) +{ + struct ksz_tagger_data *tagger_data; + + tagger_data = ksz_tagger_data(ds); + tagger_data->meta_tstamp_handler = ksz_tstamp_reconstruct; + + return 0; +} + static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag, struct netlink_ext_ack *extack) { @@ -2819,6 +2830,7 @@ static int ksz_switch_detect(struct ksz_device *dev) static const struct dsa_switch_ops ksz_switch_ops = { .get_tag_protocol = ksz_get_tag_protocol, + .connect_tag_protocol = ksz_connect_tag_protocol, .get_phy_flags = ksz_get_phy_flags, .setup = ksz_setup, .teardown = ksz_teardown, diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index 2cae543f7e0b..5ae6eedb6b39 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -372,6 +372,31 @@ static int ksz_ptp_start_clock(struct ksz_device *dev) return 0; } +ktime_t ksz_tstamp_reconstruct(struct dsa_switch *ds, ktime_t tstamp) +{ + struct ksz_device *dev = ds->priv; + struct ksz_ptp_data *ptp_data = &dev->ptp_data; + struct timespec64 ts = ktime_to_timespec64(tstamp); + struct timespec64 ptp_clock_time; + struct timespec64 diff; + + spin_lock_bh(&ptp_data->clock_lock); + ptp_clock_time = ptp_data->clock_time; + spin_unlock_bh(&ptp_data->clock_lock); + + /* calculate full time from partial time stamp */ + ts.tv_sec = (ptp_clock_time.tv_sec & ~3) | ts.tv_sec; + + /* find nearest possible point in time */ + diff = timespec64_sub(ts, ptp_clock_time); + if (diff.tv_sec > 2) + ts.tv_sec -= 4; + else if (diff.tv_sec < -2) + ts.tv_sec += 4; + + return timespec64_to_ktime(ts); +} + static const struct ptp_clock_info ksz_ptp_caps = { .owner = THIS_MODULE, .name = "Microchip Clock", diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchip/ksz_ptp.h index 7e5d374d2acf..9589909ab7d5 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.h +++ b/drivers/net/dsa/microchip/ksz_ptp.h @@ -28,6 +28,7 @@ int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr); int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr); int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p); void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p); +ktime_t ksz_tstamp_reconstruct(struct dsa_switch *ds, ktime_t tstamp); #else @@ -64,6 +65,11 @@ static inline int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p) static inline void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p) {} +static inline ktime_t ksz_tstamp_reconstruct(struct dsa_switch *ds, ktime_t tstamp) +{ + return 0; +} + #endif /* End of CONFIG_NET_DSA_MICROCHIOP_KSZ_PTP */ #endif diff --git a/include/linux/dsa/ksz_common.h b/include/linux/dsa/ksz_common.h index 8903bce4753b..82edd7228b3c 100644 --- a/include/linux/dsa/ksz_common.h +++ b/include/linux/dsa/ksz_common.h @@ -9,9 +9,24 @@ #include +/* All time stamps from the KSZ consist of 2 bits for seconds and 30 bits for + * nanoseconds. This is NOT the same as 32 bits for nanoseconds. + */ +#define KSZ_TSTAMP_SEC_MASK GENMASK(31, 30) +#define KSZ_TSTAMP_NSEC_MASK GENMASK(29, 0) + +static inline ktime_t ksz_decode_tstamp(u32 tstamp) +{ + u64 ns = FIELD_GET(KSZ_TSTAMP_SEC_MASK, tstamp) * NSEC_PER_SEC + + FIELD_GET(KSZ_TSTAMP_NSEC_MASK, tstamp); + + return ns_to_ktime(ns); +} + struct ksz_tagger_data { bool (*hwtstamp_get_state)(struct dsa_switch *ds); void (*hwtstamp_set_state)(struct dsa_switch *ds, bool on); + ktime_t (*meta_tstamp_handler)(struct dsa_switch *ds, ktime_t tstamp); }; static inline struct ksz_tagger_data * diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index ca1261b04fe7..937a3e70b471 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -164,6 +164,25 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795); #define KSZ9477_TAIL_TAG_OVERRIDE BIT(9) #define KSZ9477_TAIL_TAG_LOOKUP BIT(10) +static void ksz_rcv_timestamp(struct sk_buff *skb, u8 *tag, + struct net_device *dev, unsigned int port) +{ + struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb); + u8 *tstamp_raw = tag - KSZ9477_PTP_TAG_LEN; + struct dsa_switch *ds = dev->dsa_ptr->ds; + struct ksz_tagger_data *tagger_data; + ktime_t tstamp; + + tagger_data = ksz_tagger_data(ds); + if (!tagger_data->meta_tstamp_handler) + return; + + /* convert time stamp and write to skb */ + tstamp = ksz_decode_tstamp(get_unaligned_be32(tstamp_raw)); + memset(hwtstamps, 0, sizeof(*hwtstamps)); + hwtstamps->hwtstamp = tagger_data->meta_tstamp_handler(ds, tstamp); +} + static struct sk_buff *ksz9477_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -197,8 +216,10 @@ static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev) unsigned int len = KSZ_EGRESS_TAG_LEN; /* Extra 4-bytes PTP timestamp */ - if (tag[0] & KSZ9477_PTP_TAG_INDICATION) + if (tag[0] & KSZ9477_PTP_TAG_INDICATION) { + ksz_rcv_timestamp(skb, tag, dev, port); len += KSZ9477_PTP_TAG_LEN; + } return ksz_common_rcv(skb, dev, port, len); } @@ -257,10 +278,11 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893); * tag0 : represents tag override, lookup and valid * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x80=port8) * - * For rcv, 1 byte is added before FCS. + * For rcv, 1/5 bytes is added before FCS. * --------------------------------------------------------------------------- - * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes) + * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|ts(4bytes)|tag0(1byte)|FCS(4bytes) * --------------------------------------------------------------------------- + * ts : time stamp (Present only if bit 7 of tag0 is set) * tag0 : zero-based value represents port * (eg, 0x00=port1, 0x02=port3, 0x07=port8) */ @@ -304,7 +326,7 @@ static const struct dsa_device_ops lan937x_netdev_ops = { .rcv = ksz9477_rcv, .connect = ksz_connect, .disconnect = ksz_disconnect, - .needed_tailroom = LAN937X_EGRESS_TAG_LEN, + .needed_tailroom = LAN937X_EGRESS_TAG_LEN + KSZ9477_PTP_TAG_LEN, }; DSA_TAG_DRIVER(lan937x_netdev_ops); From patchwork Fri Oct 14 15:28:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arun Ramadoss X-Patchwork-Id: 13007119 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 83A2BC433FE for ; Fri, 14 Oct 2022 15:30:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230497AbiJNPaX (ORCPT ); Fri, 14 Oct 2022 11:30:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58402 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230498AbiJNPaJ (ORCPT ); Fri, 14 Oct 2022 11:30:09 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CB0845072A; Fri, 14 Oct 2022 08:29:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1665761398; x=1697297398; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eHwa9IHXeES+Nm+coFOclTeWUmZ0mOGsc7ZsoZdPrAQ=; b=JCLx8SgLE6Kp1MrjJTN3rAJRSa8G+Ih+zSooSq2nQ4Toe7byGZ9uryS9 /h3Gb9wBOZwwJvp/UhXfOQ7gxlpNKP5qQ+3Nk5Ra5NZURZ4PFm/01yjlM Ps4C0Em7t968dC5dtQ5AdzhMxE1Us+RDZFEYivLzt516Uy2sy46Ok56Kt jaBD8zYLYnXi+pcATzsB2fsNbYkiQZ52l7R0AT5C1IihJKbD011QnHnQ/ QCeKrgm1ZiBMAHigcY1b/sSwzdkPstHxEYRreRqe5FFHpdynBKWa0Hb7h TBQiyUacoaKecQ9JkUaU7ZPPuU5mDJWuxsPrKQH9rIB+95LQhQaeyT31q A==; X-IronPort-AV: E=Sophos;i="5.95,184,1661842800"; d="scan'208";a="184851413" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa3.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 14 Oct 2022 08:29:57 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Fri, 14 Oct 2022 08:29:57 -0700 Received: from CHE-LT-I17769U.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Fri, 14 Oct 2022 08:29:52 -0700 From: Arun Ramadoss To: , CC: , , , , , , , , , , , , Subject: [RFC Patch net-next 6/6] net: dsa: microchip: add the transmission tstamp logic Date: Fri, 14 Oct 2022 20:58:57 +0530 Message-ID: <20221014152857.32645-7-arun.ramadoss@microchip.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20221014152857.32645-1-arun.ramadoss@microchip.com> References: <20221014152857.32645-1-arun.ramadoss@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This patch adds the routines for transmission of ptp packets. When the ptp packets(sync, pdelay_req, pdelay_rsp) to be transmitted, the skb is copied to global skb through port_txtstamp ioctl. After the packet is transmitted, ISR is triggered. The time at which packet transmitted is recorded to separate register available for each message. This value is reconstructed to absolute time and posted to the user application through skb complete. Signed-off-by: Rakesh Sankaranarayanan Signed-off-by: Arun Ramadoss --- drivers/net/dsa/microchip/ksz_common.c | 2 + drivers/net/dsa/microchip/ksz_ptp.c | 104 ++++++++++++++++++++++++- drivers/net/dsa/microchip/ksz_ptp.h | 9 +++ include/linux/dsa/ksz_common.h | 15 ++++ net/dsa/tag_ksz.c | 67 +++++++++++++++- 5 files changed, 193 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 388731959b23..47232a08ed94 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2432,6 +2432,7 @@ static int ksz_connect_tag_protocol(struct dsa_switch *ds, struct ksz_tagger_data *tagger_data; tagger_data = ksz_tagger_data(ds); + tagger_data->xmit_work_fn = ksz_port_deferred_xmit; tagger_data->meta_tstamp_handler = ksz_tstamp_reconstruct; return 0; @@ -2868,6 +2869,7 @@ static const struct dsa_switch_ops ksz_switch_ops = { .get_ts_info = ksz_get_ts_info, .port_hwtstamp_get = ksz_hwtstamp_get, .port_hwtstamp_set = ksz_hwtstamp_set, + .port_txtstamp = ksz_port_txtstamp, }; struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index 5ae6eedb6b39..d11a490a6c87 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -163,6 +163,46 @@ int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr) return ret; } +void ksz_port_txtstamp(struct dsa_switch *ds, int port, + struct sk_buff *skb) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port *prt = &dev->ports[port]; + struct ptp_header *hdr; + struct sk_buff *clone; + unsigned int type; + u8 ptp_msg_type; + + if (!prt->hwts_tx_en) + return; + + type = ptp_classify_raw(skb); + if (type == PTP_CLASS_NONE) + return; + + hdr = ptp_parse_header(skb, type); + if (!hdr) + return; + + ptp_msg_type = ptp_get_msgtype(hdr, type); + + switch (ptp_msg_type) { + case PTP_MSGTYPE_PDELAY_REQ: + case PTP_MSGTYPE_PDELAY_RESP: + case PTP_MSGTYPE_SYNC: + break; + + default: + return; + } + + clone = skb_clone_sk(skb); + if (!clone) + return; + + KSZ_SKB_CB(skb)->clone = clone; +} + /* These are function related to the ptp clock info */ static int _ksz_ptp_gettime(struct ksz_device *dev, struct timespec64 *ts) { @@ -397,6 +437,49 @@ ktime_t ksz_tstamp_reconstruct(struct dsa_switch *ds, ktime_t tstamp) return timespec64_to_ktime(ts); } +static void ksz_ptp_txtstamp_skb(struct ksz_device *dev, + struct ksz_port *prt, struct sk_buff *skb) +{ + struct ksz_ptp_data *ptp_data = &dev->ptp_data; + struct skb_shared_hwtstamps hwtstamps = {}; + int ret; + + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + + /* timeout must include tstamp latency, IRQ latency and time for + * reading the time stamp. + */ + ret = wait_for_completion_timeout(&ptp_data->tstamp_msg_comp, + msecs_to_jiffies(100)); + if (!ret) + return; + + hwtstamps.hwtstamp = ptp_data->tstamp_msg; + skb_complete_tx_timestamp(skb, &hwtstamps); +} + +#define work_to_xmit_work(w) \ + container_of((w), struct ksz_deferred_xmit_work, work) +void ksz_port_deferred_xmit(struct kthread_work *work) +{ + struct ksz_deferred_xmit_work *xmit_work = work_to_xmit_work(work); + struct sk_buff *clone, *skb = xmit_work->skb; + struct dsa_switch *ds = xmit_work->dp->ds; + struct ksz_device *dev = ds->priv; + struct ksz_ptp_data *ptp_data = &dev->ptp_data; + + clone = KSZ_SKB_CB(skb)->clone; + + reinit_completion(&ptp_data->tstamp_msg_comp); + + /* Transfer skb to the host port. */ + dsa_enqueue_skb(skb, skb->dev); + + ksz_ptp_txtstamp_skb(dev, dev->ports, clone); + + kfree(xmit_work); +} + static const struct ptp_clock_info ksz_ptp_caps = { .owner = THIS_MODULE, .name = "Microchip Clock", @@ -433,6 +516,8 @@ int ksz_ptp_clock_register(struct dsa_switch *ds) if (ret) goto error_unregister_clock; + init_completion(&ptp_data->tstamp_msg_comp); + return 0; error_unregister_clock: @@ -453,7 +538,24 @@ void ksz_ptp_clock_unregister(struct dsa_switch *ds) static irqreturn_t ksz_ptp_msg_thread_fn(int irq, void *dev_id) { - return IRQ_NONE; + struct ksz_ptp_irq *ptpmsg_irq = dev_id; + struct ksz_device *dev = ptpmsg_irq->dev; + struct ksz_ptp_data *ptp_data = &dev->ptp_data; + u32 tstamp_raw; + ktime_t tstamp; + int ret; + + ret = ksz_read32(dev, ptpmsg_irq->ts_reg, &tstamp_raw); + if (ret) + return IRQ_NONE; + + tstamp = ksz_decode_tstamp(tstamp_raw); + + ptp_data->tstamp_msg = ksz_tstamp_reconstruct(dev->ds, tstamp); + + complete(&ptp_data->tstamp_msg_comp); + + return IRQ_HANDLED; } static irqreturn_t ksz_ptp_irq_thread_fn(int irq, void *dev_id) diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchip/ksz_ptp.h index 9589909ab7d5..b2035a0bcbb2 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.h +++ b/drivers/net/dsa/microchip/ksz_ptp.h @@ -13,6 +13,8 @@ struct ksz_ptp_data { struct ptp_clock *clock; /* Serializes all operations on the PTP hardware clock */ struct mutex lock; + ktime_t tstamp_msg; + struct completion tstamp_msg_comp; /* lock for accessing the clock_time */ spinlock_t clock_lock; struct timespec64 clock_time; @@ -26,8 +28,10 @@ int ksz_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts); int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr); int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr); +void ksz_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb); int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p); void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p); +void ksz_port_deferred_xmit(struct kthread_work *work); ktime_t ksz_tstamp_reconstruct(struct dsa_switch *ds, ktime_t tstamp); #else @@ -58,6 +62,9 @@ static inline int ksz_hwtstamp_set(struct dsa_switch *ds, int port, return -EOPNOTSUPP; } +static inline void ksz_port_txtstamp(struct dsa_switch *ds, int port, + struct sk_buff *skb) {} + static inline int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p) { return 0; @@ -65,6 +72,8 @@ static inline int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p) static inline void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p) {} +static inline void ksz_port_deferred_xmit(struct kthread_work *work) {} + static inline ktime_t ksz_tstamp_reconstruct(struct dsa_switch *ds, ktime_t tstamp) { return 0; diff --git a/include/linux/dsa/ksz_common.h b/include/linux/dsa/ksz_common.h index 82edd7228b3c..15550fd88692 100644 --- a/include/linux/dsa/ksz_common.h +++ b/include/linux/dsa/ksz_common.h @@ -23,12 +23,27 @@ static inline ktime_t ksz_decode_tstamp(u32 tstamp) return ns_to_ktime(ns); } +struct ksz_deferred_xmit_work { + struct dsa_port *dp; + struct sk_buff *skb; + struct kthread_work work; +}; + struct ksz_tagger_data { + void (*xmit_work_fn)(struct kthread_work *work); bool (*hwtstamp_get_state)(struct dsa_switch *ds); void (*hwtstamp_set_state)(struct dsa_switch *ds, bool on); ktime_t (*meta_tstamp_handler)(struct dsa_switch *ds, ktime_t tstamp); }; +struct ksz_skb_cb { + struct sk_buff *clone; + unsigned int ptp_type; +}; + +#define KSZ_SKB_CB(skb) \ + ((struct ksz_skb_cb *)((skb)->cb)) + static inline struct ksz_tagger_data * ksz_tagger_data(struct dsa_switch *ds) { diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 937a3e70b471..582add3398d3 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -19,6 +19,7 @@ struct ksz_tagger_private { struct ksz_tagger_data data; /* Must be first */ unsigned long state; + struct kthread_worker *xmit_worker; }; static struct ksz_tagger_private * @@ -48,6 +49,7 @@ static void ksz_disconnect(struct dsa_switch *ds) { struct ksz_tagger_private *priv = ds->tagger_data; + kthread_destroy_worker(priv->xmit_worker); kfree(priv); ds->tagger_data = NULL; } @@ -55,12 +57,23 @@ static void ksz_disconnect(struct dsa_switch *ds) static int ksz_connect(struct dsa_switch *ds) { struct ksz_tagger_data *tagger_data; + struct kthread_worker *xmit_worker; struct ksz_tagger_private *priv; + int ret; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + xmit_worker = kthread_create_worker(0, "dsa%d:%d_xmit", + ds->dst->index, ds->index); + if (IS_ERR(xmit_worker)) { + ret = PTR_ERR(xmit_worker); + kfree(priv); + return ret; + } + + priv->xmit_worker = xmit_worker; /* Export functions for switch driver use */ tagger_data = &priv->data; tagger_data->hwtstamp_get_state = ksz_hwtstamp_get_state; @@ -271,10 +284,11 @@ static const struct dsa_device_ops ksz9893_netdev_ops = { DSA_TAG_DRIVER(ksz9893_netdev_ops); MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893); -/* For xmit, 2 bytes are added before FCS. +/* For xmit, 2/6 bytes are added before FCS. * --------------------------------------------------------------------------- - * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes) + * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|ts(4bytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes) * --------------------------------------------------------------------------- + * ts : time stamp (Present only if PTP is enabled in the Hardware) * tag0 : represents tag override, lookup and valid * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x80=port8) * @@ -293,14 +307,61 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893); #define LAN937X_TAIL_TAG_VALID BIT(13) #define LAN937X_TAIL_TAG_PORT_MASK 7 +static void lan937x_xmit_timestamp(struct sk_buff *skb) +{ + put_unaligned_be32(0, skb_put(skb, KSZ9477_PTP_TAG_LEN)); +} + +static struct sk_buff *lan937x_defer_xmit(struct dsa_port *dp, + struct sk_buff *skb) +{ + struct ksz_tagger_data *tagger_data = ksz_tagger_data(dp->ds); + struct ksz_tagger_private *priv = ksz_tagger_private(dp->ds); + void (*xmit_work_fn)(struct kthread_work *work); + struct sk_buff *clone = KSZ_SKB_CB(skb)->clone; + struct ksz_deferred_xmit_work *xmit_work; + struct kthread_worker *xmit_worker; + + if (!clone) + return skb; /* no deferred xmit for this packet */ + + xmit_work_fn = tagger_data->xmit_work_fn; + xmit_worker = priv->xmit_worker; + + if (!xmit_work_fn || !xmit_worker) + return NULL; + + xmit_work = kzalloc(sizeof(*xmit_work), GFP_ATOMIC); + if (!xmit_work) + return NULL; + + kthread_init_work(&xmit_work->work, xmit_work_fn); + /* Increase refcount so the kfree_skb in dsa_slave_xmit + * won't really free the packet. + */ + xmit_work->dp = dp; + xmit_work->skb = skb_get(skb); + + kthread_queue_work(xmit_worker, &xmit_work->work); + + return NULL; +} + static struct sk_buff *lan937x_xmit(struct sk_buff *skb, struct net_device *dev) { struct dsa_port *dp = dsa_slave_to_port(dev); const struct ethhdr *hdr = eth_hdr(skb); + struct ksz_tagger_private *priv; __be16 *tag; u16 val; + priv = ksz_tagger_private(dp->ds); + + /* Tag encoding */ + if (test_bit(KSZ_HWTS_EN, &priv->state)) + lan937x_xmit_timestamp(skb); + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) return NULL; @@ -316,7 +377,7 @@ static struct sk_buff *lan937x_xmit(struct sk_buff *skb, put_unaligned_be16(val, tag); - return skb; + return lan937x_defer_xmit(dp, skb); } static const struct dsa_device_ops lan937x_netdev_ops = {