[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <2132816986.1597556.1750857530756.JavaMail.zimbra@couthit.local>
Date: Wed, 25 Jun 2025 18:48:50 +0530 (IST)
From: Parvathi Pudi <parvathi@...thit.com>
To: Vadim Fedorenko <vadim.fedorenko@...ux.dev>
Cc: parvathi <parvathi@...thit.com>, danishanwar <danishanwar@...com>,
rogerq <rogerq@...nel.org>, andrew+netdev <andrew+netdev@...n.ch>,
davem <davem@...emloft.net>, edumazet <edumazet@...gle.com>,
kuba <kuba@...nel.org>, pabeni <pabeni@...hat.com>,
robh <robh@...nel.org>, krzk+dt <krzk+dt@...nel.org>,
conor+dt <conor+dt@...nel.org>, ssantosh <ssantosh@...nel.org>,
richardcochran <richardcochran@...il.com>,
s hauer <s.hauer@...gutronix.de>, m-karicheri2 <m-karicheri2@...com>,
glaroque <glaroque@...libre.com>, afd <afd@...com>,
saikrishnag <saikrishnag@...vell.com>, m-malladi <m-malladi@...com>,
jacob e keller <jacob.e.keller@...el.com>,
diogo ivo <diogo.ivo@...mens.com>,
javier carrasco cruz <javier.carrasco.cruz@...il.com>,
horms <horms@...nel.org>, s-anna <s-anna@...com>,
basharath <basharath@...thit.com>,
linux-arm-kernel <linux-arm-kernel@...ts.infradead.org>,
netdev <netdev@...r.kernel.org>,
devicetree <devicetree@...r.kernel.org>,
linux-kernel <linux-kernel@...r.kernel.org>,
pratheesh <pratheesh@...com>, Prajith Jayarajan <prajith@...com>,
Vignesh Raghavendra <vigneshr@...com>, praneeth <praneeth@...com>,
srk <srk@...com>, rogerq <rogerq@...com>,
krishna <krishna@...thit.com>, pmohan <pmohan@...thit.com>,
mohan <mohan@...thit.com>
Subject: Re: [PATCH net-next v9 06/11] net: ti: prueth: Adds HW timestamping
support for PTP using PRU-ICSS IEP module
Hi,
> On 23/06/2025 16:26, Parvathi Pudi wrote:
>> From: Roger Quadros <rogerq@...com>
>>
>> PRU-ICSS IEP module, which is capable of timestamping RX and
>> TX packets at HW level, is used for time synchronization by PTP4L.
>>
>> This change includes interaction between firmware and user space
>> application (ptp4l) with required packet timestamps. The driver
>> initializes the PRU firmware with appropriate mode and configuration
>> flags. Firmware updates local registers with the flags set by driver
>> and uses for further operation. RX SOF timestamp comes along with
>> packet and firmware will rise interrupt with TX SOF timestamp after
>> pushing the packet on to the wire.
>>
>> IEP driver is available in upstream and we are reusing for hardware
>> configuration for ICSSM as well. On top of that we have extended it
>> with the changes for AM57xx SoC.
>>
>> Extended ethtool for reading HW timestamping capability of the PRU
>> interfaces.
>>
>> Currently ordinary clock (OC) configuration has been validated with
>> Linux ptp4l.
>>
>> Signed-off-by: Roger Quadros <rogerq@...com>
>> Signed-off-by: Andrew F. Davis <afd@...com>
>> Signed-off-by: Basharath Hussain Khaja <basharath@...thit.com>
>> Signed-off-by: Parvathi Pudi <parvathi@...thit.com>
>> ---
>> drivers/net/ethernet/ti/icssg/icss_iep.c | 42 ++
>> drivers/net/ethernet/ti/icssm/icssm_ethtool.c | 23 +
>> drivers/net/ethernet/ti/icssm/icssm_prueth.c | 439 +++++++++++++++++-
>> drivers/net/ethernet/ti/icssm/icssm_prueth.h | 11 +
>> .../net/ethernet/ti/icssm/icssm_prueth_ptp.h | 85 ++++
>> 5 files changed, 598 insertions(+), 2 deletions(-)
>> create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_ptp.h
>>
>> diff --git a/drivers/net/ethernet/ti/icssg/icss_iep.c
>> b/drivers/net/ethernet/ti/icssg/icss_iep.c
>> index 2a1c43316f46..031a6be6a4e3 100644
>> --- a/drivers/net/ethernet/ti/icssg/icss_iep.c
>> +++ b/drivers/net/ethernet/ti/icssg/icss_iep.c
>> @@ -968,11 +968,53 @@ static const struct icss_iep_plat_data
>> am654_icss_iep_plat_data = {
>> .config = &am654_icss_iep_regmap_config,
>> };
>>
>> +static const struct icss_iep_plat_data am57xx_icss_iep_plat_data = {
>> + .flags = ICSS_IEP_64BIT_COUNTER_SUPPORT |
>> + ICSS_IEP_SLOW_COMPEN_REG_SUPPORT,
>> + .reg_offs = {
>> + [ICSS_IEP_GLOBAL_CFG_REG] = 0x00,
>> + [ICSS_IEP_COMPEN_REG] = 0x08,
>> + [ICSS_IEP_SLOW_COMPEN_REG] = 0x0C,
>> + [ICSS_IEP_COUNT_REG0] = 0x10,
>> + [ICSS_IEP_COUNT_REG1] = 0x14,
>> + [ICSS_IEP_CAPTURE_CFG_REG] = 0x18,
>> + [ICSS_IEP_CAPTURE_STAT_REG] = 0x1c,
>> +
>> + [ICSS_IEP_CAP6_RISE_REG0] = 0x50,
>> + [ICSS_IEP_CAP6_RISE_REG1] = 0x54,
>> +
>> + [ICSS_IEP_CAP7_RISE_REG0] = 0x60,
>> + [ICSS_IEP_CAP7_RISE_REG1] = 0x64,
>> +
>> + [ICSS_IEP_CMP_CFG_REG] = 0x70,
>> + [ICSS_IEP_CMP_STAT_REG] = 0x74,
>> + [ICSS_IEP_CMP0_REG0] = 0x78,
>> + [ICSS_IEP_CMP0_REG1] = 0x7c,
>> + [ICSS_IEP_CMP1_REG0] = 0x80,
>> + [ICSS_IEP_CMP1_REG1] = 0x84,
>> +
>> + [ICSS_IEP_CMP8_REG0] = 0xc0,
>> + [ICSS_IEP_CMP8_REG1] = 0xc4,
>> + [ICSS_IEP_SYNC_CTRL_REG] = 0x180,
>> + [ICSS_IEP_SYNC0_STAT_REG] = 0x188,
>> + [ICSS_IEP_SYNC1_STAT_REG] = 0x18c,
>> + [ICSS_IEP_SYNC_PWIDTH_REG] = 0x190,
>> + [ICSS_IEP_SYNC0_PERIOD_REG] = 0x194,
>> + [ICSS_IEP_SYNC1_DELAY_REG] = 0x198,
>> + [ICSS_IEP_SYNC_START_REG] = 0x19c,
>> + },
>> + .config = &am654_icss_iep_regmap_config,
>> +};
>> +
>> static const struct of_device_id icss_iep_of_match[] = {
>> {
>> .compatible = "ti,am654-icss-iep",
>> .data = &am654_icss_iep_plat_data,
>> },
>> + {
>> + .compatible = "ti,am5728-icss-iep",
>> + .data = &am57xx_icss_iep_plat_data,
>> + },
>> {},
>> };
>> MODULE_DEVICE_TABLE(of, icss_iep_of_match);
>> diff --git a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c
>> b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c
>> index 6faa46ba6364..6aafca17b730 100644
>> --- a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c
>> +++ b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c
>> @@ -8,6 +8,7 @@
>> #include <linux/if_bridge.h>
>> #include <linux/if_vlan.h>
>> #include "icssm_prueth.h"
>> +#include "../icssg/icss_iep.h"
>>
>> /* set PRU firmware statistics */
>> void icssm_emac_set_stats(struct prueth_emac *emac,
>> @@ -221,6 +222,27 @@ icssm_emac_get_eth_mac_stats(struct net_device *ndev,
>> mac_stats->MultipleCollisionFrames = pstats.multi_coll;
>> }
>>
>> +static int icssm_emac_get_ts_info(struct net_device *ndev,
>> + struct kernel_ethtool_ts_info *info)
>> +{
>> + struct prueth_emac *emac = netdev_priv(ndev);
>> +
>> + if ((PRUETH_IS_EMAC(emac->prueth) && !emac->emac_ptp_tx_irq))
>> + return ethtool_op_get_ts_info(ndev, info);
>> +
>> + info->so_timestamping =
>> + SOF_TIMESTAMPING_TX_HARDWARE |
>> + SOF_TIMESTAMPING_RX_HARDWARE |
>> + SOF_TIMESTAMPING_RAW_HARDWARE;
>> +
>> + info->phc_index = icss_iep_get_ptp_clock_idx(emac->prueth->iep);
>> + info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
>> + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
>> + BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
>> +
>> + return 0;
>> +}
>> +
>> /* Ethtool support for EMAC adapter */
>> const struct ethtool_ops emac_ethtool_ops = {
>> .get_drvinfo = icssm_emac_get_drvinfo,
>> @@ -233,5 +255,6 @@ const struct ethtool_ops emac_ethtool_ops = {
>> .get_regs = icssm_emac_get_regs,
>> .get_rmon_stats = icssm_emac_get_rmon_stats,
>> .get_eth_mac_stats = icssm_emac_get_eth_mac_stats,
>> + .get_ts_info = icssm_emac_get_ts_info,
>> };
>> EXPORT_SYMBOL_GPL(emac_ethtool_ops);
>> diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c
>> b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
>> index 2b10538c616e..e45f67160d99 100644
>> --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c
>> +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
>> @@ -30,6 +30,7 @@
>>
>> #include "icssm_prueth.h"
>> #include "../icssg/icssg_mii_rt.h"
>> +#include "../icssg/icss_iep.h"
>>
>> #define OCMC_RAM_SIZE (SZ_64K)
>>
>> @@ -50,6 +51,45 @@ static void icssm_prueth_write_reg(struct prueth *prueth,
>> ETH_FCS_LEN + \
>> ICSSM_LRE_TAG_SIZE)
>>
>> +static void icssm_prueth_ptp_ts_enable(struct prueth_emac *emac)
>> +{
>> + void __iomem *sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va;
>> + u8 val = 0;
>> +
>> + if (emac->ptp_tx_enable) {
>> + /* Disable fw background task */
>> + val &= ~TIMESYNC_CTRL_BG_ENABLE;
>> + /* Enable forced 2-step */
>> + val |= TIMESYNC_CTRL_FORCED_2STEP;
>> + }
>> +
>> + writeb(val, sram + TIMESYNC_CTRL_VAR_OFFSET);
>> +}
>> +
>> +static void icssm_prueth_ptp_tx_ts_enable(struct prueth_emac *emac,
>> + bool enable)
>> +{
>> + emac->ptp_tx_enable = enable;
>> + icssm_prueth_ptp_ts_enable(emac);
>> +}
>> +
>> +static bool icssm_prueth_ptp_tx_ts_is_enabled(struct prueth_emac *emac)
>> +{
>> + return !!emac->ptp_tx_enable;
>> +}
>> +
>> +static void icssm_prueth_ptp_rx_ts_enable(struct prueth_emac *emac,
>> + bool enable)
>> +{
>> + emac->ptp_rx_enable = enable;
>> + icssm_prueth_ptp_ts_enable(emac);
>> +}
>> +
>> +static bool icssm_prueth_ptp_rx_ts_is_enabled(struct prueth_emac *emac)
>> +{
>> + return !!emac->ptp_rx_enable;
>> +}
>> +
>> /* ensure that order of PRUSS mem regions is same as enum prueth_mem */
>> static enum pruss_mem pruss_mem_ids[] = { PRUSS_MEM_DRAM0, PRUSS_MEM_DRAM1,
>> PRUSS_MEM_SHRD_RAM2 };
>> @@ -469,6 +509,173 @@ static void icssm_get_block(struct prueth_queue_desc
>> __iomem *queue_desc,
>> queue->buffer_desc_offset) / BD_SIZE;
>> }
>>
>> +static u8 icssm_prueth_ptp_ts_event_type(struct sk_buff *skb, u8 *ptp_msgtype)
>> +{
>> + unsigned int ptp_class = ptp_classify_raw(skb);
>> + struct ptp_header *hdr;
>> + u8 msgtype, event_type;
>> +
>> + if (ptp_class == PTP_CLASS_NONE)
>> + return PRUETH_PTP_TS_EVENTS;
>> +
>> + hdr = ptp_parse_header(skb, ptp_class);
>> + if (!hdr)
>> + return PRUETH_PTP_TS_EVENTS;
>> +
>> + msgtype = ptp_get_msgtype(hdr, ptp_class);
>> + /* Treat E2E Delay Req/Resp messages in the same way as P2P peer delay
>> + * req/resp in driver here since firmware stores timestamps in the same
>> + * memory location for either (since they cannot operate simultaneously
>> + * anyway)
>> + */
>> + switch (msgtype) {
>> + case PTP_MSGTYPE_SYNC:
>> + event_type = PRUETH_PTP_SYNC;
>> + break;
>> + case PTP_MSGTYPE_DELAY_REQ:
>> + case PTP_MSGTYPE_PDELAY_REQ:
>> + event_type = PRUETH_PTP_DLY_REQ;
>> + break;
>> + /* TODO: Check why PTP_MSGTYPE_DELAY_RESP needs timestamp
>> + * and need for it.
>> + */
>> + case 0x9:
>> + case PTP_MSGTYPE_PDELAY_RESP:
>> + event_type = PRUETH_PTP_DLY_RESP;
>> + break;
>> + default:
>> + event_type = PRUETH_PTP_TS_EVENTS;
>> + }
>> +
>> + if (ptp_msgtype)
>> + *ptp_msgtype = msgtype;
>> +
>> + return event_type;
>> +}
>> +
>> +static void icssm_prueth_ptp_tx_ts_reset(struct prueth_emac *emac, u8 event)
>> +{
>> + void __iomem *sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va;
>> + u32 ts_notify_offs, ts_offs;
>> +
>> + ts_offs = icssm_prueth_tx_ts_offs_get(emac->port_id - 1, event);
>> + ts_notify_offs = icssm_prueth_tx_ts_notify_offs_get(emac->port_id - 1,
>> + event);
>> +
>> + writeb(0, sram + ts_notify_offs);
>> + memset_io(sram + ts_offs, 0, sizeof(u64));
>> +}
>> +
>> +static int icssm_prueth_ptp_tx_ts_enqueue(struct prueth_emac *emac,
>> + struct sk_buff *skb)
>> +{
>> + u8 event, changed = 0;
>> + unsigned long flags;
>> +
>> + if (skb_vlan_tagged(skb)) {
>> + __skb_pull(skb, VLAN_HLEN);
>> + changed += VLAN_HLEN;
>> + }
>> +
>> + skb_reset_mac_header(skb);
>> + event = icssm_prueth_ptp_ts_event_type(skb, NULL);
>> + __skb_push(skb, changed);
>> + if (event == PRUETH_PTP_TS_EVENTS) {
>> + netdev_err(emac->ndev, "invalid PTP event\n");
>> + return -EINVAL;
>> + }
>> +
>> + spin_lock_irqsave(&emac->ptp_skb_lock, flags);
>> + if (emac->ptp_skb[event]) {
>> + dev_consume_skb_any(emac->ptp_skb[event]);
>> + icssm_prueth_ptp_tx_ts_reset(emac, event);
>> + netdev_warn(emac->ndev, "Dropped event waiting for tx ts.\n");
>> + }
>> +
>> + skb_get(skb);
>> + emac->ptp_skb[event] = skb;
>> + spin_unlock_irqrestore(&emac->ptp_skb_lock, flags);
>> +
>> + return 0;
>> +}
>> +
>> +irqreturn_t icssm_prueth_ptp_tx_irq_handle(int irq, void *dev)
>> +{
>> + struct net_device *ndev = (struct net_device *)dev;
>> + struct prueth_emac *emac = netdev_priv(ndev);
>> +
>> + if (unlikely(netif_queue_stopped(ndev)))
>> + netif_wake_queue(ndev);
>> +
>> + if (icssm_prueth_ptp_tx_ts_is_enabled(emac))
>> + return IRQ_WAKE_THREAD;
>> +
>> + return IRQ_HANDLED;
>> +}
>> +
>> +static u64 icssm_prueth_ptp_ts_get(struct prueth_emac *emac, u32 ts_offs)
>> +{
>> + void __iomem *sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va;
>> + u64 cycles;
>> +
>> + memcpy_fromio(&cycles, sram + ts_offs, sizeof(cycles));
>> + memset_io(sram + ts_offs, 0, sizeof(cycles));
>> +
>> + return cycles;
>> +}
>> +
>> +static void icssm_prueth_ptp_tx_ts_get(struct prueth_emac *emac, u8 event)
>> +{
>> + struct skb_shared_hwtstamps ssh;
>> + struct sk_buff *skb;
>> + unsigned long flags;
>> + u64 ns;
>> +
>> + /* get the msg from list */
>> + spin_lock_irqsave(&emac->ptp_skb_lock, flags);
>> + skb = emac->ptp_skb[event];
>> + emac->ptp_skb[event] = NULL;
>> + spin_unlock_irqrestore(&emac->ptp_skb_lock, flags);
>> + if (!skb) {
>> + netdev_err(emac->ndev, "no tx msg %u found waiting for ts\n",
>> + event);
>> + return;
>> + }
>> +
>> + /* get timestamp */
>> + ns = icssm_prueth_ptp_ts_get(emac,
>> + icssm_prueth_tx_ts_offs_get
>> + (emac->port_id - 1, event));
>> +
>> + memset(&ssh, 0, sizeof(ssh));
>> + ssh.hwtstamp = ns_to_ktime(ns);
>> + skb_tstamp_tx(skb, &ssh);
>> + dev_consume_skb_any(skb);
>> +}
>> +
>> +irqreturn_t icssm_prueth_ptp_tx_irq_work(int irq, void *dev)
>> +{
>> + struct prueth_emac *emac = netdev_priv(dev);
>> + u32 ts_notify_offs, ts_notify_mask, i;
>> + void __iomem *sram;
>> +
>> + /* get and reset the ts notifications */
>> + sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va;
>> + for (i = 0; i < PRUETH_PTP_TS_EVENTS; i++) {
>> + ts_notify_offs =
>> + icssm_prueth_tx_ts_notify_offs_get(emac->port_id - 1,
>> + i);
>> + memcpy_fromio(&ts_notify_mask, sram + ts_notify_offs,
>> + PRUETH_PTP_TS_NOTIFY_SIZE);
>> + memset_io(sram + ts_notify_offs, 0, PRUETH_PTP_TS_NOTIFY_SIZE);
>> +
>> + if (ts_notify_mask & PRUETH_PTP_TS_NOTIFY_MASK)
>> + icssm_prueth_ptp_tx_ts_get(emac, i);
>> + }
>> +
>> + return IRQ_HANDLED;
>> +}
>> +
>> /**
>> * icssm_emac_rx_irq - EMAC Rx interrupt handler
>> * @irq: interrupt number
>> @@ -597,6 +804,12 @@ static int icssm_prueth_tx_enqueue(struct prueth_emac
>> *emac,
>> memcpy(dst_addr, src_addr, pktlen);
>> }
>>
>> + if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
>> + icssm_prueth_ptp_tx_ts_is_enabled(emac)) {
>> + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
>> + icssm_prueth_ptp_tx_ts_enqueue(emac, skb);
>> + }
>> +
>> /* update first buffer descriptor */
>> wr_buf_desc = (pktlen << PRUETH_BD_LENGTH_SHIFT) &
>> PRUETH_BD_LENGTH_MASK;
>> @@ -647,6 +860,7 @@ int icssm_emac_rx_packet(struct prueth_emac *emac, u16
>> *bd_rd_ptr,
>> const struct prueth_queue_info *rxqueue)
>> {
>> struct net_device *ndev = emac->ndev;
>> + struct skb_shared_hwtstamps *ssh;
>> unsigned int buffer_desc_count;
>> int read_block, update_block;
>> unsigned int actual_pkt_len;
>> @@ -656,6 +870,7 @@ int icssm_emac_rx_packet(struct prueth_emac *emac, u16
>> *bd_rd_ptr,
>> struct sk_buff *skb;
>> int pkt_block_size;
>> void *ocmc_ram;
>> + u64 ts = 0;
>
> nit: the initialization is not needed, the value of ts is overwritten on
> the very first access
>
Sure, we will clean it up.
>>
>> /* the PRU firmware deals mostly in pointers already
>> * offset into ram, we would like to deal in indexes
>> @@ -665,6 +880,8 @@ int icssm_emac_rx_packet(struct prueth_emac *emac, u16
>> *bd_rd_ptr,
>> buffer_desc_count = icssm_get_buff_desc_count(rxqueue);
>> read_block = (*bd_rd_ptr - rxqueue->buffer_desc_offset) / BD_SIZE;
>> pkt_block_size = DIV_ROUND_UP(pkt_info->length, ICSS_BLOCK_SIZE);
>> + if (pkt_info->timestamp)
>> + pkt_block_size++;
>>
>> /* calculate end BD address post read */
>> update_block = read_block + pkt_block_size;
>> @@ -735,6 +952,15 @@ int icssm_emac_rx_packet(struct prueth_emac *emac, u16
>> *bd_rd_ptr,
>> if (!pkt_info->sv_frame) {
>> skb_put(skb, actual_pkt_len);
>>
>> + if (icssm_prueth_ptp_rx_ts_is_enabled(emac) &&
>> + pkt_info->timestamp) {
>> + src_addr = (void *)PTR_ALIGN((uintptr_t)src_addr,
>> + ICSS_BLOCK_SIZE);
>> + memcpy(&ts, src_addr, sizeof(ts));
>> + ssh = skb_hwtstamps(skb);
>> + memset(ssh, 0, sizeof(*ssh));
>> + ssh->hwtstamp = ns_to_ktime(ts);
>> + }
>> /* send packet up the stack */
>> skb->protocol = eth_type_trans(skb, ndev);
>> netif_receive_skb(skb);
>> @@ -895,9 +1121,67 @@ static int icssm_emac_request_irqs(struct prueth_emac
>> *emac)
>> return ret;
>> }
>>
>> + if (emac->emac_ptp_tx_irq) {
>> + ret = request_threaded_irq(emac->emac_ptp_tx_irq,
>> + icssm_prueth_ptp_tx_irq_handle,
>> + icssm_prueth_ptp_tx_irq_work,
>> + IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
>> + ndev->name, ndev);
>> + if (ret) {
>> + netdev_err(ndev, "unable to request PTP TX IRQ\n");
>> + goto free_irq;
>> + }
>> + }
>> +
>> + return 0;
>> +
>> +free_irq:
>> + free_irq(emac->rx_irq, ndev);
>> return ret;
>> }
>>
>> +static void icssm_iptp_dram_init(struct prueth_emac *emac)
>> +{
>> + void __iomem *sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va;
>> + u64 temp64;
>> +
>> + writew(0, sram + MII_RX_CORRECTION_OFFSET);
>> + writew(0, sram + MII_TX_CORRECTION_OFFSET);
>> +
>> + /* Initialize RCF to 1 (Linux N/A) */
>> + writel(1 * 1024, sram + TIMESYNC_TC_RCF_OFFSET);
>> +
>> + /* This flag will be set and cleared by firmware */
>> + /* Write Sync0 period for sync signal generation in PTP
>> + * memory in shared RAM
>> + */
>> + writel(200000000 / 50, sram + TIMESYNC_SYNC0_WIDTH_OFFSET);
>> +
>> + /* Write CMP1 period for sync signal generation in PTP
>> + * memory in shared RAM
>> + */
>> + temp64 = 1000000;
>> + memcpy_toio(sram + TIMESYNC_CMP1_CMP_OFFSET, &temp64, sizeof(temp64));
>> +
>> + /* Write Sync0 period for sync signal generation in PTP
>> + * memory in shared RAM
>> + */
>> + writel(1000000, sram + TIMESYNC_CMP1_PERIOD_OFFSET);
>> +
>> + /* Configures domainNumber list. Firmware supports 2 domains */
>> + writeb(0, sram + TIMESYNC_DOMAIN_NUMBER_LIST);
>> + writeb(0, sram + TIMESYNC_DOMAIN_NUMBER_LIST + 1);
>> +
>> + /* Configure 1-step/2-step */
>> + writeb(1, sram + DISABLE_SWITCH_SYNC_RELAY_OFFSET);
>> +
>> + /* Configures the setting to Link local frame without HSR tag */
>> + writeb(0, sram + LINK_LOCAL_FRAME_HAS_HSR_TAG);
>> +
>> + /* Enable E2E/UDP PTP message timestamping */
>> + writeb(1, sram + PTP_IPV4_UDP_E2E_ENABLE);
>> +}
>> +
>> /**
>> * icssm_emac_ndo_open - EMAC device open
>> * @ndev: network adapter device
>> @@ -922,9 +1206,18 @@ static int icssm_emac_ndo_open(struct net_device *ndev)
>>
>> icssm_emac_set_stats(emac, &emac->stats);
>>
>> + if (!prueth->emac_configured) {
>> + icssm_iptp_dram_init(emac);
>> + ret = icss_iep_init(prueth->iep, NULL, NULL, 0);
>> + if (ret) {
>> + netdev_err(ndev, "Failed to initialize iep: %d\n", ret);
>> + goto iep_exit;
>> + }
>> + }
>> +
>> ret = icssm_emac_set_boot_pru(emac, ndev);
>> if (ret)
>> - return ret;
>> + goto iep_exit;
>>
>> ret = icssm_emac_request_irqs(emac);
>> if (ret)
>> @@ -948,6 +1241,10 @@ static int icssm_emac_ndo_open(struct net_device *ndev)
>> rproc_shutdown:
>> rproc_shutdown(emac->pru);
>>
>> +iep_exit:
>> + if (!prueth->emac_configured)
>> + icss_iep_exit(prueth->iep);
>> +
>> return ret;
>> }
>>
>> @@ -963,6 +1260,7 @@ static int icssm_emac_ndo_stop(struct net_device *ndev)
>> {
>> struct prueth_emac *emac = netdev_priv(ndev);
>> struct prueth *prueth = emac->prueth;
>> + int i;
>>
>> prueth->emac_configured &= ~BIT(emac->port_id);
>>
>> @@ -973,14 +1271,32 @@ static int icssm_emac_ndo_stop(struct net_device *ndev)
>> phy_stop(emac->phydev);
>>
>> napi_disable(&emac->napi);
>> + /* inform the upper layers. */
>> + netif_stop_queue(ndev);
>>
>> /* stop the PRU */
>> rproc_shutdown(emac->pru);
>>
>> icssm_emac_get_stats(emac, &emac->stats);
>>
>> + /* Cleanup ptp related stuff for all protocols */
>> + icssm_prueth_ptp_tx_ts_enable(emac, 0);
>> + icssm_prueth_ptp_rx_ts_enable(emac, 0);
>> + for (i = 0; i < PRUETH_PTP_TS_EVENTS; i++) {
>> + if (emac->ptp_skb[i]) {
>> + icssm_prueth_ptp_tx_ts_reset(emac, i);
>> + dev_consume_skb_any(emac->ptp_skb[i]);
>> + emac->ptp_skb[i] = NULL;
>> + }
>> + }
>> +
>> /* free rx interrupts */
>> free_irq(emac->rx_irq, ndev);
>> + if (emac->emac_ptp_tx_irq)
>> + free_irq(emac->emac_ptp_tx_irq, ndev);
>> +
>> + if (!prueth->emac_configured)
>> + icss_iep_exit(prueth->iep);
>>
>> if (netif_msg_drv(emac))
>> dev_notice(&ndev->dev, "stopped\n");
>> @@ -1072,6 +1388,30 @@ static enum netdev_tx icssm_emac_ndo_start_xmit(struct
>> sk_buff *skb,
>> return ret;
>> }
>>
>> +/**
>> + * icssm_emac_ndo_tx_timeout - EMAC Transmit timeout function
>> + * @ndev: The EMAC network adapter
>> + * @txqueue: TX queue being used
>> + *
>> + * Called when system detects that a skb timeout period has expired
>> + * potentially due to a fault in the adapter in not being able to send
>> + * it out on the wire.
>> + */
>> +static void icssm_emac_ndo_tx_timeout(struct net_device *ndev,
>> + unsigned int txqueue)
>> +{
>> + struct prueth_emac *emac = netdev_priv(ndev);
>> +
>> + if (netif_msg_tx_err(emac))
>> + netdev_err(ndev, "xmit timeout");
>> +
>> + ndev->stats.tx_errors++;
>> +
>> + /* TODO: can we recover or need to reboot firmware? */
>> +
>> + netif_wake_queue(ndev);
>> +}
>> +
>> /**
>> * icssm_emac_ndo_get_stats64 - EMAC get statistics function
>> * @ndev: The EMAC network adapter
>> @@ -1100,11 +1440,86 @@ static void icssm_emac_ndo_get_stats64(struct net_device
>> *ndev,
>> stats->rx_length_errors = ndev->stats.rx_length_errors;
>> }
>>
>> +static int icssm_emac_hwtstamp_config_set(struct net_device *ndev,
>> + struct ifreq *ifr)
>> +{
>> + struct prueth_emac *emac = netdev_priv(ndev);
>> + struct hwtstamp_config cfg;
>> +
>> + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
>> + return -EFAULT;
>> +
>> + /* reserved for future extensions */
>> + if (cfg.flags)
>> + return -EINVAL;
>> +
>> + if (cfg.tx_type != HWTSTAMP_TX_OFF && cfg.tx_type != HWTSTAMP_TX_ON)
>> + return -ERANGE;
>> +
>> + switch (cfg.rx_filter) {
>> + case HWTSTAMP_FILTER_NONE:
>> + icssm_prueth_ptp_rx_ts_enable(emac, 0);
>> + break;
>> + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
>> + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
>> + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
>> + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
>> + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
>> + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
>> + case HWTSTAMP_FILTER_PTP_V2_EVENT:
>> + case HWTSTAMP_FILTER_PTP_V2_SYNC:
>> + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
>> + icssm_prueth_ptp_rx_ts_enable(emac, 1);
>> + cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
>> + break;
>> + case HWTSTAMP_FILTER_ALL:
>> + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
>> + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
>> + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
>> + default:
>> + return -ERANGE;
>> + }
>> +
>> + icssm_prueth_ptp_tx_ts_enable(emac, cfg.tx_type == HWTSTAMP_TX_ON);
>> +
>> + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
>> +}
>> +
>> +static int icssm_emac_hwtstamp_config_get(struct net_device *ndev,
>> + struct ifreq *ifr)
>> +{
>> + struct prueth_emac *emac = netdev_priv(ndev);
>> + struct hwtstamp_config cfg;
>> +
>> + cfg.flags = 0;
>> + cfg.tx_type = icssm_prueth_ptp_tx_ts_is_enabled(emac) ?
>> + HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
>> + cfg.rx_filter = icssm_prueth_ptp_rx_ts_is_enabled(emac) ?
>> + HWTSTAMP_FILTER_PTP_V2_EVENT : HWTSTAMP_FILTER_NONE;
>> +
>> + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
>> +}
>> +
>> +static int icssm_emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr,
>> + int cmd)
>> +{
>> + switch (cmd) {
>> + case SIOCSHWTSTAMP:
>> + return icssm_emac_hwtstamp_config_set(ndev, ifr);
>> + case SIOCGHWTSTAMP:
>> + return icssm_emac_hwtstamp_config_get(ndev, ifr);
>> + }
>
> Sorry for not mentioning this during previous review, but currently HW
> timestamping configuration has its own set of ndo callbacks:
> .ndo_hwtstamp_get and .ndo_hwtstamp_set. Even though the old ioctl style
> is still supported as a fallback, new drivers strongly discouraged to
> use it and should implement new callbacks. One of the benefits is to
> provide better error handling using extack messages, you can think of
> it while reworking current functions.
>
Sure, we will implement the .ndo_hwtstamp_get/.ndo_hwtstamp_set functions
and remove the ioctl's in the next version.
>> +
>> + return phy_do_ioctl(ndev, ifr, cmd);
>> +}
>> +
>> static const struct net_device_ops emac_netdev_ops = {
>> .ndo_open = icssm_emac_ndo_open,
>> .ndo_stop = icssm_emac_ndo_stop,
>> .ndo_start_xmit = icssm_emac_ndo_start_xmit,
>> + .ndo_tx_timeout = icssm_emac_ndo_tx_timeout,
>> .ndo_get_stats64 = icssm_emac_ndo_get_stats64,
>> + .ndo_eth_ioctl = icssm_emac_ndo_ioctl,
>> };
>>
>> /* get emac_port corresponding to eth_node name */
>> @@ -1205,6 +1620,14 @@ static int icssm_prueth_netdev_init(struct prueth
>> *prueth,
>> goto free;
>> }
>>
>> + emac->emac_ptp_tx_irq = of_irq_get_byname(eth_node, "emac_ptp_tx");
>> + if (emac->emac_ptp_tx_irq < 0) {
>> + emac->emac_ptp_tx_irq = 0;
>> + dev_err(prueth->dev, "could not get ptp tx irq. Skipping PTP support\n");
>> + }
>> +
>> + spin_lock_init(&emac->ptp_skb_lock);
>> +
>> /* get mac address from DT and set private and netdev addr */
>> ret = of_get_ethdev_address(eth_node, ndev);
>> if (!is_valid_ether_addr(ndev->dev_addr)) {
>
> [...]
>
> Please, put myself into CC list for the next revision, thanks.
Sure.
Thanks and Regards,
Parvathi.
Powered by blists - more mailing lists