162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Atlantic Network Driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2014-2019 aQuantia Corporation
562306a36Sopenharmony_ci * Copyright (C) 2019-2020 Marvell International Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/* File aq_ptp.c:
962306a36Sopenharmony_ci * Definition of functions for Linux PTP support.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/ptp_clock_kernel.h>
1362306a36Sopenharmony_ci#include <linux/ptp_classify.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include <linux/clocksource.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "aq_nic.h"
1862306a36Sopenharmony_ci#include "aq_ptp.h"
1962306a36Sopenharmony_ci#include "aq_ring.h"
2062306a36Sopenharmony_ci#include "aq_phy.h"
2162306a36Sopenharmony_ci#include "aq_filters.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define AQ_PTP_TX_TIMEOUT        (HZ *  10)
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define POLL_SYNC_TIMER_MS 15
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cienum ptp_speed_offsets {
3062306a36Sopenharmony_ci	ptp_offset_idx_10 = 0,
3162306a36Sopenharmony_ci	ptp_offset_idx_100,
3262306a36Sopenharmony_ci	ptp_offset_idx_1000,
3362306a36Sopenharmony_ci	ptp_offset_idx_2500,
3462306a36Sopenharmony_ci	ptp_offset_idx_5000,
3562306a36Sopenharmony_ci	ptp_offset_idx_10000,
3662306a36Sopenharmony_ci};
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistruct ptp_skb_ring {
3962306a36Sopenharmony_ci	struct sk_buff **buff;
4062306a36Sopenharmony_ci	spinlock_t lock;
4162306a36Sopenharmony_ci	unsigned int size;
4262306a36Sopenharmony_ci	unsigned int head;
4362306a36Sopenharmony_ci	unsigned int tail;
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistruct ptp_tx_timeout {
4762306a36Sopenharmony_ci	spinlock_t lock;
4862306a36Sopenharmony_ci	bool active;
4962306a36Sopenharmony_ci	unsigned long tx_start;
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistruct aq_ptp_s {
5362306a36Sopenharmony_ci	struct aq_nic_s *aq_nic;
5462306a36Sopenharmony_ci	struct hwtstamp_config hwtstamp_config;
5562306a36Sopenharmony_ci	spinlock_t ptp_lock;
5662306a36Sopenharmony_ci	spinlock_t ptp_ring_lock;
5762306a36Sopenharmony_ci	struct ptp_clock *ptp_clock;
5862306a36Sopenharmony_ci	struct ptp_clock_info ptp_info;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	atomic_t offset_egress;
6162306a36Sopenharmony_ci	atomic_t offset_ingress;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	struct aq_ring_param_s ptp_ring_param;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	struct ptp_tx_timeout ptp_tx_timeout;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	unsigned int idx_vector;
6862306a36Sopenharmony_ci	struct napi_struct napi;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	struct aq_ring_s ptp_tx;
7162306a36Sopenharmony_ci	struct aq_ring_s ptp_rx;
7262306a36Sopenharmony_ci	struct aq_ring_s hwts_rx;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	struct ptp_skb_ring skb_ring;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	struct aq_rx_filter_l3l4 udp_filter;
7762306a36Sopenharmony_ci	struct aq_rx_filter_l2 eth_type_filter;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	struct delayed_work poll_sync;
8062306a36Sopenharmony_ci	u32 poll_timeout_ms;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	bool extts_pin_enabled;
8362306a36Sopenharmony_ci	u64 last_sync1588_ts;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	bool a1_ptp;
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistruct ptp_tm_offset {
8962306a36Sopenharmony_ci	unsigned int mbps;
9062306a36Sopenharmony_ci	int egress;
9162306a36Sopenharmony_ci	int ingress;
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic struct ptp_tm_offset ptp_offset[6];
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_civoid aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic, unsigned int mbps)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
9962306a36Sopenharmony_ci	int i, egress, ingress;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (!aq_ptp)
10262306a36Sopenharmony_ci		return;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	egress = 0;
10562306a36Sopenharmony_ci	ingress = 0;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ptp_offset); i++) {
10862306a36Sopenharmony_ci		if (mbps == ptp_offset[i].mbps) {
10962306a36Sopenharmony_ci			egress = ptp_offset[i].egress;
11062306a36Sopenharmony_ci			ingress = ptp_offset[i].ingress;
11162306a36Sopenharmony_ci			break;
11262306a36Sopenharmony_ci		}
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	atomic_set(&aq_ptp->offset_egress, egress);
11662306a36Sopenharmony_ci	atomic_set(&aq_ptp->offset_ingress, ingress);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic int __aq_ptp_skb_put(struct ptp_skb_ring *ring, struct sk_buff *skb)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	unsigned int next_head = (ring->head + 1) % ring->size;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (next_head == ring->tail)
12462306a36Sopenharmony_ci		return -ENOMEM;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	ring->buff[ring->head] = skb_get(skb);
12762306a36Sopenharmony_ci	ring->head = next_head;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	return 0;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic int aq_ptp_skb_put(struct ptp_skb_ring *ring, struct sk_buff *skb)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	unsigned long flags;
13562306a36Sopenharmony_ci	int ret;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	spin_lock_irqsave(&ring->lock, flags);
13862306a36Sopenharmony_ci	ret = __aq_ptp_skb_put(ring, skb);
13962306a36Sopenharmony_ci	spin_unlock_irqrestore(&ring->lock, flags);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	return ret;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic struct sk_buff *__aq_ptp_skb_get(struct ptp_skb_ring *ring)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	struct sk_buff *skb;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	if (ring->tail == ring->head)
14962306a36Sopenharmony_ci		return NULL;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	skb = ring->buff[ring->tail];
15262306a36Sopenharmony_ci	ring->tail = (ring->tail + 1) % ring->size;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	return skb;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic struct sk_buff *aq_ptp_skb_get(struct ptp_skb_ring *ring)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	unsigned long flags;
16062306a36Sopenharmony_ci	struct sk_buff *skb;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	spin_lock_irqsave(&ring->lock, flags);
16362306a36Sopenharmony_ci	skb = __aq_ptp_skb_get(ring);
16462306a36Sopenharmony_ci	spin_unlock_irqrestore(&ring->lock, flags);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	return skb;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic unsigned int aq_ptp_skb_buf_len(struct ptp_skb_ring *ring)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	unsigned long flags;
17262306a36Sopenharmony_ci	unsigned int len;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	spin_lock_irqsave(&ring->lock, flags);
17562306a36Sopenharmony_ci	len = (ring->head >= ring->tail) ?
17662306a36Sopenharmony_ci	ring->head - ring->tail :
17762306a36Sopenharmony_ci	ring->size - ring->tail + ring->head;
17862306a36Sopenharmony_ci	spin_unlock_irqrestore(&ring->lock, flags);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return len;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int aq_ptp_skb_ring_init(struct ptp_skb_ring *ring, unsigned int size)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct sk_buff **buff = kmalloc(sizeof(*buff) * size, GFP_KERNEL);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (!buff)
18862306a36Sopenharmony_ci		return -ENOMEM;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	spin_lock_init(&ring->lock);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	ring->buff = buff;
19362306a36Sopenharmony_ci	ring->size = size;
19462306a36Sopenharmony_ci	ring->head = 0;
19562306a36Sopenharmony_ci	ring->tail = 0;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return 0;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic void aq_ptp_skb_ring_clean(struct ptp_skb_ring *ring)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct sk_buff *skb;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	while ((skb = aq_ptp_skb_get(ring)) != NULL)
20562306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void aq_ptp_skb_ring_release(struct ptp_skb_ring *ring)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	if (ring->buff) {
21162306a36Sopenharmony_ci		aq_ptp_skb_ring_clean(ring);
21262306a36Sopenharmony_ci		kfree(ring->buff);
21362306a36Sopenharmony_ci		ring->buff = NULL;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic void aq_ptp_tx_timeout_init(struct ptp_tx_timeout *timeout)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	spin_lock_init(&timeout->lock);
22062306a36Sopenharmony_ci	timeout->active = false;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic void aq_ptp_tx_timeout_start(struct aq_ptp_s *aq_ptp)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct ptp_tx_timeout *timeout = &aq_ptp->ptp_tx_timeout;
22662306a36Sopenharmony_ci	unsigned long flags;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	spin_lock_irqsave(&timeout->lock, flags);
22962306a36Sopenharmony_ci	timeout->active = true;
23062306a36Sopenharmony_ci	timeout->tx_start = jiffies;
23162306a36Sopenharmony_ci	spin_unlock_irqrestore(&timeout->lock, flags);
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic void aq_ptp_tx_timeout_update(struct aq_ptp_s *aq_ptp)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	if (!aq_ptp_skb_buf_len(&aq_ptp->skb_ring)) {
23762306a36Sopenharmony_ci		struct ptp_tx_timeout *timeout = &aq_ptp->ptp_tx_timeout;
23862306a36Sopenharmony_ci		unsigned long flags;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci		spin_lock_irqsave(&timeout->lock, flags);
24162306a36Sopenharmony_ci		timeout->active = false;
24262306a36Sopenharmony_ci		spin_unlock_irqrestore(&timeout->lock, flags);
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic void aq_ptp_tx_timeout_check(struct aq_ptp_s *aq_ptp)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct ptp_tx_timeout *timeout = &aq_ptp->ptp_tx_timeout;
24962306a36Sopenharmony_ci	unsigned long flags;
25062306a36Sopenharmony_ci	bool timeout_flag;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	timeout_flag = false;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	spin_lock_irqsave(&timeout->lock, flags);
25562306a36Sopenharmony_ci	if (timeout->active) {
25662306a36Sopenharmony_ci		timeout_flag = time_is_before_jiffies(timeout->tx_start +
25762306a36Sopenharmony_ci						      AQ_PTP_TX_TIMEOUT);
25862306a36Sopenharmony_ci		/* reset active flag if timeout detected */
25962306a36Sopenharmony_ci		if (timeout_flag)
26062306a36Sopenharmony_ci			timeout->active = false;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci	spin_unlock_irqrestore(&timeout->lock, flags);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	if (timeout_flag) {
26562306a36Sopenharmony_ci		aq_ptp_skb_ring_clean(&aq_ptp->skb_ring);
26662306a36Sopenharmony_ci		netdev_err(aq_ptp->aq_nic->ndev,
26762306a36Sopenharmony_ci			   "PTP Timeout. Clearing Tx Timestamp SKBs\n");
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/* aq_ptp_adjfine
27262306a36Sopenharmony_ci * @ptp: the ptp clock structure
27362306a36Sopenharmony_ci * @ppb: parts per billion adjustment from base
27462306a36Sopenharmony_ci *
27562306a36Sopenharmony_ci * adjust the frequency of the ptp cycle counter by the
27662306a36Sopenharmony_ci * indicated ppb from the base frequency.
27762306a36Sopenharmony_ci */
27862306a36Sopenharmony_cistatic int aq_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info);
28162306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	mutex_lock(&aq_nic->fwreq_mutex);
28462306a36Sopenharmony_ci	aq_nic->aq_hw_ops->hw_adj_clock_freq(aq_nic->aq_hw,
28562306a36Sopenharmony_ci					     scaled_ppm_to_ppb(scaled_ppm));
28662306a36Sopenharmony_ci	mutex_unlock(&aq_nic->fwreq_mutex);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	return 0;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/* aq_ptp_adjtime
29262306a36Sopenharmony_ci * @ptp: the ptp clock structure
29362306a36Sopenharmony_ci * @delta: offset to adjust the cycle counter by
29462306a36Sopenharmony_ci *
29562306a36Sopenharmony_ci * adjust the timer by resetting the timecounter structure.
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_cistatic int aq_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info);
30062306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
30162306a36Sopenharmony_ci	unsigned long flags;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	spin_lock_irqsave(&aq_ptp->ptp_lock, flags);
30462306a36Sopenharmony_ci	aq_nic->aq_hw_ops->hw_adj_sys_clock(aq_nic->aq_hw, delta);
30562306a36Sopenharmony_ci	spin_unlock_irqrestore(&aq_ptp->ptp_lock, flags);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	return 0;
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci/* aq_ptp_gettime
31162306a36Sopenharmony_ci * @ptp: the ptp clock structure
31262306a36Sopenharmony_ci * @ts: timespec structure to hold the current time value
31362306a36Sopenharmony_ci *
31462306a36Sopenharmony_ci * read the timecounter and return the correct value on ns,
31562306a36Sopenharmony_ci * after converting it into a struct timespec.
31662306a36Sopenharmony_ci */
31762306a36Sopenharmony_cistatic int aq_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info);
32062306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
32162306a36Sopenharmony_ci	unsigned long flags;
32262306a36Sopenharmony_ci	u64 ns;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	spin_lock_irqsave(&aq_ptp->ptp_lock, flags);
32562306a36Sopenharmony_ci	aq_nic->aq_hw_ops->hw_get_ptp_ts(aq_nic->aq_hw, &ns);
32662306a36Sopenharmony_ci	spin_unlock_irqrestore(&aq_ptp->ptp_lock, flags);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	*ts = ns_to_timespec64(ns);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return 0;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci/* aq_ptp_settime
33462306a36Sopenharmony_ci * @ptp: the ptp clock structure
33562306a36Sopenharmony_ci * @ts: the timespec containing the new time for the cycle counter
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci * reset the timecounter to use a new base value instead of the kernel
33862306a36Sopenharmony_ci * wall timer value.
33962306a36Sopenharmony_ci */
34062306a36Sopenharmony_cistatic int aq_ptp_settime(struct ptp_clock_info *ptp,
34162306a36Sopenharmony_ci			  const struct timespec64 *ts)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info);
34462306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
34562306a36Sopenharmony_ci	unsigned long flags;
34662306a36Sopenharmony_ci	u64 ns = timespec64_to_ns(ts);
34762306a36Sopenharmony_ci	u64 now;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	spin_lock_irqsave(&aq_ptp->ptp_lock, flags);
35062306a36Sopenharmony_ci	aq_nic->aq_hw_ops->hw_get_ptp_ts(aq_nic->aq_hw, &now);
35162306a36Sopenharmony_ci	aq_nic->aq_hw_ops->hw_adj_sys_clock(aq_nic->aq_hw, (s64)ns - (s64)now);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	spin_unlock_irqrestore(&aq_ptp->ptp_lock, flags);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	return 0;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic void aq_ptp_convert_to_hwtstamp(struct aq_ptp_s *aq_ptp,
35962306a36Sopenharmony_ci				       struct skb_shared_hwtstamps *hwtstamp,
36062306a36Sopenharmony_ci				       u64 timestamp)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	memset(hwtstamp, 0, sizeof(*hwtstamp));
36362306a36Sopenharmony_ci	hwtstamp->hwtstamp = ns_to_ktime(timestamp);
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic int aq_ptp_hw_pin_conf(struct aq_nic_s *aq_nic, u32 pin_index, u64 start,
36762306a36Sopenharmony_ci			      u64 period)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	if (period)
37062306a36Sopenharmony_ci		netdev_dbg(aq_nic->ndev,
37162306a36Sopenharmony_ci			   "Enable GPIO %d pulsing, start time %llu, period %u\n",
37262306a36Sopenharmony_ci			   pin_index, start, (u32)period);
37362306a36Sopenharmony_ci	else
37462306a36Sopenharmony_ci		netdev_dbg(aq_nic->ndev,
37562306a36Sopenharmony_ci			   "Disable GPIO %d pulsing, start time %llu, period %u\n",
37662306a36Sopenharmony_ci			   pin_index, start, (u32)period);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/* Notify hardware of request to being sending pulses.
37962306a36Sopenharmony_ci	 * If period is ZERO then pulsen is disabled.
38062306a36Sopenharmony_ci	 */
38162306a36Sopenharmony_ci	mutex_lock(&aq_nic->fwreq_mutex);
38262306a36Sopenharmony_ci	aq_nic->aq_hw_ops->hw_gpio_pulse(aq_nic->aq_hw, pin_index,
38362306a36Sopenharmony_ci					 start, (u32)period);
38462306a36Sopenharmony_ci	mutex_unlock(&aq_nic->fwreq_mutex);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	return 0;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic int aq_ptp_perout_pin_configure(struct ptp_clock_info *ptp,
39062306a36Sopenharmony_ci				       struct ptp_clock_request *rq, int on)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info);
39362306a36Sopenharmony_ci	struct ptp_clock_time *t = &rq->perout.period;
39462306a36Sopenharmony_ci	struct ptp_clock_time *s = &rq->perout.start;
39562306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
39662306a36Sopenharmony_ci	u64 start, period;
39762306a36Sopenharmony_ci	u32 pin_index = rq->perout.index;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* verify the request channel is there */
40062306a36Sopenharmony_ci	if (pin_index >= ptp->n_per_out)
40162306a36Sopenharmony_ci		return -EINVAL;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	/* we cannot support periods greater
40462306a36Sopenharmony_ci	 * than 4 seconds due to reg limit
40562306a36Sopenharmony_ci	 */
40662306a36Sopenharmony_ci	if (t->sec > 4 || t->sec < 0)
40762306a36Sopenharmony_ci		return -ERANGE;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/* convert to unsigned 64b ns,
41062306a36Sopenharmony_ci	 * verify we can put it in a 32b register
41162306a36Sopenharmony_ci	 */
41262306a36Sopenharmony_ci	period = on ? t->sec * NSEC_PER_SEC + t->nsec : 0;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* verify the value is in range supported by hardware */
41562306a36Sopenharmony_ci	if (period > U32_MAX)
41662306a36Sopenharmony_ci		return -ERANGE;
41762306a36Sopenharmony_ci	/* convert to unsigned 64b ns */
41862306a36Sopenharmony_ci	/* TODO convert to AQ time */
41962306a36Sopenharmony_ci	start = on ? s->sec * NSEC_PER_SEC + s->nsec : 0;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	aq_ptp_hw_pin_conf(aq_nic, pin_index, start, period);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	return 0;
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic int aq_ptp_pps_pin_configure(struct ptp_clock_info *ptp,
42762306a36Sopenharmony_ci				    struct ptp_clock_request *rq, int on)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info);
43062306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
43162306a36Sopenharmony_ci	u64 start, period;
43262306a36Sopenharmony_ci	u32 pin_index = 0;
43362306a36Sopenharmony_ci	u32 rest = 0;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	/* verify the request channel is there */
43662306a36Sopenharmony_ci	if (pin_index >= ptp->n_per_out)
43762306a36Sopenharmony_ci		return -EINVAL;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	aq_nic->aq_hw_ops->hw_get_ptp_ts(aq_nic->aq_hw, &start);
44062306a36Sopenharmony_ci	div_u64_rem(start, NSEC_PER_SEC, &rest);
44162306a36Sopenharmony_ci	period = on ? NSEC_PER_SEC : 0; /* PPS - pulse per second */
44262306a36Sopenharmony_ci	start = on ? start - rest + NSEC_PER_SEC *
44362306a36Sopenharmony_ci		(rest > 990000000LL ? 2 : 1) : 0;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	aq_ptp_hw_pin_conf(aq_nic, pin_index, start, period);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	return 0;
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void aq_ptp_extts_pin_ctrl(struct aq_ptp_s *aq_ptp)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
45362306a36Sopenharmony_ci	u32 enable = aq_ptp->extts_pin_enabled;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (aq_nic->aq_hw_ops->hw_extts_gpio_enable)
45662306a36Sopenharmony_ci		aq_nic->aq_hw_ops->hw_extts_gpio_enable(aq_nic->aq_hw, 0,
45762306a36Sopenharmony_ci							enable);
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic int aq_ptp_extts_pin_configure(struct ptp_clock_info *ptp,
46162306a36Sopenharmony_ci				      struct ptp_clock_request *rq, int on)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	u32 pin_index = rq->extts.index;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (pin_index >= ptp->n_ext_ts)
46862306a36Sopenharmony_ci		return -EINVAL;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	aq_ptp->extts_pin_enabled = !!on;
47162306a36Sopenharmony_ci	if (on) {
47262306a36Sopenharmony_ci		aq_ptp->poll_timeout_ms = POLL_SYNC_TIMER_MS;
47362306a36Sopenharmony_ci		cancel_delayed_work_sync(&aq_ptp->poll_sync);
47462306a36Sopenharmony_ci		schedule_delayed_work(&aq_ptp->poll_sync,
47562306a36Sopenharmony_ci				      msecs_to_jiffies(aq_ptp->poll_timeout_ms));
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	aq_ptp_extts_pin_ctrl(aq_ptp);
47962306a36Sopenharmony_ci	return 0;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci/* aq_ptp_gpio_feature_enable
48362306a36Sopenharmony_ci * @ptp: the ptp clock structure
48462306a36Sopenharmony_ci * @rq: the requested feature to change
48562306a36Sopenharmony_ci * @on: whether to enable or disable the feature
48662306a36Sopenharmony_ci */
48762306a36Sopenharmony_cistatic int aq_ptp_gpio_feature_enable(struct ptp_clock_info *ptp,
48862306a36Sopenharmony_ci				      struct ptp_clock_request *rq, int on)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	switch (rq->type) {
49162306a36Sopenharmony_ci	case PTP_CLK_REQ_EXTTS:
49262306a36Sopenharmony_ci		return aq_ptp_extts_pin_configure(ptp, rq, on);
49362306a36Sopenharmony_ci	case PTP_CLK_REQ_PEROUT:
49462306a36Sopenharmony_ci		return aq_ptp_perout_pin_configure(ptp, rq, on);
49562306a36Sopenharmony_ci	case PTP_CLK_REQ_PPS:
49662306a36Sopenharmony_ci		return aq_ptp_pps_pin_configure(ptp, rq, on);
49762306a36Sopenharmony_ci	default:
49862306a36Sopenharmony_ci		return -EOPNOTSUPP;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return 0;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci/* aq_ptp_verify
50562306a36Sopenharmony_ci * @ptp: the ptp clock structure
50662306a36Sopenharmony_ci * @pin: index of the pin in question
50762306a36Sopenharmony_ci * @func: the desired function to use
50862306a36Sopenharmony_ci * @chan: the function channel index to use
50962306a36Sopenharmony_ci */
51062306a36Sopenharmony_cistatic int aq_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
51162306a36Sopenharmony_ci			 enum ptp_pin_function func, unsigned int chan)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	/* verify the requested pin is there */
51462306a36Sopenharmony_ci	if (!ptp->pin_config || pin >= ptp->n_pins)
51562306a36Sopenharmony_ci		return -EINVAL;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/* enforce locked channels, no changing them */
51862306a36Sopenharmony_ci	if (chan != ptp->pin_config[pin].chan)
51962306a36Sopenharmony_ci		return -EINVAL;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/* we want to keep the functions locked as well */
52262306a36Sopenharmony_ci	if (func != ptp->pin_config[pin].func)
52362306a36Sopenharmony_ci		return -EINVAL;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	return 0;
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci/* aq_ptp_tx_hwtstamp - utility function which checks for TX time stamp
52962306a36Sopenharmony_ci * @adapter: the private adapter struct
53062306a36Sopenharmony_ci *
53162306a36Sopenharmony_ci * if the timestamp is valid, we convert it into the timecounter ns
53262306a36Sopenharmony_ci * value, then store that result into the hwtstamps structure which
53362306a36Sopenharmony_ci * is passed up the network stack
53462306a36Sopenharmony_ci */
53562306a36Sopenharmony_civoid aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
53862306a36Sopenharmony_ci	struct sk_buff *skb = aq_ptp_skb_get(&aq_ptp->skb_ring);
53962306a36Sopenharmony_ci	struct skb_shared_hwtstamps hwtstamp;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	if (!skb) {
54262306a36Sopenharmony_ci		netdev_err(aq_nic->ndev, "have timestamp but tx_queues empty\n");
54362306a36Sopenharmony_ci		return;
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	timestamp += atomic_read(&aq_ptp->offset_egress);
54762306a36Sopenharmony_ci	aq_ptp_convert_to_hwtstamp(aq_ptp, &hwtstamp, timestamp);
54862306a36Sopenharmony_ci	skb_tstamp_tx(skb, &hwtstamp);
54962306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	aq_ptp_tx_timeout_update(aq_ptp);
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci/* aq_ptp_rx_hwtstamp - utility function which checks for RX time stamp
55562306a36Sopenharmony_ci * @adapter: pointer to adapter struct
55662306a36Sopenharmony_ci * @shhwtstamps: particular skb_shared_hwtstamps to save timestamp
55762306a36Sopenharmony_ci *
55862306a36Sopenharmony_ci * if the timestamp is valid, we convert it into the timecounter ns
55962306a36Sopenharmony_ci * value, then store that result into the hwtstamps structure which
56062306a36Sopenharmony_ci * is passed up the network stack
56162306a36Sopenharmony_ci */
56262306a36Sopenharmony_cistatic void aq_ptp_rx_hwtstamp(struct aq_ptp_s *aq_ptp, struct skb_shared_hwtstamps *shhwtstamps,
56362306a36Sopenharmony_ci			       u64 timestamp)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	timestamp -= atomic_read(&aq_ptp->offset_ingress);
56662306a36Sopenharmony_ci	aq_ptp_convert_to_hwtstamp(aq_ptp, shhwtstamps, timestamp);
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_civoid aq_ptp_hwtstamp_config_get(struct aq_ptp_s *aq_ptp,
57062306a36Sopenharmony_ci				struct hwtstamp_config *config)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	*config = aq_ptp->hwtstamp_config;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic void aq_ptp_prepare_filters(struct aq_ptp_s *aq_ptp)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	aq_ptp->udp_filter.cmd = HW_ATL_RX_ENABLE_FLTR_L3L4 |
57862306a36Sopenharmony_ci			       HW_ATL_RX_ENABLE_CMP_PROT_L4 |
57962306a36Sopenharmony_ci			       HW_ATL_RX_UDP |
58062306a36Sopenharmony_ci			       HW_ATL_RX_ENABLE_CMP_DEST_PORT_L4 |
58162306a36Sopenharmony_ci			       HW_ATL_RX_HOST << HW_ATL_RX_ACTION_FL3F4_SHIFT |
58262306a36Sopenharmony_ci			       HW_ATL_RX_ENABLE_QUEUE_L3L4 |
58362306a36Sopenharmony_ci			       aq_ptp->ptp_rx.idx << HW_ATL_RX_QUEUE_FL3L4_SHIFT;
58462306a36Sopenharmony_ci	aq_ptp->udp_filter.p_dst = PTP_EV_PORT;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	aq_ptp->eth_type_filter.ethertype = ETH_P_1588;
58762306a36Sopenharmony_ci	aq_ptp->eth_type_filter.queue = aq_ptp->ptp_rx.idx;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ciint aq_ptp_hwtstamp_config_set(struct aq_ptp_s *aq_ptp,
59162306a36Sopenharmony_ci			       struct hwtstamp_config *config)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
59462306a36Sopenharmony_ci	const struct aq_hw_ops *hw_ops;
59562306a36Sopenharmony_ci	int err = 0;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	hw_ops = aq_nic->aq_hw_ops;
59862306a36Sopenharmony_ci	if (config->tx_type == HWTSTAMP_TX_ON ||
59962306a36Sopenharmony_ci	    config->rx_filter == HWTSTAMP_FILTER_PTP_V2_EVENT) {
60062306a36Sopenharmony_ci		aq_ptp_prepare_filters(aq_ptp);
60162306a36Sopenharmony_ci		if (hw_ops->hw_filter_l3l4_set) {
60262306a36Sopenharmony_ci			err = hw_ops->hw_filter_l3l4_set(aq_nic->aq_hw,
60362306a36Sopenharmony_ci							 &aq_ptp->udp_filter);
60462306a36Sopenharmony_ci		}
60562306a36Sopenharmony_ci		if (!err && hw_ops->hw_filter_l2_set) {
60662306a36Sopenharmony_ci			err = hw_ops->hw_filter_l2_set(aq_nic->aq_hw,
60762306a36Sopenharmony_ci						       &aq_ptp->eth_type_filter);
60862306a36Sopenharmony_ci		}
60962306a36Sopenharmony_ci		aq_utils_obj_set(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP);
61062306a36Sopenharmony_ci	} else {
61162306a36Sopenharmony_ci		aq_ptp->udp_filter.cmd &= ~HW_ATL_RX_ENABLE_FLTR_L3L4;
61262306a36Sopenharmony_ci		if (hw_ops->hw_filter_l3l4_set) {
61362306a36Sopenharmony_ci			err = hw_ops->hw_filter_l3l4_set(aq_nic->aq_hw,
61462306a36Sopenharmony_ci							 &aq_ptp->udp_filter);
61562306a36Sopenharmony_ci		}
61662306a36Sopenharmony_ci		if (!err && hw_ops->hw_filter_l2_clear) {
61762306a36Sopenharmony_ci			err = hw_ops->hw_filter_l2_clear(aq_nic->aq_hw,
61862306a36Sopenharmony_ci							&aq_ptp->eth_type_filter);
61962306a36Sopenharmony_ci		}
62062306a36Sopenharmony_ci		aq_utils_obj_clear(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP);
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	if (err)
62462306a36Sopenharmony_ci		return -EREMOTEIO;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	aq_ptp->hwtstamp_config = *config;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	return 0;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cibool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if (!aq_ptp)
63662306a36Sopenharmony_ci		return false;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	return &aq_ptp->ptp_tx == ring ||
63962306a36Sopenharmony_ci	       &aq_ptp->ptp_rx == ring || &aq_ptp->hwts_rx == ring;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ciu16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, struct skb_shared_hwtstamps *shhwtstamps, u8 *p,
64362306a36Sopenharmony_ci		      unsigned int len)
64462306a36Sopenharmony_ci{
64562306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
64662306a36Sopenharmony_ci	u64 timestamp = 0;
64762306a36Sopenharmony_ci	u16 ret = aq_nic->aq_hw_ops->rx_extract_ts(aq_nic->aq_hw,
64862306a36Sopenharmony_ci						   p, len, &timestamp);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	if (ret > 0)
65162306a36Sopenharmony_ci		aq_ptp_rx_hwtstamp(aq_ptp, shhwtstamps, timestamp);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	return ret;
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic int aq_ptp_poll(struct napi_struct *napi, int budget)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = container_of(napi, struct aq_ptp_s, napi);
65962306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
66062306a36Sopenharmony_ci	bool was_cleaned = false;
66162306a36Sopenharmony_ci	int work_done = 0;
66262306a36Sopenharmony_ci	int err;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	/* Processing PTP TX traffic */
66562306a36Sopenharmony_ci	err = aq_nic->aq_hw_ops->hw_ring_tx_head_update(aq_nic->aq_hw,
66662306a36Sopenharmony_ci							&aq_ptp->ptp_tx);
66762306a36Sopenharmony_ci	if (err < 0)
66862306a36Sopenharmony_ci		goto err_exit;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	if (aq_ptp->ptp_tx.sw_head != aq_ptp->ptp_tx.hw_head) {
67162306a36Sopenharmony_ci		aq_ring_tx_clean(&aq_ptp->ptp_tx);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci		was_cleaned = true;
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	/* Processing HW_TIMESTAMP RX traffic */
67762306a36Sopenharmony_ci	err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_receive(aq_nic->aq_hw,
67862306a36Sopenharmony_ci							 &aq_ptp->hwts_rx);
67962306a36Sopenharmony_ci	if (err < 0)
68062306a36Sopenharmony_ci		goto err_exit;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	if (aq_ptp->hwts_rx.sw_head != aq_ptp->hwts_rx.hw_head) {
68362306a36Sopenharmony_ci		aq_ring_hwts_rx_clean(&aq_ptp->hwts_rx, aq_nic);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci		err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_fill(aq_nic->aq_hw,
68662306a36Sopenharmony_ci							      &aq_ptp->hwts_rx);
68762306a36Sopenharmony_ci		if (err < 0)
68862306a36Sopenharmony_ci			goto err_exit;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci		was_cleaned = true;
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	/* Processing PTP RX traffic */
69462306a36Sopenharmony_ci	err = aq_nic->aq_hw_ops->hw_ring_rx_receive(aq_nic->aq_hw,
69562306a36Sopenharmony_ci						    &aq_ptp->ptp_rx);
69662306a36Sopenharmony_ci	if (err < 0)
69762306a36Sopenharmony_ci		goto err_exit;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	if (aq_ptp->ptp_rx.sw_head != aq_ptp->ptp_rx.hw_head) {
70062306a36Sopenharmony_ci		unsigned int sw_tail_old;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci		err = aq_ring_rx_clean(&aq_ptp->ptp_rx, napi, &work_done, budget);
70362306a36Sopenharmony_ci		if (err < 0)
70462306a36Sopenharmony_ci			goto err_exit;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci		sw_tail_old = aq_ptp->ptp_rx.sw_tail;
70762306a36Sopenharmony_ci		err = aq_ring_rx_fill(&aq_ptp->ptp_rx);
70862306a36Sopenharmony_ci		if (err < 0)
70962306a36Sopenharmony_ci			goto err_exit;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci		err = aq_nic->aq_hw_ops->hw_ring_rx_fill(aq_nic->aq_hw,
71262306a36Sopenharmony_ci							 &aq_ptp->ptp_rx,
71362306a36Sopenharmony_ci							 sw_tail_old);
71462306a36Sopenharmony_ci		if (err < 0)
71562306a36Sopenharmony_ci			goto err_exit;
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	if (was_cleaned)
71962306a36Sopenharmony_ci		work_done = budget;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	if (work_done < budget) {
72262306a36Sopenharmony_ci		napi_complete_done(napi, work_done);
72362306a36Sopenharmony_ci		aq_nic->aq_hw_ops->hw_irq_enable(aq_nic->aq_hw,
72462306a36Sopenharmony_ci					BIT_ULL(aq_ptp->ptp_ring_param.vec_idx));
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cierr_exit:
72862306a36Sopenharmony_ci	return work_done;
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic irqreturn_t aq_ptp_isr(int irq, void *private)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = private;
73462306a36Sopenharmony_ci	int err = 0;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (!aq_ptp) {
73762306a36Sopenharmony_ci		err = -EINVAL;
73862306a36Sopenharmony_ci		goto err_exit;
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci	napi_schedule(&aq_ptp->napi);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cierr_exit:
74362306a36Sopenharmony_ci	return err >= 0 ? IRQ_HANDLED : IRQ_NONE;
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ciint aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
74962306a36Sopenharmony_ci	struct aq_ring_s *ring = &aq_ptp->ptp_tx;
75062306a36Sopenharmony_ci	unsigned long irq_flags;
75162306a36Sopenharmony_ci	int err = NETDEV_TX_OK;
75262306a36Sopenharmony_ci	unsigned int frags;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	if (skb->len <= 0) {
75562306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
75662306a36Sopenharmony_ci		goto err_exit;
75762306a36Sopenharmony_ci	}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	frags = skb_shinfo(skb)->nr_frags + 1;
76062306a36Sopenharmony_ci	/* Frags cannot be bigger 16KB
76162306a36Sopenharmony_ci	 * because PTP usually works
76262306a36Sopenharmony_ci	 * without Jumbo even in a background
76362306a36Sopenharmony_ci	 */
76462306a36Sopenharmony_ci	if (frags > AQ_CFG_SKB_FRAGS_MAX || frags > aq_ring_avail_dx(ring)) {
76562306a36Sopenharmony_ci		/* Drop packet because it doesn't make sence to delay it */
76662306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
76762306a36Sopenharmony_ci		goto err_exit;
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	err = aq_ptp_skb_put(&aq_ptp->skb_ring, skb);
77162306a36Sopenharmony_ci	if (err) {
77262306a36Sopenharmony_ci		netdev_err(aq_nic->ndev, "SKB Ring is overflow (%u)!\n",
77362306a36Sopenharmony_ci			   ring->size);
77462306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci	skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
77762306a36Sopenharmony_ci	aq_ptp_tx_timeout_start(aq_ptp);
77862306a36Sopenharmony_ci	skb_tx_timestamp(skb);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	spin_lock_irqsave(&aq_nic->aq_ptp->ptp_ring_lock, irq_flags);
78162306a36Sopenharmony_ci	frags = aq_nic_map_skb(aq_nic, skb, ring);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	if (likely(frags)) {
78462306a36Sopenharmony_ci		err = aq_nic->aq_hw_ops->hw_ring_tx_xmit(aq_nic->aq_hw,
78562306a36Sopenharmony_ci						       ring, frags);
78662306a36Sopenharmony_ci		if (err >= 0) {
78762306a36Sopenharmony_ci			u64_stats_update_begin(&ring->stats.tx.syncp);
78862306a36Sopenharmony_ci			++ring->stats.tx.packets;
78962306a36Sopenharmony_ci			ring->stats.tx.bytes += skb->len;
79062306a36Sopenharmony_ci			u64_stats_update_end(&ring->stats.tx.syncp);
79162306a36Sopenharmony_ci		}
79262306a36Sopenharmony_ci	} else {
79362306a36Sopenharmony_ci		err = NETDEV_TX_BUSY;
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci	spin_unlock_irqrestore(&aq_nic->aq_ptp->ptp_ring_lock, irq_flags);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cierr_exit:
79862306a36Sopenharmony_ci	return err;
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_civoid aq_ptp_service_task(struct aq_nic_s *aq_nic)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	if (!aq_ptp)
80662306a36Sopenharmony_ci		return;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	aq_ptp_tx_timeout_check(aq_ptp);
80962306a36Sopenharmony_ci}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ciint aq_ptp_irq_alloc(struct aq_nic_s *aq_nic)
81262306a36Sopenharmony_ci{
81362306a36Sopenharmony_ci	struct pci_dev *pdev = aq_nic->pdev;
81462306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
81562306a36Sopenharmony_ci	int err = 0;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	if (!aq_ptp)
81862306a36Sopenharmony_ci		return 0;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	if (pdev->msix_enabled || pdev->msi_enabled) {
82162306a36Sopenharmony_ci		err = request_irq(pci_irq_vector(pdev, aq_ptp->idx_vector),
82262306a36Sopenharmony_ci				  aq_ptp_isr, 0, aq_nic->ndev->name, aq_ptp);
82362306a36Sopenharmony_ci	} else {
82462306a36Sopenharmony_ci		err = -EINVAL;
82562306a36Sopenharmony_ci		goto err_exit;
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_cierr_exit:
82962306a36Sopenharmony_ci	return err;
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_civoid aq_ptp_irq_free(struct aq_nic_s *aq_nic)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
83562306a36Sopenharmony_ci	struct pci_dev *pdev = aq_nic->pdev;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	if (!aq_ptp)
83862306a36Sopenharmony_ci		return;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	free_irq(pci_irq_vector(pdev, aq_ptp->idx_vector), aq_ptp);
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ciint aq_ptp_ring_init(struct aq_nic_s *aq_nic)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
84662306a36Sopenharmony_ci	int err = 0;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (!aq_ptp)
84962306a36Sopenharmony_ci		return 0;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	err = aq_ring_init(&aq_ptp->ptp_tx, ATL_RING_TX);
85262306a36Sopenharmony_ci	if (err < 0)
85362306a36Sopenharmony_ci		goto err_exit;
85462306a36Sopenharmony_ci	err = aq_nic->aq_hw_ops->hw_ring_tx_init(aq_nic->aq_hw,
85562306a36Sopenharmony_ci						 &aq_ptp->ptp_tx,
85662306a36Sopenharmony_ci						 &aq_ptp->ptp_ring_param);
85762306a36Sopenharmony_ci	if (err < 0)
85862306a36Sopenharmony_ci		goto err_exit;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	err = aq_ring_init(&aq_ptp->ptp_rx, ATL_RING_RX);
86162306a36Sopenharmony_ci	if (err < 0)
86262306a36Sopenharmony_ci		goto err_exit;
86362306a36Sopenharmony_ci	err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw,
86462306a36Sopenharmony_ci						 &aq_ptp->ptp_rx,
86562306a36Sopenharmony_ci						 &aq_ptp->ptp_ring_param);
86662306a36Sopenharmony_ci	if (err < 0)
86762306a36Sopenharmony_ci		goto err_exit;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	err = aq_ring_rx_fill(&aq_ptp->ptp_rx);
87062306a36Sopenharmony_ci	if (err < 0)
87162306a36Sopenharmony_ci		goto err_rx_free;
87262306a36Sopenharmony_ci	err = aq_nic->aq_hw_ops->hw_ring_rx_fill(aq_nic->aq_hw,
87362306a36Sopenharmony_ci						 &aq_ptp->ptp_rx,
87462306a36Sopenharmony_ci						 0U);
87562306a36Sopenharmony_ci	if (err < 0)
87662306a36Sopenharmony_ci		goto err_rx_free;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	err = aq_ring_init(&aq_ptp->hwts_rx, ATL_RING_RX);
87962306a36Sopenharmony_ci	if (err < 0)
88062306a36Sopenharmony_ci		goto err_rx_free;
88162306a36Sopenharmony_ci	err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw,
88262306a36Sopenharmony_ci						 &aq_ptp->hwts_rx,
88362306a36Sopenharmony_ci						 &aq_ptp->ptp_ring_param);
88462306a36Sopenharmony_ci	if (err < 0)
88562306a36Sopenharmony_ci		goto err_exit;
88662306a36Sopenharmony_ci	err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_fill(aq_nic->aq_hw,
88762306a36Sopenharmony_ci						      &aq_ptp->hwts_rx);
88862306a36Sopenharmony_ci	if (err < 0)
88962306a36Sopenharmony_ci		goto err_exit;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	return err;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_cierr_rx_free:
89462306a36Sopenharmony_ci	aq_ring_rx_deinit(&aq_ptp->ptp_rx);
89562306a36Sopenharmony_cierr_exit:
89662306a36Sopenharmony_ci	return err;
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ciint aq_ptp_ring_start(struct aq_nic_s *aq_nic)
90062306a36Sopenharmony_ci{
90162306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
90262306a36Sopenharmony_ci	int err = 0;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	if (!aq_ptp)
90562306a36Sopenharmony_ci		return 0;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	err = aq_nic->aq_hw_ops->hw_ring_tx_start(aq_nic->aq_hw, &aq_ptp->ptp_tx);
90862306a36Sopenharmony_ci	if (err < 0)
90962306a36Sopenharmony_ci		goto err_exit;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw, &aq_ptp->ptp_rx);
91262306a36Sopenharmony_ci	if (err < 0)
91362306a36Sopenharmony_ci		goto err_exit;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw,
91662306a36Sopenharmony_ci						  &aq_ptp->hwts_rx);
91762306a36Sopenharmony_ci	if (err < 0)
91862306a36Sopenharmony_ci		goto err_exit;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	napi_enable(&aq_ptp->napi);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cierr_exit:
92362306a36Sopenharmony_ci	return err;
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_civoid aq_ptp_ring_stop(struct aq_nic_s *aq_nic)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	if (!aq_ptp)
93162306a36Sopenharmony_ci		return;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	aq_nic->aq_hw_ops->hw_ring_tx_stop(aq_nic->aq_hw, &aq_ptp->ptp_tx);
93462306a36Sopenharmony_ci	aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->ptp_rx);
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->hwts_rx);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	napi_disable(&aq_ptp->napi);
93962306a36Sopenharmony_ci}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_civoid aq_ptp_ring_deinit(struct aq_nic_s *aq_nic)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	if (!aq_ptp || !aq_ptp->ptp_tx.aq_nic || !aq_ptp->ptp_rx.aq_nic)
94662306a36Sopenharmony_ci		return;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	aq_ring_tx_clean(&aq_ptp->ptp_tx);
94962306a36Sopenharmony_ci	aq_ring_rx_deinit(&aq_ptp->ptp_rx);
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ciint aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
95562306a36Sopenharmony_ci	unsigned int tx_ring_idx, rx_ring_idx;
95662306a36Sopenharmony_ci	int err;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	if (!aq_ptp)
95962306a36Sopenharmony_ci		return 0;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	tx_ring_idx = aq_ptp_ring_idx(aq_nic->aq_nic_cfg.tc_mode);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	err = aq_ring_tx_alloc(&aq_ptp->ptp_tx, aq_nic,
96462306a36Sopenharmony_ci			       tx_ring_idx, &aq_nic->aq_nic_cfg);
96562306a36Sopenharmony_ci	if (err)
96662306a36Sopenharmony_ci		goto err_exit;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	rx_ring_idx = aq_ptp_ring_idx(aq_nic->aq_nic_cfg.tc_mode);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	err = aq_ring_rx_alloc(&aq_ptp->ptp_rx, aq_nic,
97162306a36Sopenharmony_ci			       rx_ring_idx, &aq_nic->aq_nic_cfg);
97262306a36Sopenharmony_ci	if (err)
97362306a36Sopenharmony_ci		goto err_exit_ptp_tx;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	err = aq_ring_hwts_rx_alloc(&aq_ptp->hwts_rx, aq_nic, PTP_HWST_RING_IDX,
97662306a36Sopenharmony_ci				    aq_nic->aq_nic_cfg.rxds,
97762306a36Sopenharmony_ci				    aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size);
97862306a36Sopenharmony_ci	if (err)
97962306a36Sopenharmony_ci		goto err_exit_ptp_rx;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	err = aq_ptp_skb_ring_init(&aq_ptp->skb_ring, aq_nic->aq_nic_cfg.rxds);
98262306a36Sopenharmony_ci	if (err != 0) {
98362306a36Sopenharmony_ci		err = -ENOMEM;
98462306a36Sopenharmony_ci		goto err_exit_hwts_rx;
98562306a36Sopenharmony_ci	}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	aq_ptp->ptp_ring_param.vec_idx = aq_ptp->idx_vector;
98862306a36Sopenharmony_ci	aq_ptp->ptp_ring_param.cpu = aq_ptp->ptp_ring_param.vec_idx +
98962306a36Sopenharmony_ci			aq_nic_get_cfg(aq_nic)->aq_rss.base_cpu_number;
99062306a36Sopenharmony_ci	cpumask_set_cpu(aq_ptp->ptp_ring_param.cpu,
99162306a36Sopenharmony_ci			&aq_ptp->ptp_ring_param.affinity_mask);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	return 0;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_cierr_exit_hwts_rx:
99662306a36Sopenharmony_ci	aq_ring_hwts_rx_free(&aq_ptp->hwts_rx);
99762306a36Sopenharmony_cierr_exit_ptp_rx:
99862306a36Sopenharmony_ci	aq_ring_free(&aq_ptp->ptp_rx);
99962306a36Sopenharmony_cierr_exit_ptp_tx:
100062306a36Sopenharmony_ci	aq_ring_free(&aq_ptp->ptp_tx);
100162306a36Sopenharmony_cierr_exit:
100262306a36Sopenharmony_ci	return err;
100362306a36Sopenharmony_ci}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_civoid aq_ptp_ring_free(struct aq_nic_s *aq_nic)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	if (!aq_ptp)
101062306a36Sopenharmony_ci		return;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	aq_ring_free(&aq_ptp->ptp_tx);
101362306a36Sopenharmony_ci	aq_ring_free(&aq_ptp->ptp_rx);
101462306a36Sopenharmony_ci	aq_ring_hwts_rx_free(&aq_ptp->hwts_rx);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	aq_ptp_skb_ring_release(&aq_ptp->skb_ring);
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci#define MAX_PTP_GPIO_COUNT 4
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_cistatic struct ptp_clock_info aq_ptp_clock = {
102262306a36Sopenharmony_ci	.owner		= THIS_MODULE,
102362306a36Sopenharmony_ci	.name		= "atlantic ptp",
102462306a36Sopenharmony_ci	.max_adj	= 999999999,
102562306a36Sopenharmony_ci	.n_ext_ts	= 0,
102662306a36Sopenharmony_ci	.pps		= 0,
102762306a36Sopenharmony_ci	.adjfine	= aq_ptp_adjfine,
102862306a36Sopenharmony_ci	.adjtime	= aq_ptp_adjtime,
102962306a36Sopenharmony_ci	.gettime64	= aq_ptp_gettime,
103062306a36Sopenharmony_ci	.settime64	= aq_ptp_settime,
103162306a36Sopenharmony_ci	.n_per_out	= 0,
103262306a36Sopenharmony_ci	.enable		= aq_ptp_gpio_feature_enable,
103362306a36Sopenharmony_ci	.n_pins		= 0,
103462306a36Sopenharmony_ci	.verify		= aq_ptp_verify,
103562306a36Sopenharmony_ci	.pin_config	= NULL,
103662306a36Sopenharmony_ci};
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci#define ptp_offset_init(__idx, __mbps, __egress, __ingress)   do { \
103962306a36Sopenharmony_ci		ptp_offset[__idx].mbps = (__mbps); \
104062306a36Sopenharmony_ci		ptp_offset[__idx].egress = (__egress); \
104162306a36Sopenharmony_ci		ptp_offset[__idx].ingress = (__ingress); } \
104262306a36Sopenharmony_ci		while (0)
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_cistatic void aq_ptp_offset_init_from_fw(const struct hw_atl_ptp_offset *offsets)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	int i;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	/* Load offsets for PTP */
104962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ptp_offset); i++) {
105062306a36Sopenharmony_ci		switch (i) {
105162306a36Sopenharmony_ci		/* 100M */
105262306a36Sopenharmony_ci		case ptp_offset_idx_100:
105362306a36Sopenharmony_ci			ptp_offset_init(i, 100,
105462306a36Sopenharmony_ci					offsets->egress_100,
105562306a36Sopenharmony_ci					offsets->ingress_100);
105662306a36Sopenharmony_ci			break;
105762306a36Sopenharmony_ci		/* 1G */
105862306a36Sopenharmony_ci		case ptp_offset_idx_1000:
105962306a36Sopenharmony_ci			ptp_offset_init(i, 1000,
106062306a36Sopenharmony_ci					offsets->egress_1000,
106162306a36Sopenharmony_ci					offsets->ingress_1000);
106262306a36Sopenharmony_ci			break;
106362306a36Sopenharmony_ci		/* 2.5G */
106462306a36Sopenharmony_ci		case ptp_offset_idx_2500:
106562306a36Sopenharmony_ci			ptp_offset_init(i, 2500,
106662306a36Sopenharmony_ci					offsets->egress_2500,
106762306a36Sopenharmony_ci					offsets->ingress_2500);
106862306a36Sopenharmony_ci			break;
106962306a36Sopenharmony_ci		/* 5G */
107062306a36Sopenharmony_ci		case ptp_offset_idx_5000:
107162306a36Sopenharmony_ci			ptp_offset_init(i, 5000,
107262306a36Sopenharmony_ci					offsets->egress_5000,
107362306a36Sopenharmony_ci					offsets->ingress_5000);
107462306a36Sopenharmony_ci			break;
107562306a36Sopenharmony_ci		/* 10G */
107662306a36Sopenharmony_ci		case ptp_offset_idx_10000:
107762306a36Sopenharmony_ci			ptp_offset_init(i, 10000,
107862306a36Sopenharmony_ci					offsets->egress_10000,
107962306a36Sopenharmony_ci					offsets->ingress_10000);
108062306a36Sopenharmony_ci			break;
108162306a36Sopenharmony_ci		}
108262306a36Sopenharmony_ci	}
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cistatic void aq_ptp_offset_init(const struct hw_atl_ptp_offset *offsets)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	memset(ptp_offset, 0, sizeof(ptp_offset));
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	aq_ptp_offset_init_from_fw(offsets);
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_cistatic void aq_ptp_gpio_init(struct ptp_clock_info *info,
109362306a36Sopenharmony_ci			     struct hw_atl_info *hw_info)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	struct ptp_pin_desc pin_desc[MAX_PTP_GPIO_COUNT];
109662306a36Sopenharmony_ci	u32 extts_pin_cnt = 0;
109762306a36Sopenharmony_ci	u32 out_pin_cnt = 0;
109862306a36Sopenharmony_ci	u32 i;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	memset(pin_desc, 0, sizeof(pin_desc));
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	for (i = 0; i < MAX_PTP_GPIO_COUNT - 1; i++) {
110362306a36Sopenharmony_ci		if (hw_info->gpio_pin[i] ==
110462306a36Sopenharmony_ci		    (GPIO_PIN_FUNCTION_PTP0 + out_pin_cnt)) {
110562306a36Sopenharmony_ci			snprintf(pin_desc[out_pin_cnt].name,
110662306a36Sopenharmony_ci				 sizeof(pin_desc[out_pin_cnt].name),
110762306a36Sopenharmony_ci				 "AQ_GPIO%d", i);
110862306a36Sopenharmony_ci			pin_desc[out_pin_cnt].index = out_pin_cnt;
110962306a36Sopenharmony_ci			pin_desc[out_pin_cnt].chan = out_pin_cnt;
111062306a36Sopenharmony_ci			pin_desc[out_pin_cnt++].func = PTP_PF_PEROUT;
111162306a36Sopenharmony_ci		}
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	info->n_per_out = out_pin_cnt;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	if (hw_info->caps_ex & BIT(CAPS_EX_PHY_CTRL_TS_PIN)) {
111762306a36Sopenharmony_ci		extts_pin_cnt += 1;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci		snprintf(pin_desc[out_pin_cnt].name,
112062306a36Sopenharmony_ci			 sizeof(pin_desc[out_pin_cnt].name),
112162306a36Sopenharmony_ci			  "AQ_GPIO%d", out_pin_cnt);
112262306a36Sopenharmony_ci		pin_desc[out_pin_cnt].index = out_pin_cnt;
112362306a36Sopenharmony_ci		pin_desc[out_pin_cnt].chan = 0;
112462306a36Sopenharmony_ci		pin_desc[out_pin_cnt].func = PTP_PF_EXTTS;
112562306a36Sopenharmony_ci	}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	info->n_pins = out_pin_cnt + extts_pin_cnt;
112862306a36Sopenharmony_ci	info->n_ext_ts = extts_pin_cnt;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	if (!info->n_pins)
113162306a36Sopenharmony_ci		return;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	info->pin_config = kcalloc(info->n_pins, sizeof(struct ptp_pin_desc),
113462306a36Sopenharmony_ci				   GFP_KERNEL);
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	if (!info->pin_config)
113762306a36Sopenharmony_ci		return;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	memcpy(info->pin_config, &pin_desc,
114062306a36Sopenharmony_ci	       sizeof(struct ptp_pin_desc) * info->n_pins);
114162306a36Sopenharmony_ci}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_civoid aq_ptp_clock_init(struct aq_nic_s *aq_nic)
114462306a36Sopenharmony_ci{
114562306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
114662306a36Sopenharmony_ci	struct timespec64 ts;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	ktime_get_real_ts64(&ts);
114962306a36Sopenharmony_ci	aq_ptp_settime(&aq_ptp->ptp_info, &ts);
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_cistatic void aq_ptp_poll_sync_work_cb(struct work_struct *w);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ciint aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
115562306a36Sopenharmony_ci{
115662306a36Sopenharmony_ci	bool a1_ptp = ATL_HW_IS_CHIP_FEATURE(aq_nic->aq_hw, ATLANTIC);
115762306a36Sopenharmony_ci	struct hw_atl_utils_mbox mbox;
115862306a36Sopenharmony_ci	struct ptp_clock *clock;
115962306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp;
116062306a36Sopenharmony_ci	int err = 0;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (!a1_ptp) {
116362306a36Sopenharmony_ci		aq_nic->aq_ptp = NULL;
116462306a36Sopenharmony_ci		return 0;
116562306a36Sopenharmony_ci	}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	if (!aq_nic->aq_hw_ops->hw_get_ptp_ts) {
116862306a36Sopenharmony_ci		aq_nic->aq_ptp = NULL;
116962306a36Sopenharmony_ci		return 0;
117062306a36Sopenharmony_ci	}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	if (!aq_nic->aq_fw_ops->enable_ptp) {
117362306a36Sopenharmony_ci		aq_nic->aq_ptp = NULL;
117462306a36Sopenharmony_ci		return 0;
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	hw_atl_utils_mpi_read_stats(aq_nic->aq_hw, &mbox);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	if (!(mbox.info.caps_ex & BIT(CAPS_EX_PHY_PTP_EN))) {
118062306a36Sopenharmony_ci		aq_nic->aq_ptp = NULL;
118162306a36Sopenharmony_ci		return 0;
118262306a36Sopenharmony_ci	}
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	aq_ptp_offset_init(&mbox.info.ptp_offset);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	aq_ptp = kzalloc(sizeof(*aq_ptp), GFP_KERNEL);
118762306a36Sopenharmony_ci	if (!aq_ptp) {
118862306a36Sopenharmony_ci		err = -ENOMEM;
118962306a36Sopenharmony_ci		goto err_exit;
119062306a36Sopenharmony_ci	}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	aq_ptp->aq_nic = aq_nic;
119362306a36Sopenharmony_ci	aq_ptp->a1_ptp = a1_ptp;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	spin_lock_init(&aq_ptp->ptp_lock);
119662306a36Sopenharmony_ci	spin_lock_init(&aq_ptp->ptp_ring_lock);
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	aq_ptp->ptp_info = aq_ptp_clock;
119962306a36Sopenharmony_ci	aq_ptp_gpio_init(&aq_ptp->ptp_info, &mbox.info);
120062306a36Sopenharmony_ci	clock = ptp_clock_register(&aq_ptp->ptp_info, &aq_nic->ndev->dev);
120162306a36Sopenharmony_ci	if (IS_ERR(clock)) {
120262306a36Sopenharmony_ci		netdev_err(aq_nic->ndev, "ptp_clock_register failed\n");
120362306a36Sopenharmony_ci		err = PTR_ERR(clock);
120462306a36Sopenharmony_ci		goto err_exit;
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci	aq_ptp->ptp_clock = clock;
120762306a36Sopenharmony_ci	aq_ptp_tx_timeout_init(&aq_ptp->ptp_tx_timeout);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	atomic_set(&aq_ptp->offset_egress, 0);
121062306a36Sopenharmony_ci	atomic_set(&aq_ptp->offset_ingress, 0);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	netif_napi_add(aq_nic_get_ndev(aq_nic), &aq_ptp->napi, aq_ptp_poll);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	aq_ptp->idx_vector = idx_vec;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	aq_nic->aq_ptp = aq_ptp;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	/* enable ptp counter */
121962306a36Sopenharmony_ci	aq_utils_obj_set(&aq_nic->aq_hw->flags, AQ_HW_PTP_AVAILABLE);
122062306a36Sopenharmony_ci	mutex_lock(&aq_nic->fwreq_mutex);
122162306a36Sopenharmony_ci	aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 1);
122262306a36Sopenharmony_ci	aq_ptp_clock_init(aq_nic);
122362306a36Sopenharmony_ci	mutex_unlock(&aq_nic->fwreq_mutex);
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	INIT_DELAYED_WORK(&aq_ptp->poll_sync, &aq_ptp_poll_sync_work_cb);
122662306a36Sopenharmony_ci	aq_ptp->eth_type_filter.location =
122762306a36Sopenharmony_ci			aq_nic_reserve_filter(aq_nic, aq_rx_filter_ethertype);
122862306a36Sopenharmony_ci	aq_ptp->udp_filter.location =
122962306a36Sopenharmony_ci			aq_nic_reserve_filter(aq_nic, aq_rx_filter_l3l4);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	return 0;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_cierr_exit:
123462306a36Sopenharmony_ci	if (aq_ptp)
123562306a36Sopenharmony_ci		kfree(aq_ptp->ptp_info.pin_config);
123662306a36Sopenharmony_ci	kfree(aq_ptp);
123762306a36Sopenharmony_ci	aq_nic->aq_ptp = NULL;
123862306a36Sopenharmony_ci	return err;
123962306a36Sopenharmony_ci}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_civoid aq_ptp_unregister(struct aq_nic_s *aq_nic)
124262306a36Sopenharmony_ci{
124362306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (!aq_ptp)
124662306a36Sopenharmony_ci		return;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	ptp_clock_unregister(aq_ptp->ptp_clock);
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_civoid aq_ptp_free(struct aq_nic_s *aq_nic)
125262306a36Sopenharmony_ci{
125362306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	if (!aq_ptp)
125662306a36Sopenharmony_ci		return;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	aq_nic_release_filter(aq_nic, aq_rx_filter_ethertype,
125962306a36Sopenharmony_ci			      aq_ptp->eth_type_filter.location);
126062306a36Sopenharmony_ci	aq_nic_release_filter(aq_nic, aq_rx_filter_l3l4,
126162306a36Sopenharmony_ci			      aq_ptp->udp_filter.location);
126262306a36Sopenharmony_ci	cancel_delayed_work_sync(&aq_ptp->poll_sync);
126362306a36Sopenharmony_ci	/* disable ptp */
126462306a36Sopenharmony_ci	mutex_lock(&aq_nic->fwreq_mutex);
126562306a36Sopenharmony_ci	aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 0);
126662306a36Sopenharmony_ci	mutex_unlock(&aq_nic->fwreq_mutex);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	kfree(aq_ptp->ptp_info.pin_config);
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	netif_napi_del(&aq_ptp->napi);
127162306a36Sopenharmony_ci	kfree(aq_ptp);
127262306a36Sopenharmony_ci	aq_nic->aq_ptp = NULL;
127362306a36Sopenharmony_ci}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_cistruct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp)
127662306a36Sopenharmony_ci{
127762306a36Sopenharmony_ci	return aq_ptp->ptp_clock;
127862306a36Sopenharmony_ci}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci/* PTP external GPIO nanoseconds count */
128162306a36Sopenharmony_cistatic uint64_t aq_ptp_get_sync1588_ts(struct aq_nic_s *aq_nic)
128262306a36Sopenharmony_ci{
128362306a36Sopenharmony_ci	u64 ts = 0;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	if (aq_nic->aq_hw_ops->hw_get_sync_ts)
128662306a36Sopenharmony_ci		aq_nic->aq_hw_ops->hw_get_sync_ts(aq_nic->aq_hw, &ts);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	return ts;
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_cistatic void aq_ptp_start_work(struct aq_ptp_s *aq_ptp)
129262306a36Sopenharmony_ci{
129362306a36Sopenharmony_ci	if (aq_ptp->extts_pin_enabled) {
129462306a36Sopenharmony_ci		aq_ptp->poll_timeout_ms = POLL_SYNC_TIMER_MS;
129562306a36Sopenharmony_ci		aq_ptp->last_sync1588_ts =
129662306a36Sopenharmony_ci				aq_ptp_get_sync1588_ts(aq_ptp->aq_nic);
129762306a36Sopenharmony_ci		schedule_delayed_work(&aq_ptp->poll_sync,
129862306a36Sopenharmony_ci				      msecs_to_jiffies(aq_ptp->poll_timeout_ms));
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ciint aq_ptp_link_change(struct aq_nic_s *aq_nic)
130362306a36Sopenharmony_ci{
130462306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	if (!aq_ptp)
130762306a36Sopenharmony_ci		return 0;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	if (aq_nic->aq_hw->aq_link_status.mbps)
131062306a36Sopenharmony_ci		aq_ptp_start_work(aq_ptp);
131162306a36Sopenharmony_ci	else
131262306a36Sopenharmony_ci		cancel_delayed_work_sync(&aq_ptp->poll_sync);
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	return 0;
131562306a36Sopenharmony_ci}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_cistatic bool aq_ptp_sync_ts_updated(struct aq_ptp_s *aq_ptp, u64 *new_ts)
131862306a36Sopenharmony_ci{
131962306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
132062306a36Sopenharmony_ci	u64 sync_ts2;
132162306a36Sopenharmony_ci	u64 sync_ts;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	sync_ts = aq_ptp_get_sync1588_ts(aq_nic);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	if (sync_ts != aq_ptp->last_sync1588_ts) {
132662306a36Sopenharmony_ci		sync_ts2 = aq_ptp_get_sync1588_ts(aq_nic);
132762306a36Sopenharmony_ci		if (sync_ts != sync_ts2) {
132862306a36Sopenharmony_ci			sync_ts = sync_ts2;
132962306a36Sopenharmony_ci			sync_ts2 = aq_ptp_get_sync1588_ts(aq_nic);
133062306a36Sopenharmony_ci			if (sync_ts != sync_ts2) {
133162306a36Sopenharmony_ci				netdev_err(aq_nic->ndev,
133262306a36Sopenharmony_ci					   "%s: Unable to get correct GPIO TS",
133362306a36Sopenharmony_ci					   __func__);
133462306a36Sopenharmony_ci				sync_ts = 0;
133562306a36Sopenharmony_ci			}
133662306a36Sopenharmony_ci		}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci		*new_ts = sync_ts;
133962306a36Sopenharmony_ci		return true;
134062306a36Sopenharmony_ci	}
134162306a36Sopenharmony_ci	return false;
134262306a36Sopenharmony_ci}
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_cistatic int aq_ptp_check_sync1588(struct aq_ptp_s *aq_ptp)
134562306a36Sopenharmony_ci{
134662306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
134762306a36Sopenharmony_ci	u64 sync_ts;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	 /* Sync1588 pin was triggered */
135062306a36Sopenharmony_ci	if (aq_ptp_sync_ts_updated(aq_ptp, &sync_ts)) {
135162306a36Sopenharmony_ci		if (aq_ptp->extts_pin_enabled) {
135262306a36Sopenharmony_ci			struct ptp_clock_event ptp_event;
135362306a36Sopenharmony_ci			u64 time = 0;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci			aq_nic->aq_hw_ops->hw_ts_to_sys_clock(aq_nic->aq_hw,
135662306a36Sopenharmony_ci							      sync_ts, &time);
135762306a36Sopenharmony_ci			ptp_event.index = aq_ptp->ptp_info.n_pins - 1;
135862306a36Sopenharmony_ci			ptp_event.timestamp = time;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci			ptp_event.type = PTP_CLOCK_EXTTS;
136162306a36Sopenharmony_ci			ptp_clock_event(aq_ptp->ptp_clock, &ptp_event);
136262306a36Sopenharmony_ci		}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci		aq_ptp->last_sync1588_ts = sync_ts;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	return 0;
136862306a36Sopenharmony_ci}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_cistatic void aq_ptp_poll_sync_work_cb(struct work_struct *w)
137162306a36Sopenharmony_ci{
137262306a36Sopenharmony_ci	struct delayed_work *dw = to_delayed_work(w);
137362306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = container_of(dw, struct aq_ptp_s, poll_sync);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	aq_ptp_check_sync1588(aq_ptp);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	if (aq_ptp->extts_pin_enabled) {
137862306a36Sopenharmony_ci		unsigned long timeout = msecs_to_jiffies(aq_ptp->poll_timeout_ms);
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci		schedule_delayed_work(&aq_ptp->poll_sync, timeout);
138162306a36Sopenharmony_ci	}
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ciint aq_ptp_get_ring_cnt(struct aq_nic_s *aq_nic, const enum atl_ring_type ring_type)
138562306a36Sopenharmony_ci{
138662306a36Sopenharmony_ci	if (!aq_nic->aq_ptp)
138762306a36Sopenharmony_ci		return 0;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	/* Additional RX ring is allocated for PTP HWTS on A1 */
139062306a36Sopenharmony_ci	return (aq_nic->aq_ptp->a1_ptp && ring_type == ATL_RING_RX) ? 2 : 1;
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ciu64 *aq_ptp_get_stats(struct aq_nic_s *aq_nic, u64 *data)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
139662306a36Sopenharmony_ci	unsigned int count = 0U;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	if (!aq_ptp)
139962306a36Sopenharmony_ci		return data;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	count = aq_ring_fill_stats_data(&aq_ptp->ptp_rx, data);
140262306a36Sopenharmony_ci	data += count;
140362306a36Sopenharmony_ci	count = aq_ring_fill_stats_data(&aq_ptp->ptp_tx, data);
140462306a36Sopenharmony_ci	data += count;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	if (aq_ptp->a1_ptp) {
140762306a36Sopenharmony_ci		/* Only Receive ring for HWTS */
140862306a36Sopenharmony_ci		count = aq_ring_fill_stats_data(&aq_ptp->hwts_rx, data);
140962306a36Sopenharmony_ci		data += count;
141062306a36Sopenharmony_ci	}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	return data;
141362306a36Sopenharmony_ci}
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci#endif
1416