Skip to content

Commit b1f66a5

Browse files
grygoriySdavem330
authored andcommitted
net: ethernet: ti: am65-cpsw-nuss: enable packet timestamping support
The MCU CPSW Common Platform Time Sync (CPTS) provides possibility to timestamp TX PTP packets and all RX packets. This enables corresponding support in TI AM65x/J721E MCU CPSW driver. Signed-off-by: Grygorii Strashko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f6bd595 commit b1f66a5

File tree

4 files changed

+201
-2
lines changed

4 files changed

+201
-2
lines changed

drivers/net/ethernet/ti/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ config TI_K3_AM65_CPSW_NUSS
100100
depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER
101101
select TI_DAVINCI_MDIO
102102
imply PHY_TI_GMII_SEL
103+
imply TI_AM65_CPTS
103104
help
104105
This driver supports TI K3 AM654/J721E CPSW2G Ethernet SubSystem.
105106
The two-port Gigabit Ethernet MAC (MCU_CPSW0) subsystem provides

drivers/net/ethernet/ti/am65-cpsw-ethtool.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "am65-cpsw-nuss.h"
1414
#include "cpsw_ale.h"
15+
#include "am65-cpts.h"
1516

1617
#define AM65_CPSW_REGDUMP_VER 0x1
1718

@@ -694,6 +695,27 @@ static void am65_cpsw_get_ethtool_stats(struct net_device *ndev,
694695
hw_stats[i].offset);
695696
}
696697

698+
static int am65_cpsw_get_ethtool_ts_info(struct net_device *ndev,
699+
struct ethtool_ts_info *info)
700+
{
701+
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
702+
703+
if (!IS_ENABLED(CONFIG_TI_K3_AM65_CPTS))
704+
return ethtool_op_get_ts_info(ndev, info);
705+
706+
info->so_timestamping =
707+
SOF_TIMESTAMPING_TX_HARDWARE |
708+
SOF_TIMESTAMPING_TX_SOFTWARE |
709+
SOF_TIMESTAMPING_RX_HARDWARE |
710+
SOF_TIMESTAMPING_RX_SOFTWARE |
711+
SOF_TIMESTAMPING_SOFTWARE |
712+
SOF_TIMESTAMPING_RAW_HARDWARE;
713+
info->phc_index = am65_cpts_phc_index(common->cpts);
714+
info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
715+
info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
716+
return 0;
717+
}
718+
697719
static u32 am65_cpsw_get_ethtool_priv_flags(struct net_device *ndev)
698720
{
699721
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
@@ -730,7 +752,7 @@ const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
730752
.get_sset_count = am65_cpsw_get_sset_count,
731753
.get_strings = am65_cpsw_get_strings,
732754
.get_ethtool_stats = am65_cpsw_get_ethtool_stats,
733-
.get_ts_info = ethtool_op_get_ts_info,
755+
.get_ts_info = am65_cpsw_get_ethtool_ts_info,
734756
.get_priv_flags = am65_cpsw_get_ethtool_priv_flags,
735757
.set_priv_flags = am65_cpsw_set_ethtool_priv_flags,
736758

drivers/net/ethernet/ti/am65-cpsw-nuss.c

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "cpsw_sl.h"
3131
#include "am65-cpsw-nuss.h"
3232
#include "k3-cppi-desc-pool.h"
33+
#include "am65-cpts.h"
3334

3435
#define AM65_CPSW_SS_BASE 0x0
3536
#define AM65_CPSW_SGMII_BASE 0x100
@@ -668,6 +669,18 @@ static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma)
668669
dev_kfree_skb_any(skb);
669670
}
670671

672+
static void am65_cpsw_nuss_rx_ts(struct sk_buff *skb, u32 *psdata)
673+
{
674+
struct skb_shared_hwtstamps *ssh;
675+
u64 ns;
676+
677+
ns = ((u64)psdata[1] << 32) | psdata[0];
678+
679+
ssh = skb_hwtstamps(skb);
680+
memset(ssh, 0, sizeof(*ssh));
681+
ssh->hwtstamp = ns_to_ktime(ns);
682+
}
683+
671684
/* RX psdata[2] word format - checksum information */
672685
#define AM65_CPSW_RX_PSD_CSUM_ADD GENMASK(15, 0)
673686
#define AM65_CPSW_RX_PSD_CSUM_ERR BIT(16)
@@ -745,6 +758,9 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_common *common,
745758
skb->dev = ndev;
746759

747760
psdata = cppi5_hdesc_get_psdata(desc_rx);
761+
/* add RX timestamp */
762+
if (port->rx_ts_enabled)
763+
am65_cpsw_nuss_rx_ts(skb, psdata);
748764
csum_info = psdata[2];
749765
dev_dbg(dev, "%s rx csum_info:%#x\n", __func__, csum_info);
750766

@@ -904,6 +920,8 @@ static int am65_cpsw_nuss_tx_compl_packets(struct am65_cpsw_common *common,
904920

905921
ndev = skb->dev;
906922

923+
am65_cpts_tx_timestamp(common->cpts, skb);
924+
907925
ndev_priv = netdev_priv(ndev);
908926
stats = this_cpu_ptr(ndev_priv->stats);
909927
u64_stats_update_begin(&stats->syncp);
@@ -995,6 +1013,10 @@ static netdev_tx_t am65_cpsw_nuss_ndo_slave_xmit(struct sk_buff *skb,
9951013
/* padding enabled in hw */
9961014
pkt_len = skb_headlen(skb);
9971015

1016+
/* SKB TX timestamp */
1017+
if (port->tx_ts_enabled)
1018+
am65_cpts_prep_tx_timestamp(common->cpts, skb);
1019+
9981020
q_idx = skb_get_queue_mapping(skb);
9991021
dev_dbg(dev, "%s skb_queue:%d\n", __func__, q_idx);
10001022

@@ -1158,6 +1180,111 @@ static int am65_cpsw_nuss_ndo_slave_set_mac_address(struct net_device *ndev,
11581180
return 0;
11591181
}
11601182

1183+
static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
1184+
struct ifreq *ifr)
1185+
{
1186+
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
1187+
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
1188+
u32 ts_ctrl, seq_id, ts_ctrl_ltype2, ts_vlan_ltype;
1189+
struct hwtstamp_config cfg;
1190+
1191+
if (!IS_ENABLED(CONFIG_TI_K3_AM65_CPTS))
1192+
return -EOPNOTSUPP;
1193+
1194+
if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
1195+
return -EFAULT;
1196+
1197+
/* TX HW timestamp */
1198+
switch (cfg.tx_type) {
1199+
case HWTSTAMP_TX_OFF:
1200+
case HWTSTAMP_TX_ON:
1201+
break;
1202+
default:
1203+
return -ERANGE;
1204+
}
1205+
1206+
switch (cfg.rx_filter) {
1207+
case HWTSTAMP_FILTER_NONE:
1208+
port->rx_ts_enabled = false;
1209+
break;
1210+
case HWTSTAMP_FILTER_ALL:
1211+
case HWTSTAMP_FILTER_SOME:
1212+
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
1213+
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
1214+
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
1215+
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
1216+
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
1217+
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
1218+
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
1219+
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
1220+
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
1221+
case HWTSTAMP_FILTER_PTP_V2_EVENT:
1222+
case HWTSTAMP_FILTER_PTP_V2_SYNC:
1223+
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
1224+
case HWTSTAMP_FILTER_NTP_ALL:
1225+
port->rx_ts_enabled = true;
1226+
cfg.rx_filter = HWTSTAMP_FILTER_ALL;
1227+
break;
1228+
default:
1229+
return -ERANGE;
1230+
}
1231+
1232+
port->tx_ts_enabled = (cfg.tx_type == HWTSTAMP_TX_ON);
1233+
1234+
/* cfg TX timestamp */
1235+
seq_id = (AM65_CPSW_TS_SEQ_ID_OFFSET <<
1236+
AM65_CPSW_PN_TS_SEQ_ID_OFFSET_SHIFT) | ETH_P_1588;
1237+
1238+
ts_vlan_ltype = ETH_P_8021Q;
1239+
1240+
ts_ctrl_ltype2 = ETH_P_1588 |
1241+
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_107 |
1242+
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_129 |
1243+
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_130 |
1244+
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_131 |
1245+
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_132 |
1246+
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_319 |
1247+
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_320 |
1248+
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_TTL_NONZERO;
1249+
1250+
ts_ctrl = AM65_CPSW_TS_EVENT_MSG_TYPE_BITS <<
1251+
AM65_CPSW_PN_TS_CTL_MSG_TYPE_EN_SHIFT;
1252+
1253+
if (port->tx_ts_enabled)
1254+
ts_ctrl |= AM65_CPSW_TS_TX_ANX_ALL_EN |
1255+
AM65_CPSW_PN_TS_CTL_TX_VLAN_LT1_EN;
1256+
1257+
writel(seq_id, port->port_base + AM65_CPSW_PORTN_REG_TS_SEQ_LTYPE_REG);
1258+
writel(ts_vlan_ltype, port->port_base +
1259+
AM65_CPSW_PORTN_REG_TS_VLAN_LTYPE_REG);
1260+
writel(ts_ctrl_ltype2, port->port_base +
1261+
AM65_CPSW_PORTN_REG_TS_CTL_LTYPE2);
1262+
writel(ts_ctrl, port->port_base + AM65_CPSW_PORTN_REG_TS_CTL);
1263+
1264+
/* en/dis RX timestamp */
1265+
am65_cpts_rx_enable(common->cpts, port->rx_ts_enabled);
1266+
1267+
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
1268+
}
1269+
1270+
static int am65_cpsw_nuss_hwtstamp_get(struct net_device *ndev,
1271+
struct ifreq *ifr)
1272+
{
1273+
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
1274+
struct hwtstamp_config cfg;
1275+
1276+
if (!IS_ENABLED(CONFIG_TI_K3_AM65_CPTS))
1277+
return -EOPNOTSUPP;
1278+
1279+
cfg.flags = 0;
1280+
cfg.tx_type = port->tx_ts_enabled ?
1281+
HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
1282+
cfg.rx_filter = port->rx_ts_enabled ?
1283+
HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
1284+
1285+
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
1286+
}
1287+
11611288
static int am65_cpsw_nuss_ndo_slave_ioctl(struct net_device *ndev,
11621289
struct ifreq *req, int cmd)
11631290
{
@@ -1166,6 +1293,13 @@ static int am65_cpsw_nuss_ndo_slave_ioctl(struct net_device *ndev,
11661293
if (!netif_running(ndev))
11671294
return -EINVAL;
11681295

1296+
switch (cmd) {
1297+
case SIOCSHWTSTAMP:
1298+
return am65_cpsw_nuss_hwtstamp_set(ndev, req);
1299+
case SIOCGHWTSTAMP:
1300+
return am65_cpsw_nuss_hwtstamp_get(ndev, req);
1301+
}
1302+
11691303
if (!port->slave.phy)
11701304
return -EOPNOTSUPP;
11711305

@@ -1531,6 +1665,40 @@ static int am65_cpsw_am654_get_efuse_macid(struct device_node *of_node,
15311665
return 0;
15321666
}
15331667

1668+
static int am65_cpsw_init_cpts(struct am65_cpsw_common *common)
1669+
{
1670+
struct device *dev = common->dev;
1671+
struct device_node *node;
1672+
struct am65_cpts *cpts;
1673+
void __iomem *reg_base;
1674+
1675+
if (!IS_ENABLED(CONFIG_TI_K3_AM65_CPTS))
1676+
return 0;
1677+
1678+
node = of_get_child_by_name(dev->of_node, "cpts");
1679+
if (!node) {
1680+
dev_err(dev, "%s cpts not found\n", __func__);
1681+
return -ENOENT;
1682+
}
1683+
1684+
reg_base = common->cpsw_base + AM65_CPSW_NU_CPTS_BASE;
1685+
cpts = am65_cpts_create(dev, reg_base, node);
1686+
if (IS_ERR(cpts)) {
1687+
int ret = PTR_ERR(cpts);
1688+
1689+
if (ret == -EOPNOTSUPP) {
1690+
dev_info(dev, "cpts disabled\n");
1691+
return 0;
1692+
}
1693+
1694+
dev_err(dev, "cpts create err %d\n", ret);
1695+
return ret;
1696+
}
1697+
common->cpts = cpts;
1698+
1699+
return 0;
1700+
}
1701+
15341702
static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
15351703
{
15361704
struct device_node *node, *port_np;
@@ -1899,6 +2067,10 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
18992067
goto err_of_clear;
19002068
}
19012069

2070+
ret = am65_cpsw_init_cpts(common);
2071+
if (ret)
2072+
goto err_of_clear;
2073+
19022074
/* init ports */
19032075
for (i = 0; i < common->port_num; i++)
19042076
am65_cpsw_nuss_slave_disable_unused(&common->ports[i]);

drivers/net/ethernet/ti/am65-cpsw-nuss.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <linux/module.h>
1111
#include <linux/netdevice.h>
1212

13+
struct am65_cpts;
14+
1315
#define HOST_PORT_NUM 0
1416

1517
#define AM65_CPSW_MAX_TX_QUEUES 8
@@ -37,6 +39,8 @@ struct am65_cpsw_port {
3739
void __iomem *stat_base;
3840
bool disabled;
3941
struct am65_cpsw_slave_data slave;
42+
bool tx_ts_enabled;
43+
bool rx_ts_enabled;
4044
};
4145

4246
struct am65_cpsw_host {
@@ -96,8 +100,8 @@ struct am65_cpsw_common {
96100

97101
u32 nuss_ver;
98102
u32 cpsw_ver;
99-
100103
bool pf_p0_rx_ptype_rrobin;
104+
struct am65_cpts *cpts;
101105
};
102106

103107
struct am65_cpsw_ndev_stats {

0 commit comments

Comments
 (0)