drivers: eth_nxp_imx_netc: support PTP timestamping
Added PTP timestamping support. Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
This commit is contained in:
parent
e0aa603f9c
commit
2cf5c7091a
@ -12,6 +12,9 @@ LOG_MODULE_REGISTER(nxp_imx_eth);
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/mbox.h>
|
||||
#include <zephyr/drivers/pinctrl.h>
|
||||
#ifdef CONFIG_PTP_CLOCK_NXP_NETC
|
||||
#include <zephyr/drivers/ptp_clock.h>
|
||||
#endif
|
||||
#include <zephyr/net/ethernet.h>
|
||||
#include <zephyr/net/net_if.h>
|
||||
#include <zephyr/net/net_pkt.h>
|
||||
@ -28,6 +31,44 @@ LOG_MODULE_REGISTER(nxp_imx_eth);
|
||||
|
||||
const struct device *netc_dev_list[NETC_DRV_MAX_INST_SUPPORT];
|
||||
|
||||
#ifdef CONFIG_PTP_CLOCK_NXP_NETC
|
||||
static void netc_eth_pkt_get_timestamp(struct net_pkt *pkt, const struct device *ptp_clock,
|
||||
uint32_t timestamp)
|
||||
{
|
||||
struct net_ptp_time ptp_time = {0};
|
||||
uint64_t time_ns;
|
||||
uint32_t time_h;
|
||||
uint32_t time_l;
|
||||
|
||||
/*
|
||||
* Packet timestamp is lower 32-bit ns value.
|
||||
* Need to reconstruct 64-bit ns value with ptp clock time.
|
||||
*/
|
||||
ptp_clock_get(ptp_clock, &ptp_time);
|
||||
|
||||
time_ns = ptp_time.second * NSEC_PER_SEC + ptp_time.nanosecond;
|
||||
time_h = time_ns >> 32;
|
||||
time_l = time_ns & 0xffffffff;
|
||||
|
||||
/* Check if wrap happened. */
|
||||
if (time_l <= timestamp) {
|
||||
time_h--;
|
||||
}
|
||||
|
||||
time_ns = (uint64_t)time_h << 32 | timestamp;
|
||||
|
||||
pkt->timestamp.nanosecond = time_ns % NSEC_PER_SEC;
|
||||
pkt->timestamp.second = time_ns / NSEC_PER_SEC;
|
||||
}
|
||||
|
||||
const struct device *netc_eth_get_ptp_clock(const struct device *dev)
|
||||
{
|
||||
const struct netc_eth_config *cfg = dev->config;
|
||||
|
||||
return cfg->ptp_clock;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int netc_eth_rx(const struct device *dev)
|
||||
{
|
||||
struct netc_eth_data *data = dev->data;
|
||||
@ -85,6 +126,13 @@ static int netc_eth_rx(const struct device *dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PTP_CLOCK_NXP_NETC
|
||||
if (attr.isTsAvail) {
|
||||
const struct netc_eth_config *cfg = dev->config;
|
||||
|
||||
netc_eth_pkt_get_timestamp(pkt, cfg->ptp_clock, attr.timestamp);
|
||||
}
|
||||
#endif
|
||||
/* Send to upper layer */
|
||||
ret = net_recv_data(iface_dst, pkt);
|
||||
if (ret < 0) {
|
||||
@ -169,6 +217,10 @@ int netc_eth_init_common(const struct device *dev)
|
||||
|
||||
config->bdr_init(&bdr_config, &rx_bdr_config, &tx_bdr_config);
|
||||
|
||||
#ifdef CONFIG_PTP_CLOCK_NXP_NETC
|
||||
bdr_config.rxBdrConfig[0].extendDescEn = true;
|
||||
#endif
|
||||
|
||||
/* MSIX entry configuration */
|
||||
msg_addr = MSGINTR_GetIntrSelectAddr(NETC_MSGINTR, NETC_MSGINTR_CHANNEL);
|
||||
msix_entry[NETC_TX_MSIX_ENTRY_IDX].control = kNETC_MsixIntrMaskBit;
|
||||
@ -254,7 +306,10 @@ int netc_eth_tx(const struct device *dev, struct net_pkt *pkt)
|
||||
#endif
|
||||
status_t result;
|
||||
int ret;
|
||||
|
||||
ep_tx_opt opt = {0};
|
||||
#ifdef CONFIG_PTP_CLOCK_NXP_NETC
|
||||
bool pkt_is_gptp;
|
||||
#endif
|
||||
__ASSERT(pkt, "Packet pointer is NULL");
|
||||
|
||||
iface_dst = data->iface;
|
||||
@ -274,6 +329,12 @@ int netc_eth_tx(const struct device *dev, struct net_pkt *pkt)
|
||||
|
||||
k_mutex_lock(&data->tx_mutex, K_FOREVER);
|
||||
|
||||
#ifdef CONFIG_PTP_CLOCK_NXP_NETC
|
||||
pkt_is_gptp = ntohs(NET_ETH_HDR(pkt)->type) == NET_ETH_PTYPE_PTP;
|
||||
if (pkt_is_gptp || net_pkt_is_tx_timestamping(pkt)) {
|
||||
opt.flags |= kEP_TX_OPT_REQ_TS;
|
||||
}
|
||||
#endif
|
||||
/* Copy packet to tx buffer */
|
||||
buff.length = (uint16_t)pkt_len;
|
||||
ret = net_pkt_read(pkt, buff.buffer, pkt_len);
|
||||
@ -298,10 +359,10 @@ int netc_eth_tx(const struct device *dev, struct net_pkt *pkt)
|
||||
result = EP_SendFrameCommon(&data->handle, &data->handle.txBdRing[0], 0, &frame,
|
||||
NULL, &txDesc[0], data->handle.cfg.txCacheMaintain);
|
||||
} else {
|
||||
result = EP_SendFrame(&data->handle, 0, &frame, NULL, NULL);
|
||||
result = EP_SendFrame(&data->handle, 0, &frame, NULL, &opt);
|
||||
}
|
||||
#else
|
||||
result = EP_SendFrame(&data->handle, 0, &frame, NULL, NULL);
|
||||
result = EP_SendFrame(&data->handle, 0, &frame, NULL, &opt);
|
||||
#endif
|
||||
if (result != kStatus_Success) {
|
||||
LOG_ERR("Failed to tx frame");
|
||||
@ -314,7 +375,7 @@ int netc_eth_tx(const struct device *dev, struct net_pkt *pkt)
|
||||
|
||||
do {
|
||||
frame_info = EP_ReclaimTxDescCommon(&data->handle, &data->handle.txBdRing[0],
|
||||
0, false);
|
||||
0, true);
|
||||
if (frame_info != NULL) {
|
||||
if (frame_info->status != kNETC_EPTxSuccess) {
|
||||
memset(frame_info, 0, sizeof(netc_tx_frame_info_t));
|
||||
@ -322,6 +383,14 @@ int netc_eth_tx(const struct device *dev, struct net_pkt *pkt)
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PTP_CLOCK_NXP_NETC
|
||||
if (frame_info->isTsAvail) {
|
||||
netc_eth_pkt_get_timestamp(pkt, cfg->ptp_clock,
|
||||
frame_info->timestamp);
|
||||
net_if_add_tx_timestamp(pkt);
|
||||
}
|
||||
#endif
|
||||
memset(frame_info, 0, sizeof(netc_tx_frame_info_t));
|
||||
}
|
||||
} while (frame_info != NULL);
|
||||
@ -345,6 +414,9 @@ enum ethernet_hw_caps netc_eth_get_capabilities(const struct device *dev)
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
| ETHERNET_HW_VLAN
|
||||
#endif
|
||||
#if defined(CONFIG_PTP_CLOCK_NXP_NETC)
|
||||
| ETHERNET_PTP
|
||||
#endif
|
||||
#if defined(CONFIG_NET_PROMISCUOUS_MODE)
|
||||
| ETHERNET_PROMISC_MODE
|
||||
#endif
|
||||
|
||||
@ -92,6 +92,9 @@ struct netc_eth_config {
|
||||
const struct pinctrl_dev_config *pincfg;
|
||||
uint8_t tx_intr_msg_data;
|
||||
uint8_t rx_intr_msg_data;
|
||||
#ifdef CONFIG_PTP_CLOCK_NXP_NETC
|
||||
const struct device *ptp_clock;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef uint8_t rx_buffer_t[NETC_RX_RING_BUF_SIZE_ALIGN];
|
||||
@ -117,5 +120,7 @@ int netc_eth_tx(const struct device *dev, struct net_pkt *pkt);
|
||||
enum ethernet_hw_caps netc_eth_get_capabilities(const struct device *dev);
|
||||
int netc_eth_set_config(const struct device *dev, enum ethernet_config_type type,
|
||||
const struct ethernet_config *config);
|
||||
|
||||
#ifdef CONFIG_PTP_CLOCK_NXP_NETC
|
||||
const struct device *netc_eth_get_ptp_clock(const struct device *dev);
|
||||
#endif
|
||||
#endif /* ZEPHYR_DRIVERS_ETHERNET_ETH_NXP_IMX_NETC_PRIV_H_ */
|
||||
|
||||
@ -128,6 +128,9 @@ static const struct ethernet_api netc_eth_api = {.iface_api.init = netc_eth_ifac
|
||||
.get_capabilities = netc_eth_get_capabilities,
|
||||
.get_phy = netc_eth_get_phy,
|
||||
.set_config = netc_eth_set_config,
|
||||
#ifdef CONFIG_PTP_CLOCK_NXP_NETC
|
||||
.get_ptp_clock = netc_eth_get_ptp_clock,
|
||||
#endif
|
||||
.send = netc_eth_tx};
|
||||
|
||||
#define NETC_PSI_INSTANCE_DEFINE(n) \
|
||||
@ -199,6 +202,8 @@ static const struct ethernet_api netc_eth_api = {.iface_api.init = netc_eth_ifac
|
||||
.si_idx = (DT_INST_PROP(n, mac_index) << 8) | DT_INST_PROP(n, si_index), \
|
||||
.tx_intr_msg_data = NETC_TX_INTR_MSG_DATA_START + n, \
|
||||
.rx_intr_msg_data = NETC_RX_INTR_MSG_DATA_START + n, \
|
||||
IF_ENABLED(CONFIG_PTP_CLOCK_NXP_NETC, \
|
||||
(.ptp_clock = DEVICE_DT_GET(DT_INST_PHANDLE(n, ptp_clock)),)) \
|
||||
}; \
|
||||
ETH_NET_DEVICE_DT_INST_DEFINE(n, netc_eth_init, NULL, &netc_eth##n##_data, \
|
||||
&netc_eth##n##_config, CONFIG_ETH_INIT_PRIORITY, \
|
||||
|
||||
Loading…
Reference in New Issue
Block a user