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, ×tamp); 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