Skip to content

Commit

Permalink
tsnep: Add free running cycle counter support
Browse files Browse the repository at this point in the history
The TSN endpoint Ethernet MAC supports a free running counter
additionally to its clock. This free running counter can be read and
hardware timestamps are supported. As the name implies, this counter
cannot be set and its frequency cannot be adjusted.

Add free running cycle counter support based on this free running
counter to physical clock. This also requires hardware time stamps
based on that free running counter.

Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com>
Acked-by: Jonathan Lemon <jonathan.lemon@gmail.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Gerhard Engleder authored and Paolo Abeni committed May 10, 2022
1 parent fcf308e commit 0abb62b
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 7 deletions.
9 changes: 7 additions & 2 deletions drivers/net/ethernet/engleder/tsnep_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
#define ECM_RESET_CHANNEL 0x00000100
#define ECM_RESET_TXRX 0x00010000

/* counter */
#define ECM_COUNTER_LOW 0x0028
#define ECM_COUNTER_HIGH 0x002C

/* control and status */
#define ECM_STATUS 0x0080
#define ECM_LINK_MODE_OFF 0x01000000
Expand Down Expand Up @@ -190,7 +194,8 @@ struct tsnep_tx_desc {
/* tsnep TX descriptor writeback */
struct tsnep_tx_desc_wb {
__le32 properties;
__le32 reserved1[3];
__le32 reserved1;
__le64 counter;
__le64 timestamp;
__le32 dma_delay;
__le32 reserved2;
Expand Down Expand Up @@ -221,7 +226,7 @@ struct tsnep_rx_desc_wb {

/* tsnep RX inline meta */
struct tsnep_rx_inline {
__le64 reserved;
__le64 counter;
__le64 timestamp;
};

Expand Down
33 changes: 28 additions & 5 deletions drivers/net/ethernet/engleder/tsnep_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,15 @@ static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget)
(__le32_to_cpu(entry->desc_wb->properties) &
TSNEP_DESC_EXTENDED_WRITEBACK_FLAG)) {
struct skb_shared_hwtstamps hwtstamps;
u64 timestamp =
__le64_to_cpu(entry->desc_wb->timestamp);
u64 timestamp;

if (skb_shinfo(entry->skb)->tx_flags &
SKBTX_HW_TSTAMP_USE_CYCLES)
timestamp =
__le64_to_cpu(entry->desc_wb->counter);
else
timestamp =
__le64_to_cpu(entry->desc_wb->timestamp);

memset(&hwtstamps, 0, sizeof(hwtstamps));
hwtstamps.hwtstamp = ns_to_ktime(timestamp);
Expand Down Expand Up @@ -704,11 +711,11 @@ static int tsnep_rx_poll(struct tsnep_rx *rx, struct napi_struct *napi,
skb_hwtstamps(skb);
struct tsnep_rx_inline *rx_inline =
(struct tsnep_rx_inline *)skb->data;
u64 timestamp =
__le64_to_cpu(rx_inline->timestamp);

skb_shinfo(skb)->tx_flags |=
SKBTX_HW_TSTAMP_NETDEV;
memset(hwtstamps, 0, sizeof(*hwtstamps));
hwtstamps->hwtstamp = ns_to_ktime(timestamp);
hwtstamps->netdev_data = rx_inline;
}
skb_pull(skb, TSNEP_RX_INLINE_METADATA_SIZE);
skb->protocol = eth_type_trans(skb,
Expand Down Expand Up @@ -1010,6 +1017,21 @@ static int tsnep_netdev_set_mac_address(struct net_device *netdev, void *addr)
return 0;
}

static ktime_t tsnep_netdev_get_tstamp(struct net_device *netdev,
const struct skb_shared_hwtstamps *hwtstamps,
bool cycles)
{
struct tsnep_rx_inline *rx_inline = hwtstamps->netdev_data;
u64 timestamp;

if (cycles)
timestamp = __le64_to_cpu(rx_inline->counter);
else
timestamp = __le64_to_cpu(rx_inline->timestamp);

return ns_to_ktime(timestamp);
}

static const struct net_device_ops tsnep_netdev_ops = {
.ndo_open = tsnep_netdev_open,
.ndo_stop = tsnep_netdev_close,
Expand All @@ -1019,6 +1041,7 @@ static const struct net_device_ops tsnep_netdev_ops = {

.ndo_get_stats64 = tsnep_netdev_get_stats64,
.ndo_set_mac_address = tsnep_netdev_set_mac_address,
.ndo_get_tstamp = tsnep_netdev_get_tstamp,
.ndo_setup_tc = tsnep_tc_setup,
};

Expand Down
28 changes: 28 additions & 0 deletions drivers/net/ethernet/engleder/tsnep_ptp.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,33 @@ static int tsnep_ptp_settime64(struct ptp_clock_info *ptp,
return 0;
}

static int tsnep_ptp_getcyclesx64(struct ptp_clock_info *ptp,
struct timespec64 *ts,
struct ptp_system_timestamp *sts)
{
struct tsnep_adapter *adapter = container_of(ptp, struct tsnep_adapter,
ptp_clock_info);
u32 high_before;
u32 low;
u32 high;
u64 counter;

/* read high dword twice to detect overrun */
high = ioread32(adapter->addr + ECM_COUNTER_HIGH);
do {
ptp_read_system_prets(sts);
low = ioread32(adapter->addr + ECM_COUNTER_LOW);
ptp_read_system_postts(sts);
high_before = high;
high = ioread32(adapter->addr + ECM_COUNTER_HIGH);
} while (high != high_before);
counter = (((u64)high) << 32) | ((u64)low);

*ts = ns_to_timespec64(counter);

return 0;
}

int tsnep_ptp_init(struct tsnep_adapter *adapter)
{
int retval = 0;
Expand All @@ -192,6 +219,7 @@ int tsnep_ptp_init(struct tsnep_adapter *adapter)
adapter->ptp_clock_info.adjtime = tsnep_ptp_adjtime;
adapter->ptp_clock_info.gettimex64 = tsnep_ptp_gettimex64;
adapter->ptp_clock_info.settime64 = tsnep_ptp_settime64;
adapter->ptp_clock_info.getcyclesx64 = tsnep_ptp_getcyclesx64;

spin_lock_init(&adapter->ptp_lock);

Expand Down

0 comments on commit 0abb62b

Please sign in to comment.