lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <5bfba4fc-05b2-4a63-9ed4-9b1b3309d3d9@linux.dev>
Date: Tue, 24 Jun 2025 12:05:19 +0100
From: Vadim Fedorenko <vadim.fedorenko@...ux.dev>
To: Parvathi Pudi <parvathi@...thit.com>, danishanwar@...com,
 rogerq@...nel.org, andrew+netdev@...n.ch, davem@...emloft.net,
 edumazet@...gle.com, kuba@...nel.org, pabeni@...hat.com, robh@...nel.org,
 krzk+dt@...nel.org, conor+dt@...nel.org, ssantosh@...nel.org,
 richardcochran@...il.com, s.hauer@...gutronix.de, m-karicheri2@...com,
 glaroque@...libre.com, afd@...com, saikrishnag@...vell.com,
 m-malladi@...com, jacob.e.keller@...el.com, diogo.ivo@...mens.com,
 javier.carrasco.cruz@...il.com, horms@...nel.org, s-anna@...com,
 basharath@...thit.com
Cc: linux-arm-kernel@...ts.infradead.org, netdev@...r.kernel.org,
 devicetree@...r.kernel.org, linux-kernel@...r.kernel.org, pratheesh@...com,
 prajith@...com, vigneshr@...com, praneeth@...com, srk@...com, rogerq@...com,
 krishna@...thit.com, pmohan@...thit.com, 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

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

>   
>   	/* 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.

> +
> +	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.


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ