]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: atlantic: add AQC113 TX timestamp polling and PTP TX classification
authorSukhdeep Singh <sukhdeeps@marvell.com>
Wed, 10 Jun 2026 11:54:47 +0000 (17:24 +0530)
committerJakub Kicinski <kuba@kernel.org>
Mon, 15 Jun 2026 22:38:44 +0000 (15:38 -0700)
aq_ring.h / aq_ring.c:
- Add ptp_ts_deadline field to aq_ring_s to track TX timestamp timeout.
- In aq_ring_tx_clean(): when hw_ring_tx_ptp_get_ts() returns 0 (HW not
  yet written back the timestamp), clear buff->is_mapped and buff->pa
  before breaking to prevent double dma_unmap on retry.  When
  ptp_ts_deadline expires, dequeue and drop the head of skb_ring to keep
  it in lockstep with buff_ring, then clear request_ts and free the skb
  via dev_kfree_skb_any() to unblock the ring.

aq_main.c:
- Add IPv6 PTP packet detection in aq_ndev_start_xmit() using
  ipv6_hdr()->nexthdr for ETH_P_IPV6 frames, steering them through
  aq_ptp_xmit() alongside the existing IPv4 path.
- Use PTP_EV_PORT/PTP_GEN_PORT constants instead of magic numbers 319/320.
- Remove duplicate aq_reapply_rxnfc_all_rules() and
  aq_filters_vlans_update()
  calls from aq_ndev_open() - now covered by aq_nic_start(), which also
  ensures filters are restored correctly after PM resume.

aq_nic.c:
- Move aq_reapply_rxnfc_all_rules() and aq_filters_vlans_update() into
  aq_nic_start() after hardware init, replacing the duplicate calls that
  were removed from aq_ndev_open().

Signed-off-by: Sukhdeep Singh <sukhdeeps@marvell.com>
Link: https://patch.msgid.link/20260610115448.272-12-sukhdeeps@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/aquantia/atlantic/aq_main.c
drivers/net/ethernet/aquantia/atlantic/aq_nic.c
drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
drivers/net/ethernet/aquantia/atlantic/aq_ring.c
drivers/net/ethernet/aquantia/atlantic/aq_ring.h

index 4ef4fe64b8ac13e4afef8615a3e7486c40033aa0..1da14786fe5cc73234227222569f1f6c8207eeab 100644 (file)
 #include <linux/netdevice.h>
 #include <linux/module.h>
 #include <linux/ip.h>
+#include <linux/ipv6.h>
 #include <linux/udp.h>
 #include <net/pkt_cls.h>
+#include <linux/ptp_classify.h>
 #include <net/pkt_sched.h>
 #include <linux/filter.h>
 
@@ -68,14 +70,6 @@ int aq_ndev_open(struct net_device *ndev)
        if (err < 0)
                goto err_exit;
 
-       err = aq_reapply_rxnfc_all_rules(aq_nic);
-       if (err < 0)
-               goto err_exit;
-
-       err = aq_filters_vlans_update(aq_nic);
-       if (err < 0)
-               goto err_exit;
-
        err = aq_nic_start(aq_nic);
        if (err < 0) {
                aq_nic_stop(aq_nic);
@@ -113,12 +107,20 @@ static netdev_tx_t aq_ndev_start_xmit(struct sk_buff *skb, struct net_device *nd
                 * and hardware PTP design of the chip. Otherwise ptp stream
                 * will fail to sync
                 */
-               if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) ||
-                   unlikely((ip_hdr(skb)->version == 4) &&
-                            (ip_hdr(skb)->protocol == IPPROTO_UDP) &&
-                            ((udp_hdr(skb)->dest == htons(319)) ||
-                             (udp_hdr(skb)->dest == htons(320)))) ||
-                   unlikely(eth_hdr(skb)->h_proto == htons(ETH_P_1588)))
+               if (unlikely(skb->protocol == htons(ETH_P_IP) &&
+                            ip_hdr(skb)->protocol == IPPROTO_UDP &&
+                            (udp_hdr(skb)->dest == htons(PTP_EV_PORT) ||
+                             udp_hdr(skb)->dest == htons(PTP_GEN_PORT))))
+                       return aq_ptp_xmit(aq_nic, skb);
+
+               /* PTP over IPv6 does not use extension headers */
+               if (unlikely(skb->protocol == htons(ETH_P_IPV6) &&
+                            ipv6_hdr(skb)->nexthdr == IPPROTO_UDP &&
+                            (udp_hdr(skb)->dest == htons(PTP_EV_PORT) ||
+                             udp_hdr(skb)->dest == htons(PTP_GEN_PORT))))
+                       return aq_ptp_xmit(aq_nic, skb);
+
+               if (unlikely(eth_hdr(skb)->h_proto == htons(ETH_P_1588)))
                        return aq_ptp_xmit(aq_nic, skb);
        }
 #endif
index ef94478100716a9d79d5e6526d42a30ca1511a5d..09c90c969fb1d5a7ea5e74ae562fd696f2e02d61 100644 (file)
@@ -496,6 +496,14 @@ int aq_nic_start(struct aq_nic_s *self)
                        goto err_exit;
        }
 
+       err = aq_reapply_rxnfc_all_rules(self);
+       if (err < 0)
+               goto err_exit;
+
+       err = aq_filters_vlans_update(self);
+       if (err < 0)
+               goto err_exit;
+
        err = aq_ptp_ring_start(self);
        if (err < 0)
                goto err_exit;
index 7486a28d7ff8f7f9ebab3809e18dd4711a0ad89c..6bb2329f1a682b309c7b728d2f7f30f1828783eb 100644 (file)
@@ -268,6 +268,18 @@ static void aq_ptp_tx_timeout_check(struct aq_ptp_s *aq_ptp)
        }
 }
 
+void aq_ptp_tx_skb_drop_head(struct aq_nic_s *aq_nic)
+{
+       struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
+       struct sk_buff *skb;
+
+       if (!aq_ptp)
+               return;
+       skb = aq_ptp_skb_get(&aq_ptp->skb_ring);
+       if (skb)
+               dev_kfree_skb_any(skb);
+}
+
 /* aq_ptp_adjfine
  * @ptp: the ptp clock structure
  * @ppb: parts per billion adjustment from base
index 5e643ec7cc06a521ad54c85a8ef0da0d592f5b58..1658ef788de8a902f335e5e7de7daaf1c64bffd4 100644 (file)
@@ -53,6 +53,7 @@ void aq_ptp_service_task(struct aq_nic_s *aq_nic);
 void aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic, unsigned int mbps);
 
 void aq_ptp_clock_init(struct aq_nic_s *aq_nic);
+void aq_ptp_tx_skb_drop_head(struct aq_nic_s *aq_nic);
 
 /* Traffic processing functions */
 int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb);
@@ -123,6 +124,7 @@ static inline void aq_ptp_service_task(struct aq_nic_s *aq_nic) {}
 static inline void aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic,
                                        unsigned int mbps) {}
 static inline void aq_ptp_clock_init(struct aq_nic_s *aq_nic) {}
+static inline void aq_ptp_tx_skb_drop_head(struct aq_nic_s *aq_nic) {}
 static inline int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb)
 {
        return -EOPNOTSUPP;
index e270327e47fd804cc8ee5cfd53ed1b993c955c41..8ff07de2bd52401c1099ffc08dcf33e831c876d0 100644 (file)
@@ -311,6 +311,30 @@ bool aq_ring_tx_clean(struct aq_ring_s *self)
                if (likely(!buff->is_eop))
                        goto out;
 
+               if (unlikely(buff->request_ts) &&
+                   self->aq_nic->aq_hw_ops->hw_ring_tx_ptp_get_ts) {
+                       u64 ts = self->aq_nic->aq_hw_ops->hw_ring_tx_ptp_get_ts(self);
+
+                       if (!ts) {
+                               if (time_after(jiffies,
+                                              self->ptp_ts_deadline)) {
+                                       /* Timeout: drain skb_ring head to
+                                        * keep in sync with buff_ring
+                                        */
+                                       aq_ptp_tx_skb_drop_head(self->aq_nic);
+                                       buff->request_ts = 0;
+                                       dev_kfree_skb_any(buff->skb);
+                                       buff->skb = NULL;
+                                       goto out;
+                               } else {
+                                       buff->is_mapped = 0;
+                                       buff->pa = 0U;
+                                       break;
+                               }
+                       }
+
+                       aq_ptp_tx_hwtstamp(self->aq_nic, ts);
+               }
                if (buff->skb) {
                        u64_stats_update_begin(&self->stats.tx.syncp);
                        ++self->stats.tx.packets;
@@ -570,7 +594,7 @@ static int __aq_ring_rx_clean(struct aq_ring_s *self, struct napi_struct *napi,
                                                            self->hw_head);
 
                                if (unlikely(!is_rsc_completed) ||
-                                               frag_cnt > MAX_SKB_FRAGS) {
+                                   frag_cnt > MAX_SKB_FRAGS) {
                                        err = 0;
                                        goto err_exit;
                                }
index e578fe04d22c9c5d07138ea444e6aa60fec8441c..a70b880ada67e956793140abe19306c520aa1a6f 100644 (file)
@@ -154,6 +154,7 @@ struct aq_ring_s {
        struct bpf_prog *xdp_prog;
        enum atl_ring_type ring_type;
        struct xdp_rxq_info xdp_rxq;
+       unsigned long ptp_ts_deadline;
 };
 
 struct aq_ring_param_s {