* [PATCH net-next v2 6/9] net: ethernet: oa_tc6: Hardware timestamp support for OA TC6 framework
@ 2026-05-11 18:19 Selvamani Rajagopal
2026-05-11 19:49 ` Andrew Lunn
0 siblings, 1 reply; 2+ messages in thread
From: Selvamani Rajagopal @ 2026-05-11 18:19 UTC (permalink / raw)
To: Piergiorgio Beruto, parthiban.veerasooran@microchip.com,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Added hardware timestamp support as defined in Open Alliance
10BASET1x MACPHY_Serial_Interface specification. ioctl interface
added for ethtool to report and set the hardware timestamp feature
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
drivers/net/ethernet/oa_tc6.c | 321 ++++++++++++++++++++++++++++++++--
include/linux/oa_tc6.h | 5 +
2 files changed, 312 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
index beeac008f..48bd75f42 100644
--- a/drivers/net/ethernet/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6.c
@@ -24,9 +24,16 @@
#define OA_TC6_REG_CONFIG0 0x0004
#define CONFIG0_SYNC BIT(15)
#define CONFIG0_ZARFE_ENABLE BIT(12)
+#define CONFIG0_FTSE_ENABLE BIT(7)
+#define CONFIG0_FTSS_ENABLE BIT(6)
+#define CONFIG0_FTS_ENABLE_MASK GENMASK(7, 6)
/* Status Register #0 */
#define OA_TC6_REG_STATUS0 0x0008
+#define STATUS0_TTSCAC BIT(10)
+#define STATUS0_TTSCAB BIT(9)
+#define STATUS0_TTSCAA BIT(8)
+#define STATUS0_TTSCA_MASK GENMASK(10, 8)
#define STATUS0_RESETC BIT(6) /* Reset Complete */
#define STATUS0_HEADER_ERROR BIT(5)
#define STATUS0_LOSS_OF_FRAME_ERROR BIT(4)
@@ -40,6 +47,10 @@
/* Interrupt Mask Register #0 */
#define OA_TC6_REG_INT_MASK0 0x000C
+#define INT_MASK0_TTSCACM BIT(10)
+#define INT_MASK0_TTSCABM BIT(9)
+#define INT_MASK0_TTSCAAM BIT(8)
+#define INT_MASK0_TTSCA_MASK GENMASK(10, 8)
#define INT_MASK0_HEADER_ERR_MASK BIT(5)
#define INT_MASK0_LOSS_OF_FRAME_ERR_MASK BIT(4)
#define INT_MASK0_RX_BUFFER_OVERFLOW_ERR_MASK BIT(3)
@@ -64,6 +75,7 @@
#define OA_TC6_DATA_HEADER_START_WORD_OFFSET GENMASK(19, 16)
#define OA_TC6_DATA_HEADER_END_VALID BIT(14)
#define OA_TC6_DATA_HEADER_END_BYTE_OFFSET GENMASK(13, 8)
+#define OA_TC6_DATA_HEADER_TSC_OFFSET GENMASK(7, 6)
#define OA_TC6_DATA_HEADER_PARITY BIT(0)
/* Data footer */
@@ -75,6 +87,8 @@
#define OA_TC6_DATA_FOOTER_START_VALID BIT(20)
#define OA_TC6_DATA_FOOTER_START_WORD_OFFSET GENMASK(19, 16)
#define OA_TC6_DATA_FOOTER_END_VALID BIT(14)
+#define OA_TC6_DATA_FOOTER_RTSA_VALID BIT(7)
+#define OA_TC6_DATA_FOOTER_RTSP_VALID BIT(6)
#define OA_TC6_DATA_FOOTER_END_BYTE_OFFSET GENMASK(13, 8)
#define OA_TC6_DATA_FOOTER_TX_CREDITS GENMASK(5, 1)
@@ -105,6 +119,22 @@
#define STATUS0_RESETC_POLL_DELAY 1000
#define STATUS0_RESETC_POLL_TIMEOUT 1000000
+#define OA_TC6_REG_TTSCA_HIGH (0x1010)
+#define OA_TC6_TSTAMP_SZ 8
+
+#define OA_TC6_TTSCA_REG_ID 1
+#define OA_TC6_TTSCB_REG_ID 2
+#define OA_TC6_TTSCC_REG_ID 3
+
+struct oa_tc6_ts_info_rx {
+ bool rtsa;
+ bool rtsp;
+};
+
+struct oa_tc6_ts_info_tx {
+ u8 tsc;
+};
+
/* Internal structure for MAC-PHY drivers */
struct oa_tc6 {
struct device *dev;
@@ -130,6 +160,9 @@ struct oa_tc6 {
bool rx_buf_overflow;
bool int_flag;
int vend1_mms;
+ u8 tx_ts_idx;
+ struct hwtstamp_config ts_config;
+ struct list_head tx_ts_skb_q;
};
enum oa_tc6_header_type {
@@ -191,6 +224,238 @@ static int oa_tc6_get_parity(u32 p)
return !((p >> 28) & 1);
}
+static inline struct oa_tc6_ts_info_tx *oa_tc6_tsinfo_tx(struct sk_buff *skb)
+{
+ return (struct oa_tc6_ts_info_tx *)((skb)->cb);
+}
+
+static inline struct oa_tc6_ts_info_rx *oa_tc6_tsinfo_rx(struct sk_buff *skb)
+{
+ return (struct oa_tc6_ts_info_rx *)((skb)->cb);
+}
+
+static void oa_tc6_defer_for_hwtstamp(struct oa_tc6 *tc6, struct sk_buff *skb)
+{
+ if (tc6->ts_config.tx_type != HWTSTAMP_TX_ON || !skb ||
+ (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) == 0)
+ return;
+
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ u8 ret = tc6->tx_ts_idx++;
+
+ if (ret == OA_TC6_TTSCC_REG_ID)
+ tc6->tx_ts_idx = OA_TC6_TTSCA_REG_ID;
+ oa_tc6_tsinfo_tx(skb)->tsc = ret;
+
+ list_add_tail(&skb->list, &tc6->tx_ts_skb_q);
+}
+
+static int oa_tc6_process_deferred_skb(struct oa_tc6 *tc6, u8 tsc)
+{
+ struct skb_shared_hwtstamps tstamp;
+ struct oa_tc6_ts_info_tx *ski;
+ struct sk_buff *skb, *tmp;
+ bool found = false;
+ int ret = 0;
+
+ /* Size of data must match OA_TC6_TSTAMP_SZ */
+ u32 data[2];
+
+ list_for_each_entry_safe(skb, tmp, &tc6->tx_ts_skb_q, list) {
+ ski = oa_tc6_tsinfo_tx(skb);
+ if (ski->tsc != tsc)
+ continue;
+ if (found)
+ dev_warn(&tc6->spi->dev, "Multiple skb with tsc = %d\n", tsc);
+ found = true;
+ list_del(&skb->list);
+
+ // Retrieve the timestamping info
+ ret = oa_tc6_read_registers(tc6,
+ OA_TC6_REG_TTSCA_HIGH +
+ 2 * (tsc - 1), &data[0], 2);
+
+ if (!ret) {
+ tstamp.hwtstamp = ktime_set(data[0], data[1]);
+ skb_tstamp_tx(skb, &tstamp);
+ }
+
+ dev_kfree_skb(skb);
+ }
+ return ret;
+}
+
+static int oa_tc6_set_hwtstamp_settings(struct oa_tc6 *tc6)
+{
+ u32 cfg0, irqm, status0;
+ int ret;
+
+ ret = oa_tc6_read_register(tc6, OA_TC6_REG_CONFIG0, &cfg0);
+ if (ret) {
+ dev_err(&tc6->spi->dev, "Failed to read CFG0 register\n");
+ goto out;
+ }
+
+ ret = oa_tc6_read_register(tc6, OA_TC6_REG_INT_MASK0, &irqm);
+ if (ret) {
+ dev_err(&tc6->spi->dev, "failed to read IRQM register\n");
+ goto out;
+ }
+
+ if (tc6->ts_config.tx_type == HWTSTAMP_TX_ON ||
+ tc6->ts_config.rx_filter == HWTSTAMP_FILTER_ALL)
+ cfg0 |= CONFIG0_FTS_ENABLE_MASK;
+ else
+ cfg0 &= ~CONFIG0_FTS_ENABLE_MASK;
+
+ if (tc6->ts_config.tx_type == HWTSTAMP_TX_ON)
+ irqm &= ~INT_MASK0_TTSCA_MASK;
+ else
+ irqm |= INT_MASK0_TTSCA_MASK;
+
+ /* Clear timestamp related IRQs */
+ status0 = STATUS0_TTSCA_MASK;
+ ret = oa_tc6_write_register(tc6, OA_TC6_REG_STATUS0, status0);
+ if (ret) {
+ dev_err(&tc6->spi->dev, "failed to write STATUS0 register\n");
+ goto out;
+ }
+
+ // apply configuration
+ ret = oa_tc6_write_register(tc6, OA_TC6_REG_INT_MASK0, irqm);
+ if (ret) {
+ dev_err(&tc6->spi->dev, "failed to write IRQM register\n");
+ goto out;
+ }
+
+ ret = oa_tc6_write_register(tc6, OA_TC6_REG_CONFIG0, cfg0);
+ if (ret) {
+ dev_err(&tc6->spi->dev, "failed to write CFG0 register\n");
+ goto out;
+ }
+out:
+ return ret;
+}
+
+static void oa_tc6_events_handle(struct oa_tc6 *tc6, u32 val)
+{
+ /* check TX timestamping */
+ if (val & STATUS0_TTSCAA)
+ oa_tc6_process_deferred_skb(tc6, OA_TC6_TTSCA_REG_ID);
+
+ if (val & STATUS0_TTSCAB)
+ oa_tc6_process_deferred_skb(tc6, OA_TC6_TTSCB_REG_ID);
+
+ if (val & STATUS0_TTSCAC)
+ oa_tc6_process_deferred_skb(tc6, OA_TC6_TTSCC_REG_ID);
+}
+
+static void oa_tc6_update_ts_in_rx_skb(struct oa_tc6 *tc6)
+{
+ struct sk_buff *skb = tc6->rx_skb;
+ struct oa_tc6_ts_info_rx *ski;
+ u32 ts[2];
+
+ ski = oa_tc6_tsinfo_rx(skb);
+ if (!ski->rtsa)
+ return;
+
+ ts[0] = be32_to_cpu(*((u32 *)(skb->data)));
+ ts[1] = be32_to_cpu(*((u32 *)(skb->data) + 1));
+
+ /* Check parity */
+ if ((oa_tc6_get_parity(ts[0]) ^ oa_tc6_get_parity(ts[1])) ==
+ !ski->rtsp) {
+ struct skb_shared_hwtstamps *hw_ts;
+ /* Report timestamp to the upper layers */
+ hw_ts = skb_hwtstamps(skb);
+ memset(hw_ts, 0, sizeof(*hw_ts));
+ hw_ts->hwtstamp = ktime_set(ts[0], ts[1]);
+ }
+ skb_pull(skb, sizeof(ts));
+}
+
+/**
+ * oa_tc6_hwtstamp_get - gets hardware timestamp config
+ * @tc6: oa_tc6 struct.
+ * @cfg: kernel copy of hardware timestamp config
+ */
+void oa_tc6_hwtstamp_get(struct oa_tc6 *tc6, struct kernel_hwtstamp_config *cfg)
+{
+ cfg->tx_type = tc6->ts_config.tx_type;
+ cfg->rx_filter = tc6->ts_config.rx_filter;
+}
+EXPORT_SYMBOL_GPL(oa_tc6_hwtstamp_get);
+
+/**
+ * oa_tc6_hwtstamp_set - sets hardware timestamp config
+ * @tc6: oa_tc6 struct.
+ * @cfg: kernel copy of hardware timestamp config
+ *
+ * Return: 0 on success otherwise failed.
+ */
+int oa_tc6_hwtstamp_set(struct oa_tc6 *tc6, struct kernel_hwtstamp_config *cfg)
+{
+ switch (cfg->tx_type) {
+ case HWTSTAMP_TX_OFF:
+ case HWTSTAMP_TX_ON:
+ break;
+ default:
+ return -ERANGE;
+ }
+ tc6->ts_config.tx_type = cfg->tx_type;
+ if (cfg->rx_filter == HWTSTAMP_FILTER_NONE)
+ tc6->ts_config.rx_filter = cfg->rx_filter;
+ else
+ tc6->ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
+ return oa_tc6_set_hwtstamp_settings(tc6);
+}
+EXPORT_SYMBOL_GPL(oa_tc6_hwtstamp_set);
+
+/**
+ * oa_tc6_hwtstamp_ioctl - ioctl interface for hardware timestamp
+ * @tc6: oa_tc6 struct.
+ * @rq: request from socket interface
+ * @cmd: value to set/get timestamp configuration
+ *
+ * Return: 0 on success otherwise failed.
+ */
+int oa_tc6_hwtstamp_ioctl(struct oa_tc6 *tc6, struct ifreq *rq, int cmd)
+{
+ struct kernel_hwtstamp_config kcfg;
+ struct hwtstamp_config tscfg;
+ int ret = 0;
+
+ if (!netif_running(tc6->netdev))
+ return -EINVAL;
+
+ switch (cmd) {
+ case SIOCSHWTSTAMP:
+ if (copy_from_user(&tscfg, rq->ifr_data, sizeof(tscfg)))
+ return -EFAULT;
+
+ if (tscfg.flags)
+ return -EINVAL;
+ memset(&kcfg, 0, sizeof(kcfg));
+ kcfg.tx_type = tscfg.tx_type;
+ kcfg.rx_filter = tscfg.rx_filter;
+
+ ret = oa_tc6_hwtstamp_set(tc6, &kcfg);
+ break;
+
+ case SIOCGHWTSTAMP:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ if (copy_to_user(rq->ifr_data, &tc6->ts_config,
+ sizeof(tc6->ts_config)))
+ ret = -EFAULT;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(oa_tc6_hwtstamp_ioctl);
+
/**
* Add vendor specific MDIO_MMD to OA TC6 MMS mapper value.
* @tc6: oa_tc6 struct.
@@ -697,6 +962,9 @@ static int oa_tc6_process_extended_status(struct oa_tc6 *tc6)
return ret;
}
+ if ((value & STATUS0_TTSCA_MASK) != 0)
+ oa_tc6_events_handle(tc6, value & STATUS0_TTSCA_MASK);
+
/* Clear the error interrupts status */
ret = oa_tc6_write_register(tc6, OA_TC6_REG_STATUS0, value);
if (ret) {
@@ -768,10 +1036,15 @@ static int oa_tc6_process_rx_chunk_footer(struct oa_tc6 *tc6, u32 footer)
static void oa_tc6_submit_rx_skb(struct oa_tc6 *tc6)
{
+ oa_tc6_update_ts_in_rx_skb(tc6);
+
tc6->rx_skb->protocol = eth_type_trans(tc6->rx_skb, tc6->netdev);
tc6->netdev->stats.rx_packets++;
tc6->netdev->stats.rx_bytes += tc6->rx_skb->len;
+ if ((tc6->netdev->hw_features & NETIF_F_RXFCS) != 0)
+ skb_trim(tc6->rx_skb, tc6->rx_skb->len - ETH_FCS_LEN);
+
netif_rx(tc6->rx_skb);
tc6->rx_skb = NULL;
@@ -782,24 +1055,29 @@ static void oa_tc6_update_rx_skb(struct oa_tc6 *tc6, u8 *payload, u8 length)
memcpy(skb_put(tc6->rx_skb, length), payload, length);
}
-static int oa_tc6_allocate_rx_skb(struct oa_tc6 *tc6)
+static int oa_tc6_allocate_rx_skb(struct oa_tc6 *tc6, u32 footer)
{
+ struct oa_tc6_ts_info_rx *ski;
+
tc6->rx_skb = netdev_alloc_skb_ip_align(tc6->netdev, tc6->netdev->mtu +
- ETH_HLEN + ETH_FCS_LEN);
+ ETH_HLEN + ETH_FCS_LEN + OA_TC6_TSTAMP_SZ);
if (!tc6->rx_skb) {
tc6->netdev->stats.rx_dropped++;
return -ENOMEM;
}
+ ski = oa_tc6_tsinfo_rx(tc6->rx_skb);
+ ski->rtsa = FIELD_GET(OA_TC6_DATA_FOOTER_RTSA_VALID, footer);
+ ski->rtsp = FIELD_GET(OA_TC6_DATA_FOOTER_RTSP_VALID, footer);
return 0;
}
static int oa_tc6_prcs_complete_rx_frame(struct oa_tc6 *tc6, u8 *payload,
- u16 size)
+ u16 size, u32 footer)
{
int ret;
- ret = oa_tc6_allocate_rx_skb(tc6);
+ ret = oa_tc6_allocate_rx_skb(tc6, footer);
if (ret)
return ret;
@@ -810,11 +1088,11 @@ static int oa_tc6_prcs_complete_rx_frame(struct oa_tc6 *tc6, u8 *payload,
return 0;
}
-static int oa_tc6_prcs_rx_frame_start(struct oa_tc6 *tc6, u8 *payload, u16 size)
+static int oa_tc6_prcs_rx_frame_start(struct oa_tc6 *tc6, u8 *payload, u16 size, u32 footer)
{
int ret;
- ret = oa_tc6_allocate_rx_skb(tc6);
+ ret = oa_tc6_allocate_rx_skb(tc6, footer);
if (ret)
return ret;
@@ -859,7 +1137,7 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *tc6, u8 *data,
size = end_byte_offset + 1 - start_byte_offset;
return oa_tc6_prcs_complete_rx_frame(tc6,
&data[start_byte_offset],
- size);
+ size, footer);
}
/* Process the chunk with only rx frame start */
@@ -867,7 +1145,7 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *tc6, u8 *data,
size = OA_TC6_CHUNK_PAYLOAD_SIZE - start_byte_offset;
return oa_tc6_prcs_rx_frame_start(tc6,
&data[start_byte_offset],
- size);
+ size, footer);
}
/* Process the chunk with only rx frame end */
@@ -892,7 +1170,7 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *tc6, u8 *data,
size = OA_TC6_CHUNK_PAYLOAD_SIZE - start_byte_offset;
return oa_tc6_prcs_rx_frame_start(tc6,
&data[start_byte_offset],
- size);
+ size, footer);
}
/* Process the chunk with ongoing rx frame data */
@@ -946,13 +1224,15 @@ static int oa_tc6_process_spi_data_rx_buf(struct oa_tc6 *tc6, u16 length)
}
static __be32 oa_tc6_prepare_data_header(bool data_valid, bool start_valid,
- bool end_valid, u8 end_byte_offset)
+ bool end_valid, u8 end_byte_offset,
+ u8 tsc)
{
u32 header = FIELD_PREP(OA_TC6_DATA_HEADER_DATA_NOT_CTRL,
OA_TC6_DATA_HEADER) |
FIELD_PREP(OA_TC6_DATA_HEADER_DATA_VALID, data_valid) |
FIELD_PREP(OA_TC6_DATA_HEADER_START_VALID, start_valid) |
FIELD_PREP(OA_TC6_DATA_HEADER_END_VALID, end_valid) |
+ FIELD_PREP(OA_TC6_DATA_HEADER_TSC_OFFSET, tsc) |
FIELD_PREP(OA_TC6_DATA_HEADER_END_BYTE_OFFSET,
end_byte_offset);
@@ -971,6 +1251,7 @@ static void oa_tc6_add_tx_skb_to_spi_buf(struct oa_tc6 *tc6)
enum oa_tc6_data_start_valid_info start_valid;
u8 end_byte_offset = 0;
u16 length_to_copy;
+ u8 tsc = 0;
/* Initial value is assigned here to avoid more than 80 characters in
* the declaration place.
@@ -980,8 +1261,10 @@ static void oa_tc6_add_tx_skb_to_spi_buf(struct oa_tc6 *tc6)
/* Set start valid if the current tx chunk contains the start of the tx
* ethernet frame.
*/
- if (!tc6->tx_skb_offset)
+ if (!tc6->tx_skb_offset) {
start_valid = OA_TC6_DATA_START_VALID;
+ tsc = oa_tc6_tsinfo_tx(tc6->ongoing_tx_skb)->tsc;
+ }
/* If the remaining tx skb length is more than the chunk payload size of
* 64 bytes then copy only 64 bytes and leave the ongoing tx skb for
@@ -1002,12 +1285,17 @@ static void oa_tc6_add_tx_skb_to_spi_buf(struct oa_tc6 *tc6)
tc6->tx_skb_offset = 0;
tc6->netdev->stats.tx_bytes += tc6->ongoing_tx_skb->len;
tc6->netdev->stats.tx_packets++;
- kfree_skb(tc6->ongoing_tx_skb);
+
+ /* Free the ones that are not saved for later processing,
+ * like timestamping.
+ */
+ if (!(skb_shinfo(tc6->ongoing_tx_skb)->tx_flags & SKBTX_IN_PROGRESS))
+ kfree_skb(tc6->ongoing_tx_skb);
tc6->ongoing_tx_skb = NULL;
}
*tx_buf = oa_tc6_prepare_data_header(OA_TC6_DATA_VALID, start_valid,
- end_valid, end_byte_offset);
+ end_valid, end_byte_offset, tsc);
tc6->spi_data_tx_buf_offset += OA_TC6_CHUNK_SIZE;
}
@@ -1025,6 +1313,8 @@ static u16 oa_tc6_prepare_spi_tx_buf_for_tx_skbs(struct oa_tc6 *tc6)
tc6->ongoing_tx_skb = tc6->waiting_tx_skb;
tc6->waiting_tx_skb = NULL;
spin_unlock_bh(&tc6->tx_skb_lock);
+ oa_tc6_defer_for_hwtstamp(tc6,
+ tc6->ongoing_tx_skb);
}
if (!tc6->ongoing_tx_skb)
break;
@@ -1041,7 +1331,7 @@ static void oa_tc6_add_empty_chunks_to_spi_buf(struct oa_tc6 *tc6,
header = oa_tc6_prepare_data_header(OA_TC6_DATA_INVALID,
OA_TC6_DATA_START_INVALID,
- OA_TC6_DATA_END_INVALID, 0);
+ OA_TC6_DATA_END_INVALID, 0, false);
while (needed_empty_chunks--) {
__be32 *tx_buf = tc6->spi_data_tx_buf +
@@ -1232,6 +1522,7 @@ netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb)
spin_lock_bh(&tc6->tx_skb_lock);
tc6->waiting_tx_skb = skb;
spin_unlock_bh(&tc6->tx_skb_lock);
+ oa_tc6_tsinfo_tx(skb)->tsc = 0;
/* Wake spi kthread to perform spi transfer */
wake_up_interruptible(&tc6->spi_wq);
@@ -1263,6 +1554,8 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev)
mutex_init(&tc6->spi_ctrl_lock);
spin_lock_init(&tc6->tx_skb_lock);
tc6->vend1_mms = -EOPNOTSUPP;
+ tc6->tx_ts_idx = OA_TC6_TTSCA_REG_ID;
+ INIT_LIST_HEAD(&tc6->tx_ts_skb_q);
/* Set the SPI controller to pump at realtime priority */
tc6->spi->rt = true;
diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
index d3c74555f..7fab8db3f 100644
--- a/include/linux/oa_tc6.h
+++ b/include/linux/oa_tc6.h
@@ -26,4 +26,9 @@ int oa_tc6_read_registers(struct oa_tc6 *tc6, u32 address, u32 value[],
netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb);
int oa_tc6_zero_align_receive_frame_enable(struct oa_tc6 *tc6);
void oa_tc6_set_vend1_mms(struct oa_tc6 *tc6, int mms);
+int oa_tc6_hwtstamp_ioctl(struct oa_tc6 *tc6, struct ifreq *rq, int cmd);
+void oa_tc6_hwtstamp_get(struct oa_tc6 *tc6,
+ struct kernel_hwtstamp_config *cfg);
+int oa_tc6_hwtstamp_set(struct oa_tc6 *tc6,
+ struct kernel_hwtstamp_config *cfg);
#endif /* _LINUX_OA_TC6_H */
--
2.43.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH net-next v2 6/9] net: ethernet: oa_tc6: Hardware timestamp support for OA TC6 framework
2026-05-11 18:19 [PATCH net-next v2 6/9] net: ethernet: oa_tc6: Hardware timestamp support for OA TC6 framework Selvamani Rajagopal
@ 2026-05-11 19:49 ` Andrew Lunn
0 siblings, 0 replies; 2+ messages in thread
From: Andrew Lunn @ 2026-05-11 19:49 UTC (permalink / raw)
To: Selvamani Rajagopal
Cc: Piergiorgio Beruto, parthiban.veerasooran@microchip.com,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
On Mon, May 11, 2026 at 06:19:31PM +0000, Selvamani Rajagopal wrote:
> Added hardware timestamp support as defined in Open Alliance
> 10BASET1x MACPHY_Serial_Interface specification. ioctl interface
> added for ethtool to report and set the hardware timestamp feature
7.8 Frame Timestamp Capture
The MAC-PHY may optionally support the capturing of timestamps on
Ethernet frames received from and transmitted to the network. Support
for this option is indicated by the Frame Timestamp Capability (FTSC)
bit in the STDCAP register
I don't see anything in this patch looking for FTSC.
> +/**
> + * oa_tc6_hwtstamp_ioctl - ioctl interface for hardware timestamp
> + * @tc6: oa_tc6 struct.
> + * @rq: request from socket interface
> + * @cmd: value to set/get timestamp configuration
> + *
> + * Return: 0 on success otherwise failed.
> + */
> +int oa_tc6_hwtstamp_ioctl(struct oa_tc6 *tc6, struct ifreq *rq, int cmd)
> +{
It would be better to add a generic ioctl handler. It can call
phy_do_ioctl_running(), and can check if time stamping is support in
the hardware, and if so, also support the time stamping IOCTL calls.
Andrew
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-05-11 19:49 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-11 18:19 [PATCH net-next v2 6/9] net: ethernet: oa_tc6: Hardware timestamp support for OA TC6 framework Selvamani Rajagopal
2026-05-11 19:49 ` Andrew Lunn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox