From: <sukhdeeps@marvell.com>
To: <netdev@vger.kernel.org>
Cc: <irusskikh@marvell.com>, <epomozov@marvell.com>,
<richardcochran@gmail.com>, <andrew+netdev@lunn.ch>,
<davem@davemloft.net>, <edumazet@google.com>, <kuba@kernel.org>,
<pabeni@redhat.com>, <linux-kernel@vger.kernel.org>,
Sukhdeep Singh <sukhdeeps@marvell.com>
Subject: [PATCH net-next 9/9] net: atlantic: add PTP support for AQC113 (Antigua) (Antigua)
Date: Wed, 6 May 2026 19:27:06 +0530 [thread overview]
Message-ID: <20260506135706.2834-10-sukhdeeps@marvell.com> (raw)
In-Reply-To: <20260506135706.2834-1-sukhdeeps@marvell.com>
From: Sukhdeep Singh <sukhdeeps@marvell.com>
Add IEEE 1588 PTP support for the AQC113 (Antigua) network controller
alongside the existing AQC107 (Atlantic) PTP implementation.
AQC113 PTP uses a different hardware architecture from AQC107:
- Dual TSG clocks (sel 0 for PTP, sel 1 for PTM) instead of PHY-based
timestamping
- TX timestamp via descriptor writeback instead of firmware mailbox
- Per-instance PTP timestamp offsets instead of global static table
- Hardware L3/L4 filters for PTP multicast steering with IPv4 and
IPv6 support (4 filter slots for multicast addresses)
- Direct hardware clock control instead of firmware-mediated access
Key implementation details:
PTP clock management:
- Add aq_ptp_state enum to distinguish first init, link up, and no
link states for proper clock initialization
- On AQC113, only reset the clock on first init (not on every link
change) to avoid disrupting ongoing PTP synchronization
- Re-apply RX filters on link change since hardware state is lost
TX timestamp path:
- Add per-packet TX timestamp request via request_ts/clk_sel in the
ring buffer descriptor
- Poll for TX timestamp completion in aq_ring_tx_clean() with a
timeout mechanism (aq_ptp_tx_ts_timedout/clear)
- Set AQ_HW_TXD_CTL_TS_EN in TX descriptors for timestamp-requested
packets
RX filter management:
- Replace single UDP filter with array of 4 for IPv4/IPv6 multicast
PTP addresses (224.0.1.129, 224.0.0.107, ff0e::181, ff02::6b)
- Add aq_ptp_dpath_enable() for comprehensive filter setup/teardown
- Add aq_ptp_parse_rx_filters() to map hwtstamp_rx_filters to L2/L4
enable flags
PTP TX path in aq_main.c:
- Add IPv6 PTP packet detection using ipv6_hdr()->nexthdr
- Use PTP_EV_PORT/PTP_GEN_PORT defines instead of magic numbers
- Move skb_tx_timestamp() to non-PTP path to avoid double timestamps
IRQ and initialization:
- Account for PTP IRQ vector (AQ_HW_PTP_IRQS) in vector math
- Move filter/VLAN rule application to aq_nic_start() for proper
ordering after PTP ring setup
- Add AQ_HW_FLAG_STARTED flag management in open/close
HW layer (hw_atl2.c):
- Implement PTP clock enable/disable, read, adjust, increment
- Add GPIO pulse generation for PPS output
- Add TX/RX PTP ring initialization
- Add TX timestamp descriptor readback
- Add RX timestamp extraction from packet trailer
- Re-enable PTP after hardware reset
- Wire all PTP ops into hw_atl2_ops table
Per-instance PTP offsets with empirically measured values for AQC113
at each link speed (100M/1G/2.5G/5G/10G).
Signed-off-by: Sukhdeep Singh <sukhdeeps@marvell.com>
---
.../net/ethernet/aquantia/atlantic/aq_hw.h | 1 +
.../net/ethernet/aquantia/atlantic/aq_main.c | 34 +-
.../net/ethernet/aquantia/atlantic/aq_nic.c | 48 +-
.../ethernet/aquantia/atlantic/aq_pci_func.c | 4 +-
.../net/ethernet/aquantia/atlantic/aq_ptp.c | 535 ++++++++++++++----
.../net/ethernet/aquantia/atlantic/aq_ptp.h | 15 +-
.../net/ethernet/aquantia/atlantic/aq_ring.c | 42 +-
.../aquantia/atlantic/hw_atl2/hw_atl2.c | 179 +++++-
.../aquantia/atlantic/hw_atl2/hw_atl2.h | 12 +
.../atlantic/hw_atl2/hw_atl2_internal.h | 3 +-
.../aquantia/atlantic/hw_atl2/hw_atl2_utils.h | 10 +
11 files changed, 710 insertions(+), 173 deletions(-)
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index e3bacad08b93..4141210578fd 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -15,6 +15,7 @@
#include "aq_common.h"
#include "aq_rss.h"
#include "hw_atl/hw_atl_utils.h"
+#include "hw_atl2/hw_atl2.h"
#define AQ_HW_MAC_COUNTER_HZ 312500000ll
#define AQ_HW_PHY_COUNTER_HZ 160000000ll
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
index 4ef4fe64b8ac..aadf3f7f40d0 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
@@ -19,8 +19,10 @@
#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,20 +70,14 @@ 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);
goto err_exit;
}
+ aq_utils_obj_set(&aq_nic->aq_hw->flags, AQ_HW_FLAG_STARTED);
+
err_exit:
if (err < 0)
aq_nic_deinit(aq_nic, true);
@@ -97,6 +93,7 @@ int aq_ndev_close(struct net_device *ndev)
err = aq_nic_stop(aq_nic);
aq_nic_deinit(aq_nic, true);
+ aq_utils_obj_clear(&aq_nic->aq_hw->flags, AQ_HW_FLAG_STARTED);
return err;
}
@@ -113,16 +110,25 @@ 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
+ skb_tx_timestamp(skb);
return aq_nic_xmit(aq_nic, skb);
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 3cec853e9fad..63a4987a60de 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -72,8 +72,15 @@ static void aq_nic_cfg_update_num_vecs(struct aq_nic_s *self)
cfg->vecs = min(cfg->aq_hw_caps->vecs, AQ_CFG_VECS_DEF);
cfg->vecs = min(cfg->vecs, num_online_cpus());
- if (self->irqvecs > AQ_HW_SERVICE_IRQS)
- cfg->vecs = min(cfg->vecs, self->irqvecs - AQ_HW_SERVICE_IRQS);
+ if (self->irqvecs > AQ_HW_SERVICE_IRQS + AQ_HW_PTP_IRQS)
+ cfg->vecs = min(cfg->vecs,
+ self->irqvecs - AQ_HW_SERVICE_IRQS - AQ_HW_PTP_IRQS);
+ else if (self->irqvecs > AQ_HW_PTP_IRQS)
+ cfg->vecs = min(cfg->vecs,
+ self->irqvecs - AQ_HW_PTP_IRQS);
+ else
+ cfg->vecs = 1U;
+
/* cfg->vecs should be power of 2 for RSS */
cfg->vecs = rounddown_pow_of_two(cfg->vecs);
@@ -138,7 +145,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
* link status IRQ. If no - we'll know link state from
* slower service task.
*/
- if (AQ_HW_SERVICE_IRQS > 0 && cfg->vecs + 1 <= self->irqvecs)
+ if (AQ_HW_SERVICE_IRQS > 0 &&
+ self->irqvecs > AQ_HW_PTP_IRQS + AQ_HW_SERVICE_IRQS)
cfg->link_irq_vec = cfg->vecs;
else
cfg->link_irq_vec = 0;
@@ -172,7 +180,11 @@ static int aq_nic_update_link_status(struct aq_nic_s *self)
aq_nic_update_interrupt_moderation_settings(self);
if (self->aq_ptp) {
- aq_ptp_clock_init(self);
+ /* PTP does not work in some modes even if physical link is up */
+ bool ptp_link_good = (self->aq_hw->aq_link_status.mbps >= 100 &&
+ self->aq_hw->aq_link_status.full_duplex);
+
+ aq_ptp_clock_init(self, ptp_link_good ? AQ_PTP_LINK_UP : AQ_PTP_NO_LINK);
aq_ptp_tm_offset_set(self,
self->aq_hw->aq_link_status.mbps);
aq_ptp_link_change(self);
@@ -279,6 +291,9 @@ static int aq_nic_hw_prepare(struct aq_nic_s *self)
int err = 0;
err = self->aq_hw_ops->hw_soft_reset(self->aq_hw);
+
+ self->aq_hw->clk_select = -1;
+
if (err)
goto exit;
@@ -450,7 +465,14 @@ int aq_nic_init(struct aq_nic_s *self)
}
if (aq_nic_get_cfg(self)->is_ptp) {
- err = aq_ptp_init(self, self->irqvecs - 1);
+ u32 ptp_isr_vec;
+
+ if (self->irqvecs > AQ_HW_PTP_IRQS)
+ ptp_isr_vec = self->irqvecs - AQ_HW_PTP_IRQS;
+ else
+ ptp_isr_vec = 0;
+
+ err = aq_ptp_init(self, ptp_isr_vec);
if (err < 0)
goto err_exit;
@@ -496,6 +518,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;
@@ -793,6 +823,12 @@ unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb,
first->eop_index = dx;
dx_buff->is_eop = 1U;
+ if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS &&
+ self->aq_hw_ops->enable_ptp &&
+ self->aq_hw_ops->hw_get_clk_sel) {
+ dx_buff->request_ts = 1U;
+ dx_buff->clk_sel = self->aq_hw_ops->hw_get_clk_sel(self->aq_hw);
+ }
dx_buff->skb = skb;
dx_buff->xdpf = NULL;
goto exit;
@@ -895,8 +931,6 @@ int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb)
frags = aq_nic_map_skb(self, skb, ring);
- skb_tx_timestamp(skb);
-
if (likely(frags)) {
err = self->aq_hw_ops->hw_ring_tx_xmit(self->aq_hw,
ring, frags);
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
index e9e38af680c3..9e72a9c23b40 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
@@ -293,8 +293,8 @@ static int aq_pci_probe(struct pci_dev *pdev,
numvecs = min((u8)AQ_CFG_VECS_DEF,
aq_nic_get_cfg(self)->aq_hw_caps->msix_irqs);
numvecs = min(numvecs, num_online_cpus());
- /* Request IRQ vector for PTP */
- numvecs += 1;
+ /* Request IRQ lines for PTP */
+ numvecs += AQ_HW_PTP_IRQS;
numvecs += AQ_HW_SERVICE_IRQS;
/*enable interrupts */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
index 7486a28d7ff8..781d865e1127 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
@@ -26,6 +26,18 @@
#define POLL_SYNC_TIMER_MS 15
+#define PTP_UDP_FILTERS_CNT 4
+
+#define PTP_IPV4_MC_ADDR1 0xE0000181
+#define PTP_IPV4_MC_ADDR2 0xE000006B
+
+#define PTP_IPV6_MC_ADDR10 0xFF0E
+#define PTP_IPV6_MC_ADDR14 0x0181
+#define PTP_IPV6_MC_ADDR20 0xFF02
+#define PTP_IPV6_MC_ADDR24 0x006B
+
+#define PTP_GPIO_HIGHTIME 100000
+
enum ptp_speed_offsets {
ptp_offset_idx_10 = 0,
ptp_offset_idx_100,
@@ -49,6 +61,12 @@ struct ptp_tx_timeout {
unsigned long tx_start;
};
+struct ptp_tm_offset {
+ unsigned int mbps;
+ int egress;
+ int ingress;
+};
+
struct aq_ptp_s {
struct aq_nic_s *aq_nic;
struct kernel_hwtstamp_config hwtstamp_config;
@@ -64,7 +82,7 @@ struct aq_ptp_s {
struct ptp_tx_timeout ptp_tx_timeout;
- unsigned int idx_vector;
+ unsigned int idx_ptp_vector;
struct napi_struct napi;
struct aq_ring_s ptp_tx;
@@ -73,7 +91,7 @@ struct aq_ptp_s {
struct ptp_skb_ring skb_ring;
- struct aq_rx_filter_l3l4 udp_filter;
+ struct aq_rx_filter_l3l4 udp_filter[PTP_UDP_FILTERS_CNT];
struct aq_rx_filter_l2 eth_type_filter;
struct delayed_work poll_sync;
@@ -81,18 +99,15 @@ struct aq_ptp_s {
bool extts_pin_enabled;
u64 last_sync1588_ts;
+ /* TSG clock selection: 0 - PTP, 1 - PTM */
+ u32 ptp_clock_sel;
bool a1_ptp;
-};
+ bool a2_ptp;
-struct ptp_tm_offset {
- unsigned int mbps;
- int egress;
- int ingress;
+ struct ptp_tm_offset ptp_offset[6];
};
-static struct ptp_tm_offset ptp_offset[6];
-
void aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic, unsigned int mbps)
{
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
@@ -104,10 +119,10 @@ void aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic, unsigned int mbps)
egress = 0;
ingress = 0;
- for (i = 0; i < ARRAY_SIZE(ptp_offset); i++) {
- if (mbps == ptp_offset[i].mbps) {
- egress = ptp_offset[i].egress;
- ingress = ptp_offset[i].ingress;
+ for (i = 0; i < ARRAY_SIZE(aq_ptp->ptp_offset); i++) {
+ if (mbps == aq_ptp->ptp_offset[i].mbps) {
+ egress = aq_ptp->ptp_offset[i].egress;
+ ingress = aq_ptp->ptp_offset[i].ingress;
break;
}
}
@@ -366,6 +381,8 @@ static void aq_ptp_convert_to_hwtstamp(struct aq_ptp_s *aq_ptp,
static int aq_ptp_hw_pin_conf(struct aq_nic_s *aq_nic, u32 pin_index, u64 start,
u64 period)
{
+ struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
+
if (period)
netdev_dbg(aq_nic->ndev,
"Enable GPIO %d pulsing, start time %llu, period %u\n",
@@ -380,7 +397,8 @@ static int aq_ptp_hw_pin_conf(struct aq_nic_s *aq_nic, u32 pin_index, u64 start,
*/
mutex_lock(&aq_nic->fwreq_mutex);
aq_nic->aq_hw_ops->hw_gpio_pulse(aq_nic->aq_hw, pin_index,
- 0, start, (u32)period, 0);
+ aq_ptp->ptp_clock_sel, start,
+ (u32)period, PTP_GPIO_HIGHTIME);
mutex_unlock(&aq_nic->fwreq_mutex);
return 0;
@@ -454,7 +472,8 @@ static void aq_ptp_extts_pin_ctrl(struct aq_ptp_s *aq_ptp)
if (aq_nic->aq_hw_ops->hw_extts_gpio_enable)
aq_nic->aq_hw_ops->hw_extts_gpio_enable(aq_nic->aq_hw, 0,
- 0, enable);
+ aq_ptp->ptp_clock_sel,
+ enable);
}
static int aq_ptp_extts_pin_configure(struct ptp_clock_info *ptp,
@@ -543,14 +562,193 @@ void aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp)
return;
}
- timestamp += atomic_read(&aq_ptp->offset_egress);
- aq_ptp_convert_to_hwtstamp(aq_ptp, &hwtstamp, timestamp);
- skb_tstamp_tx(skb, &hwtstamp);
+ if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+ timestamp += atomic_read(&aq_ptp->offset_egress);
+ aq_ptp_convert_to_hwtstamp(aq_ptp, &hwtstamp, timestamp);
+ skb_tstamp_tx(skb, &hwtstamp);
+ }
+
dev_kfree_skb_any(skb);
aq_ptp_tx_timeout_update(aq_ptp);
}
+static void aq_ptp_fill_udpv4_mc(struct ethtool_rx_flow_spec *fsp,
+ u16 rx_queue, __be32 mc_addr)
+{
+ memset(fsp, 0, sizeof(*fsp));
+ fsp->ring_cookie = rx_queue;
+ fsp->flow_type = UDP_V4_FLOW;
+ fsp->h_u.udp_ip4_spec.pdst = cpu_to_be16(PTP_EV_PORT);
+ fsp->m_u.udp_ip4_spec.pdst = cpu_to_be16(0xffff);
+ fsp->h_u.udp_ip4_spec.ip4dst = mc_addr;
+ fsp->m_u.udp_ip4_spec.ip4dst = cpu_to_be32(0xffffffff);
+}
+
+static void aq_ptp_fill_udpv6_mc(struct ethtool_rx_flow_spec *fsp,
+ u16 rx_queue,
+ __be32 ip6dst_hi, __be32 ip6dst_hi_mask,
+ __be32 ip6dst_lo, __be32 ip6dst_lo_mask)
+{
+ memset(fsp, 0, sizeof(*fsp));
+ fsp->ring_cookie = rx_queue;
+ fsp->flow_type = UDP_V6_FLOW;
+ fsp->h_u.udp_ip6_spec.pdst = cpu_to_be16(PTP_EV_PORT);
+ fsp->m_u.udp_ip6_spec.pdst = cpu_to_be16(0xffff);
+ fsp->h_u.udp_ip6_spec.ip6dst[0] = ip6dst_hi;
+ fsp->m_u.udp_ip6_spec.ip6dst[0] = ip6dst_hi_mask;
+ fsp->h_u.udp_ip6_spec.ip6dst[3] = ip6dst_lo;
+ fsp->m_u.udp_ip6_spec.ip6dst[3] = ip6dst_lo_mask;
+}
+
+static int aq_ptp_add_a2_filter(struct aq_ptp_s *aq_ptp,
+ struct ethtool_rx_flow_spec *fsp,
+ int *flt_idx)
+{
+ struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
+ int err;
+
+ err = aq_set_data_fl3l4(fsp,
+ &aq_ptp->udp_filter[*flt_idx],
+ aq_ptp->udp_filter[*flt_idx].location,
+ true);
+ if (!err) {
+ netdev_dbg(aq_nic->ndev,
+ "PTP MC filter prepared. Loc: %x\n",
+ aq_ptp->udp_filter[*flt_idx].location);
+ (*flt_idx)++;
+ }
+ return err;
+}
+
+static int aq_ptp_dpath_enable(struct aq_ptp_s *aq_ptp,
+ int enable_flags, u16 rx_queue)
+{
+ struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
+ struct ethtool_rxnfc cmd = { 0 };
+ int err = 0, i = 0;
+ int flt_idx = 0;
+ const struct aq_hw_ops *hw_ops = aq_nic->aq_hw_ops;
+ struct ethtool_rx_flow_spec *fsp =
+ (struct ethtool_rx_flow_spec *)&cmd.fs;
+
+ netdev_dbg(aq_nic->ndev,
+ "%sable ptp filters: %x.\n",
+ enable_flags ? "En" : "Dis", enable_flags);
+
+ if (enable_flags) {
+ if (enable_flags & (AQ_HW_PTP_L4_ENABLE)) {
+ if (aq_ptp->a1_ptp) {
+ fsp->ring_cookie = rx_queue;
+ fsp->flow_type = UDP_V4_FLOW;
+ fsp->h_u.udp_ip4_spec.pdst =
+ cpu_to_be16(PTP_EV_PORT);
+ fsp->m_u.udp_ip4_spec.pdst =
+ cpu_to_be16(0xffff);
+ err = aq_set_data_fl3l4(fsp,
+ &aq_ptp->udp_filter[flt_idx],
+ aq_ptp->udp_filter[flt_idx].location,
+ true);
+ if (!err) {
+ netdev_dbg(aq_nic->ndev,
+ "Set UDPv4, location: %x\n",
+ aq_ptp->udp_filter[flt_idx]
+ .location);
+ flt_idx++;
+ }
+ } else {
+ aq_ptp_fill_udpv4_mc(fsp, rx_queue,
+ cpu_to_be32(PTP_IPV4_MC_ADDR1));
+ err = aq_ptp_add_a2_filter(aq_ptp, fsp,
+ &flt_idx);
+ if (err)
+ netdev_dbg(aq_nic->ndev,
+ "UDPv4 filter prepare failed\n");
+
+ aq_ptp_fill_udpv6_mc(fsp, rx_queue,
+ cpu_to_be32(PTP_IPV6_MC_ADDR20 << 16),
+ cpu_to_be32(0xffff0000),
+ cpu_to_be32(PTP_IPV6_MC_ADDR24),
+ cpu_to_be32(0x0000ffff));
+ err = aq_ptp_add_a2_filter(aq_ptp, fsp,
+ &flt_idx);
+ if (err)
+ netdev_dbg(aq_nic->ndev,
+ "UDPv6 filter prepare failed\n");
+
+ aq_ptp_fill_udpv6_mc(fsp, rx_queue,
+ cpu_to_be32(PTP_IPV6_MC_ADDR10 << 16),
+ cpu_to_be32(0xffff0000),
+ cpu_to_be32(PTP_IPV6_MC_ADDR14),
+ cpu_to_be32(0x0000ffff));
+ err = aq_ptp_add_a2_filter(aq_ptp, fsp,
+ &flt_idx);
+ if (err)
+ netdev_dbg(aq_nic->ndev,
+ "UDPv6 filter prepare failed\n");
+
+ aq_ptp_fill_udpv4_mc(fsp, rx_queue,
+ cpu_to_be32(PTP_IPV4_MC_ADDR2));
+ err = aq_ptp_add_a2_filter(aq_ptp, fsp,
+ &flt_idx);
+ if (err)
+ netdev_dbg(aq_nic->ndev,
+ "UDPv4 filter prepare failed\n");
+ }
+ }
+
+ if (enable_flags & AQ_HW_PTP_L2_ENABLE) {
+ aq_ptp->eth_type_filter.ethertype = ETH_P_1588;
+ aq_ptp->eth_type_filter.queue = rx_queue;
+ }
+
+ if (hw_ops->hw_filter_l3l4_set) {
+ for (i = 0; i < flt_idx; i++) {
+ err = hw_ops->hw_filter_l3l4_set(aq_nic->aq_hw,
+ &aq_ptp->udp_filter[i]);
+
+ if (!err) {
+ netdev_dbg(aq_nic->ndev,
+ "Set UDP filter complete. Location: %x\n",
+ aq_ptp->udp_filter[i].location);
+ } else {
+ netdev_dbg(aq_nic->ndev, "Set UDP filter failed\n");
+ break;
+ }
+ }
+ }
+
+ if (!err && hw_ops->hw_filter_l2_set) {
+ err = hw_ops->hw_filter_l2_set(aq_nic->aq_hw,
+ &aq_ptp->eth_type_filter);
+
+ if (!err)
+ netdev_dbg(aq_nic->ndev,
+ "Set L2 filter complete. Location: %d\n",
+ aq_ptp->eth_type_filter.location);
+ }
+ } else {
+ /* PTP disabled, clear all UDP/L2 filters */
+ for (i = 0; i < PTP_UDP_FILTERS_CNT; i++) {
+ aq_ptp->udp_filter[i].cmd &=
+ ~HW_ATL_RX_ENABLE_FLTR_L3L4;
+ if (hw_ops->hw_filter_l3l4_set) {
+ err = hw_ops->hw_filter_l3l4_set(aq_nic->aq_hw,
+ &aq_ptp->udp_filter[i]);
+ if (err)
+ netdev_dbg(aq_nic->ndev,
+ "Set UDP filter failed\n");
+ }
+ }
+
+ if (!err && hw_ops->hw_filter_l2_clear)
+ err = hw_ops->hw_filter_l2_clear(aq_nic->aq_hw,
+ &aq_ptp->eth_type_filter);
+ }
+
+ return err;
+}
+
/* aq_ptp_rx_hwtstamp - utility function which checks for RX time stamp
* @adapter: pointer to adapter struct
* @shhwtstamps: particular skb_shared_hwtstamps to save timestamp
@@ -572,53 +770,53 @@ void aq_ptp_hwtstamp_config_get(struct aq_ptp_s *aq_ptp,
*config = aq_ptp->hwtstamp_config;
}
-static void aq_ptp_prepare_filters(struct aq_ptp_s *aq_ptp)
+static unsigned int aq_ptp_parse_rx_filters(enum hwtstamp_rx_filters rx_filter)
{
- aq_ptp->udp_filter.cmd = HW_ATL_RX_ENABLE_FLTR_L3L4 |
- HW_ATL_RX_ENABLE_CMP_PROT_L4 |
- HW_ATL_RX_UDP |
- HW_ATL_RX_ENABLE_CMP_DEST_PORT_L4 |
- HW_ATL_RX_HOST << HW_ATL_RX_ACTION_FL3F4_SHIFT |
- HW_ATL_RX_ENABLE_QUEUE_L3L4 |
- aq_ptp->ptp_rx.idx << HW_ATL_RX_QUEUE_FL3L4_SHIFT;
- aq_ptp->udp_filter.p_dst = PTP_EV_PORT;
-
- aq_ptp->eth_type_filter.ethertype = ETH_P_1588;
- aq_ptp->eth_type_filter.queue = aq_ptp->ptp_rx.idx;
+ unsigned int ptp_en_flags = AQ_HW_PTP_DISABLE;
+
+ switch (rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ ptp_en_flags = AQ_HW_PTP_L2_ENABLE;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ ptp_en_flags = AQ_HW_PTP_L4_ENABLE;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ case HWTSTAMP_FILTER_ALL:
+ default:
+ ptp_en_flags = AQ_HW_PTP_L4_ENABLE | AQ_HW_PTP_L2_ENABLE;
+ break;
+ }
+ return ptp_en_flags;
}
int aq_ptp_hwtstamp_config_set(struct aq_ptp_s *aq_ptp,
struct kernel_hwtstamp_config *config)
{
+ unsigned int ptp_en_flags = aq_ptp_parse_rx_filters(config->rx_filter);
struct aq_nic_s *aq_nic = aq_ptp->aq_nic;
- const struct aq_hw_ops *hw_ops;
int err = 0;
- hw_ops = aq_nic->aq_hw_ops;
- if (config->tx_type == HWTSTAMP_TX_ON ||
- config->rx_filter == HWTSTAMP_FILTER_PTP_V2_EVENT) {
- aq_ptp_prepare_filters(aq_ptp);
- if (hw_ops->hw_filter_l3l4_set) {
- err = hw_ops->hw_filter_l3l4_set(aq_nic->aq_hw,
- &aq_ptp->udp_filter);
- }
- if (!err && hw_ops->hw_filter_l2_set) {
- err = hw_ops->hw_filter_l2_set(aq_nic->aq_hw,
- &aq_ptp->eth_type_filter);
- }
+ if (aq_ptp->hwtstamp_config.rx_filter != config->rx_filter)
+ err = aq_ptp_dpath_enable(aq_ptp,
+ ptp_en_flags,
+ aq_ptp->ptp_rx.idx);
+
+ if (ptp_en_flags != AQ_HW_PTP_DISABLE)
aq_utils_obj_set(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP);
- } else {
- aq_ptp->udp_filter.cmd &= ~HW_ATL_RX_ENABLE_FLTR_L3L4;
- if (hw_ops->hw_filter_l3l4_set) {
- err = hw_ops->hw_filter_l3l4_set(aq_nic->aq_hw,
- &aq_ptp->udp_filter);
- }
- if (!err && hw_ops->hw_filter_l2_clear) {
- err = hw_ops->hw_filter_l2_clear(aq_nic->aq_hw,
- &aq_ptp->eth_type_filter);
- }
+ else
aq_utils_obj_clear(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP);
- }
if (err)
return -EREMOTEIO;
@@ -673,21 +871,23 @@ static int aq_ptp_poll(struct napi_struct *napi, int budget)
was_cleaned = true;
}
- /* Processing HW_TIMESTAMP RX traffic */
- err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_receive(aq_nic->aq_hw,
- &aq_ptp->hwts_rx);
- if (err < 0)
- goto err_exit;
-
- if (aq_ptp->hwts_rx.sw_head != aq_ptp->hwts_rx.hw_head) {
- aq_ring_hwts_rx_clean(&aq_ptp->hwts_rx, aq_nic);
-
- err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_fill(aq_nic->aq_hw,
- &aq_ptp->hwts_rx);
+ if (aq_ptp->a1_ptp) {
+ /* Processing HW_TIMESTAMP RX traffic */
+ err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_receive(aq_nic->aq_hw,
+ &aq_ptp->hwts_rx);
if (err < 0)
goto err_exit;
- was_cleaned = true;
+ if (aq_ptp->hwts_rx.sw_head != aq_ptp->hwts_rx.hw_head) {
+ aq_ring_hwts_rx_clean(&aq_ptp->hwts_rx, aq_nic);
+
+ err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_fill(aq_nic->aq_hw,
+ &aq_ptp->hwts_rx);
+ if (err < 0)
+ goto err_exit;
+
+ was_cleaned = true;
+ }
}
/* Processing PTP RX traffic */
@@ -818,7 +1018,7 @@ int aq_ptp_irq_alloc(struct aq_nic_s *aq_nic)
return 0;
if (pdev->msix_enabled || pdev->msi_enabled) {
- err = request_irq(pci_irq_vector(pdev, aq_ptp->idx_vector),
+ err = request_irq(pci_irq_vector(pdev, aq_ptp->idx_ptp_vector),
aq_ptp_isr, 0, aq_nic->ndev->name, aq_ptp);
} else {
err = -EINVAL;
@@ -837,7 +1037,7 @@ void aq_ptp_irq_free(struct aq_nic_s *aq_nic)
if (!aq_ptp)
return;
- free_irq(pci_irq_vector(pdev, aq_ptp->idx_vector), aq_ptp);
+ free_irq(pci_irq_vector(pdev, aq_ptp->idx_ptp_vector), aq_ptp);
}
int aq_ptp_ring_init(struct aq_nic_s *aq_nic)
@@ -875,6 +1075,9 @@ int aq_ptp_ring_init(struct aq_nic_s *aq_nic)
if (err < 0)
goto err_rx_free;
+ if (aq_ptp->a2_ptp)
+ return 0;
+
err = aq_ring_init(&aq_ptp->hwts_rx, ATL_RING_RX);
if (err < 0)
goto err_rx_free;
@@ -912,10 +1115,12 @@ int aq_ptp_ring_start(struct aq_nic_s *aq_nic)
if (err < 0)
goto err_exit;
- err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw,
- &aq_ptp->hwts_rx);
- if (err < 0)
- goto err_exit;
+ if (aq_ptp->a1_ptp) {
+ err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw,
+ &aq_ptp->hwts_rx);
+ if (err < 0)
+ goto err_exit;
+ }
napi_enable(&aq_ptp->napi);
@@ -933,7 +1138,9 @@ void aq_ptp_ring_stop(struct aq_nic_s *aq_nic)
aq_nic->aq_hw_ops->hw_ring_tx_stop(aq_nic->aq_hw, &aq_ptp->ptp_tx);
aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->ptp_rx);
- aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->hwts_rx);
+ if (aq_ptp->a1_ptp)
+ aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw,
+ &aq_ptp->hwts_rx);
napi_disable(&aq_ptp->napi);
}
@@ -972,11 +1179,13 @@ int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
if (err)
goto err_exit_ptp_tx;
- err = aq_ring_hwts_rx_alloc(&aq_ptp->hwts_rx, aq_nic, PTP_HWST_RING_IDX,
- aq_nic->aq_nic_cfg.rxds,
- aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size);
- if (err)
- goto err_exit_ptp_rx;
+ if (aq_ptp->a1_ptp) {
+ err = aq_ring_hwts_rx_alloc(&aq_ptp->hwts_rx, aq_nic, PTP_HWST_RING_IDX,
+ aq_nic->aq_nic_cfg.rxds,
+ aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size);
+ if (err)
+ goto err_exit_ptp_rx;
+ }
err = aq_ptp_skb_ring_init(&aq_ptp->skb_ring, aq_nic->aq_nic_cfg.rxds);
if (err != 0) {
@@ -984,7 +1193,7 @@ int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
goto err_exit_hwts_rx;
}
- aq_ptp->ptp_ring_param.vec_idx = aq_ptp->idx_vector;
+ aq_ptp->ptp_ring_param.vec_idx = aq_ptp->idx_ptp_vector;
aq_ptp->ptp_ring_param.cpu = aq_ptp->ptp_ring_param.vec_idx +
aq_nic_get_cfg(aq_nic)->aq_rss.base_cpu_number;
cpumask_set_cpu(aq_ptp->ptp_ring_param.cpu,
@@ -993,7 +1202,8 @@ int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
return 0;
err_exit_hwts_rx:
- aq_ring_hwts_rx_free(&aq_ptp->hwts_rx);
+ if (aq_ptp->a1_ptp)
+ aq_ring_free(&aq_ptp->hwts_rx);
err_exit_ptp_rx:
aq_ring_free(&aq_ptp->ptp_rx);
err_exit_ptp_tx:
@@ -1011,7 +1221,8 @@ void aq_ptp_ring_free(struct aq_nic_s *aq_nic)
aq_ring_free(&aq_ptp->ptp_tx);
aq_ring_free(&aq_ptp->ptp_rx);
- aq_ring_hwts_rx_free(&aq_ptp->hwts_rx);
+ if (aq_ptp->a1_ptp)
+ aq_ring_hwts_rx_free(&aq_ptp->hwts_rx);
aq_ptp_skb_ring_release(&aq_ptp->skb_ring);
}
@@ -1035,46 +1246,49 @@ static struct ptp_clock_info aq_ptp_clock = {
.pin_config = NULL,
};
-#define ptp_offset_init(__idx, __mbps, __egress, __ingress) do { \
- ptp_offset[__idx].mbps = (__mbps); \
- ptp_offset[__idx].egress = (__egress); \
- ptp_offset[__idx].ingress = (__ingress); } \
- while (0)
+static inline void ptp_offset_init(struct aq_ptp_s *aq_ptp, int idx,
+ unsigned int mbps, int egress, int ingress)
+{
+ aq_ptp->ptp_offset[idx].mbps = mbps;
+ aq_ptp->ptp_offset[idx].egress = egress;
+ aq_ptp->ptp_offset[idx].ingress = ingress;
+}
-static void aq_ptp_offset_init_from_fw(const struct hw_atl_ptp_offset *offsets)
+static void aq_ptp_offset_init_from_fw(struct aq_ptp_s *aq_ptp,
+ const struct hw_atl_ptp_offset *offsets)
{
int i;
/* Load offsets for PTP */
- for (i = 0; i < ARRAY_SIZE(ptp_offset); i++) {
+ for (i = 0; i < ARRAY_SIZE(aq_ptp->ptp_offset); i++) {
switch (i) {
/* 100M */
case ptp_offset_idx_100:
- ptp_offset_init(i, 100,
+ ptp_offset_init(aq_ptp, i, 100,
offsets->egress_100,
offsets->ingress_100);
break;
/* 1G */
case ptp_offset_idx_1000:
- ptp_offset_init(i, 1000,
+ ptp_offset_init(aq_ptp, i, 1000,
offsets->egress_1000,
offsets->ingress_1000);
break;
/* 2.5G */
case ptp_offset_idx_2500:
- ptp_offset_init(i, 2500,
+ ptp_offset_init(aq_ptp, i, 2500,
offsets->egress_2500,
offsets->ingress_2500);
break;
/* 5G */
case ptp_offset_idx_5000:
- ptp_offset_init(i, 5000,
+ ptp_offset_init(aq_ptp, i, 5000,
offsets->egress_5000,
offsets->ingress_5000);
break;
/* 10G */
case ptp_offset_idx_10000:
- ptp_offset_init(i, 10000,
+ ptp_offset_init(aq_ptp, i, 10000,
offsets->egress_10000,
offsets->ingress_10000);
break;
@@ -1082,11 +1296,12 @@ static void aq_ptp_offset_init_from_fw(const struct hw_atl_ptp_offset *offsets)
}
}
-static void aq_ptp_offset_init(const struct hw_atl_ptp_offset *offsets)
+static void aq_ptp_offset_init(struct aq_ptp_s *aq_ptp,
+ const struct hw_atl_ptp_offset *offsets)
{
- memset(ptp_offset, 0, sizeof(ptp_offset));
+ memset(aq_ptp->ptp_offset, 0, sizeof(aq_ptp->ptp_offset));
- aq_ptp_offset_init_from_fw(offsets);
+ aq_ptp_offset_init_from_fw(aq_ptp, offsets);
}
static void aq_ptp_gpio_init(struct ptp_clock_info *info,
@@ -1139,26 +1354,43 @@ static void aq_ptp_gpio_init(struct ptp_clock_info *info,
sizeof(struct ptp_pin_desc) * info->n_pins);
}
-void aq_ptp_clock_init(struct aq_nic_s *aq_nic)
+void aq_ptp_clock_init(struct aq_nic_s *aq_nic, enum aq_ptp_state state)
{
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
- struct timespec64 ts;
- ktime_get_real_ts64(&ts);
- aq_ptp_settime(&aq_ptp->ptp_info, &ts);
+ if (!aq_ptp)
+ return;
+
+ if (aq_ptp->a1_ptp || state == AQ_PTP_FIRST_INIT) {
+ struct timespec64 ts;
+
+ ktime_get_real_ts64(&ts);
+ aq_ptp_settime(&aq_ptp->ptp_info, &ts);
+ }
+
+ if (!aq_ptp->a1_ptp && state != AQ_PTP_FIRST_INIT) {
+ unsigned int ptp_en_flags =
+ aq_ptp_parse_rx_filters(state == AQ_PTP_LINK_UP ?
+ aq_ptp->hwtstamp_config.rx_filter :
+ AQ_HW_PTP_DISABLE);
+
+ aq_ptp_dpath_enable(aq_ptp, ptp_en_flags, aq_ptp->ptp_rx.idx);
+ }
}
static void aq_ptp_poll_sync_work_cb(struct work_struct *w);
-int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
+int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_ptp_vec)
{
bool a1_ptp = ATL_HW_IS_CHIP_FEATURE(aq_nic->aq_hw, ATLANTIC);
+ bool a2_ptp = ATL_HW_IS_CHIP_FEATURE(aq_nic->aq_hw, ANTIGUA);
struct hw_atl_utils_mbox mbox;
struct ptp_clock *clock;
- struct aq_ptp_s *aq_ptp;
+ struct aq_ptp_s *aq_ptp = NULL;
int err = 0;
+ int i;
- if (!a1_ptp) {
+ if (!a1_ptp && !a2_ptp) {
aq_nic->aq_ptp = NULL;
return 0;
}
@@ -1168,19 +1400,43 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
return 0;
}
- if (!aq_nic->aq_fw_ops->enable_ptp) {
- aq_nic->aq_ptp = NULL;
- return 0;
+ if (a1_ptp) {
+ if (!aq_nic->aq_fw_ops->enable_ptp) {
+ aq_nic->aq_ptp = NULL;
+ return 0;
+ }
}
- hw_atl_utils_mpi_read_stats(aq_nic->aq_hw, &mbox);
-
- if (!(mbox.info.caps_ex & BIT(CAPS_EX_PHY_PTP_EN))) {
+ /* PTP requires at least 1 free irq vector for itself */
+ if (aq_nic->irqvecs <= AQ_HW_PTP_IRQS) {
+ netdev_warn(aq_nic->ndev,
+ "Disabling PTP due to insufficient number of available IRQ vectors.\n");
aq_nic->aq_ptp = NULL;
return 0;
}
- aq_ptp_offset_init(&mbox.info.ptp_offset);
+ if (a1_ptp) {
+ hw_atl_utils_mpi_read_stats(aq_nic->aq_hw, &mbox);
+ if (!(mbox.info.caps_ex & BIT(CAPS_EX_PHY_PTP_EN))) {
+ aq_nic->aq_ptp = NULL;
+ return 0;
+ }
+ } else {
+ memset(&mbox, 0, sizeof(mbox));
+
+ if (a2_ptp) {
+ mbox.info.ptp_offset.ingress_100 = HW_ATL2_PTP_OFFSET_INGRESS_100;
+ mbox.info.ptp_offset.egress_100 = HW_ATL2_PTP_OFFSET_EGRESS_100;
+ mbox.info.ptp_offset.ingress_1000 = HW_ATL2_PTP_OFFSET_INGRESS_1000;
+ mbox.info.ptp_offset.egress_1000 = HW_ATL2_PTP_OFFSET_EGRESS_1000;
+ mbox.info.ptp_offset.ingress_2500 = HW_ATL2_PTP_OFFSET_INGRESS_2500;
+ mbox.info.ptp_offset.egress_2500 = HW_ATL2_PTP_OFFSET_EGRESS_2500;
+ mbox.info.ptp_offset.ingress_5000 = HW_ATL2_PTP_OFFSET_INGRESS_5000;
+ mbox.info.ptp_offset.egress_5000 = HW_ATL2_PTP_OFFSET_EGRESS_5000;
+ mbox.info.ptp_offset.ingress_10000 = HW_ATL2_PTP_OFFSET_INGRESS_10000;
+ mbox.info.ptp_offset.egress_10000 = HW_ATL2_PTP_OFFSET_EGRESS_10000;
+ }
+ }
aq_ptp = kzalloc_obj(*aq_ptp);
if (!aq_ptp) {
@@ -1190,10 +1446,12 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
aq_ptp->aq_nic = aq_nic;
aq_ptp->a1_ptp = a1_ptp;
+ aq_ptp->a2_ptp = a2_ptp;
spin_lock_init(&aq_ptp->ptp_lock);
spin_lock_init(&aq_ptp->ptp_ring_lock);
+ aq_ptp_offset_init(aq_ptp, &mbox.info.ptp_offset);
aq_ptp->ptp_info = aq_ptp_clock;
aq_ptp_gpio_init(&aq_ptp->ptp_info, &mbox.info);
clock = ptp_clock_register(&aq_ptp->ptp_info, &aq_nic->ndev->dev);
@@ -1210,22 +1468,34 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
netif_napi_add(aq_nic_get_ndev(aq_nic), &aq_ptp->napi, aq_ptp_poll);
- aq_ptp->idx_vector = idx_vec;
+ aq_ptp->idx_ptp_vector = idx_ptp_vec;
aq_nic->aq_ptp = aq_ptp;
/* enable ptp counter */
+ aq_ptp->ptp_clock_sel = ATL_TSG_CLOCK_SEL_0;
aq_utils_obj_set(&aq_nic->aq_hw->flags, AQ_HW_PTP_AVAILABLE);
- mutex_lock(&aq_nic->fwreq_mutex);
- aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 1);
- aq_ptp_clock_init(aq_nic);
- mutex_unlock(&aq_nic->fwreq_mutex);
+ if (a1_ptp) {
+ mutex_lock(&aq_nic->fwreq_mutex);
+ aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 1);
+ mutex_unlock(&aq_nic->fwreq_mutex);
+ }
+ if (a2_ptp)
+ aq_nic->aq_hw_ops->enable_ptp(aq_nic->aq_hw, aq_ptp->ptp_clock_sel, 1);
INIT_DELAYED_WORK(&aq_ptp->poll_sync, &aq_ptp_poll_sync_work_cb);
aq_ptp->eth_type_filter.location =
- aq_nic_reserve_filter(aq_nic, aq_rx_filter_ethertype);
- aq_ptp->udp_filter.location =
+ aq_nic_reserve_filter(aq_nic, aq_rx_filter_ethertype);
+
+ for (i = 0; i < PTP_UDP_FILTERS_CNT; i++) {
+ aq_ptp->udp_filter[i].location =
aq_nic_reserve_filter(aq_nic, aq_rx_filter_l3l4);
+ }
+
+ aq_ptp_clock_init(aq_nic, AQ_PTP_FIRST_INIT);
+ netdev_info(aq_nic->ndev,
+ "Enable PTP Support. %d GPIO(s)\n",
+ aq_ptp->ptp_info.n_pins);
return 0;
@@ -1244,30 +1514,45 @@ void aq_ptp_unregister(struct aq_nic_s *aq_nic)
if (!aq_ptp)
return;
- ptp_clock_unregister(aq_ptp->ptp_clock);
+ if (aq_ptp->ptp_clock) {
+ ptp_clock_unregister(aq_ptp->ptp_clock);
+ aq_ptp->ptp_clock = NULL;
+ }
}
void aq_ptp_free(struct aq_nic_s *aq_nic)
{
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
+ int i;
if (!aq_ptp)
return;
+ /* disable ptp */
+ if (aq_ptp->a1_ptp) {
+ mutex_lock(&aq_nic->fwreq_mutex);
+ aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 0);
+ mutex_unlock(&aq_nic->fwreq_mutex);
+ }
+
+ if (aq_ptp->a2_ptp)
+ aq_nic->aq_hw_ops->enable_ptp(aq_nic->aq_hw,
+ aq_ptp->ptp_clock_sel, 0);
+
+ cancel_delayed_work_sync(&aq_ptp->poll_sync);
+
aq_nic_release_filter(aq_nic, aq_rx_filter_ethertype,
aq_ptp->eth_type_filter.location);
- aq_nic_release_filter(aq_nic, aq_rx_filter_l3l4,
- aq_ptp->udp_filter.location);
- cancel_delayed_work_sync(&aq_ptp->poll_sync);
- /* disable ptp */
- mutex_lock(&aq_nic->fwreq_mutex);
- aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 0);
- mutex_unlock(&aq_nic->fwreq_mutex);
+ for (i = 0; i < PTP_UDP_FILTERS_CNT; i++)
+ aq_nic_release_filter(aq_nic, aq_rx_filter_l3l4,
+ aq_ptp->udp_filter[i].location);
kfree(aq_ptp->ptp_info.pin_config);
+ aq_ptp->ptp_info.pin_config = NULL;
netif_napi_del(&aq_ptp->napi);
kfree(aq_ptp);
+ aq_utils_obj_clear(&aq_nic->aq_hw->flags, AQ_HW_PTP_AVAILABLE);
aq_nic->aq_ptp = NULL;
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
index 5e643ec7cc06..df93857deac9 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
@@ -14,6 +14,12 @@
#include "aq_ring.h"
+enum aq_ptp_state {
+ AQ_PTP_NO_LINK = 0,
+ AQ_PTP_FIRST_INIT = 1,
+ AQ_PTP_LINK_UP = 2,
+};
+
#define PTP_8TC_RING_IDX 8
#define PTP_4TC_RING_IDX 16
#define PTP_HWST_RING_IDX 31
@@ -32,7 +38,7 @@ static inline unsigned int aq_ptp_ring_idx(const enum aq_tc_mode tc_mode)
#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
/* Common functions */
-int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec);
+int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_ptp_vec);
void aq_ptp_unregister(struct aq_nic_s *aq_nic);
void aq_ptp_free(struct aq_nic_s *aq_nic);
@@ -52,7 +58,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_clock_init(struct aq_nic_s *aq_nic, enum aq_ptp_state state);
/* Traffic processing functions */
int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb);
@@ -80,7 +86,7 @@ u64 *aq_ptp_get_stats(struct aq_nic_s *aq_nic, u64 *data);
#else
-static inline int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
+static inline int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_ptp_vec)
{
return 0;
}
@@ -122,7 +128,8 @@ static inline void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic) {}
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_clock_init(struct aq_nic_s *aq_nic,
+ enum aq_ptp_state state) {}
static inline int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb)
{
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index e270327e47fd..a52d6d3fe464 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -308,24 +308,30 @@ bool aq_ring_tx_clean(struct aq_ring_s *self)
}
}
- if (likely(!buff->is_eop))
- goto out;
-
- if (buff->skb) {
- u64_stats_update_begin(&self->stats.tx.syncp);
- ++self->stats.tx.packets;
- self->stats.tx.bytes += buff->skb->len;
- u64_stats_update_end(&self->stats.tx.syncp);
- dev_kfree_skb_any(buff->skb);
- } else if (buff->xdpf) {
- u64_stats_update_begin(&self->stats.tx.syncp);
- ++self->stats.tx.packets;
- self->stats.tx.bytes += xdp_get_frame_len(buff->xdpf);
- u64_stats_update_end(&self->stats.tx.syncp);
- xdp_return_frame_rx_napi(buff->xdpf);
- }
+ if (unlikely(buff->is_eop)) {
+ 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)
+ break;
-out:
+ aq_ptp_tx_hwtstamp(self->aq_nic, ts);
+ }
+ if (buff->skb) {
+ u64_stats_update_begin(&self->stats.tx.syncp);
+ ++self->stats.tx.packets;
+ self->stats.tx.bytes += buff->skb->len;
+ u64_stats_update_end(&self->stats.tx.syncp);
+ dev_kfree_skb_any(buff->skb);
+ } else if (buff->xdpf) {
+ u64_stats_update_begin(&self->stats.tx.syncp);
+ ++self->stats.tx.packets;
+ self->stats.tx.bytes += xdp_get_frame_len(buff->xdpf);
+ u64_stats_update_end(&self->stats.tx.syncp);
+ xdp_return_frame_rx_napi(buff->xdpf);
+ }
+ }
buff->skb = NULL;
buff->xdpf = NULL;
buff->pa = 0U;
@@ -570,7 +576,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;
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
index c71e8d1adfc9..3047bda619c0 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
@@ -7,6 +7,7 @@
#include "aq_hw_utils.h"
#include "aq_ring.h"
#include "aq_nic.h"
+#include "aq_ptp.h"
#include "hw_atl/hw_atl_b0.h"
#include "hw_atl/hw_atl_utils.h"
#include "hw_atl/hw_atl_llh.h"
@@ -20,6 +21,15 @@
static int hw_atl2_act_rslvr_table_set(struct aq_hw_s *self, u8 location,
u32 tag, u32 mask, u32 action);
+static void hw_atl2_enable_ptp(struct aq_hw_s *self,
+ unsigned int param, int enable);
+static int hw_atl2_hw_tx_ptp_ring_init(struct aq_hw_s *self,
+ struct aq_ring_s *aq_ring);
+static int hw_atl2_hw_rx_ptp_ring_init(struct aq_hw_s *self,
+ struct aq_ring_s *aq_ring);
+static void aq_get_ptp_ts(struct aq_hw_s *self, u64 *stamp);
+static int hw_atl2_adj_clock_freq(struct aq_hw_s *self, s32 ppb);
+
#define DEFAULT_BOARD_BASIC_CAPABILITIES \
.is_64_dma = true, \
.op64bit = true, \
@@ -144,6 +154,12 @@ static int hw_atl2_hw_reset(struct aq_hw_s *self)
priv->l3l4_filters[i].l4_index = -1;
}
+ if (self->clk_select != -1)
+ hw_atl2_enable_ptp(self,
+ self->clk_select,
+ aq_utils_obj_test(&self->flags, AQ_HW_PTP_AVAILABLE) ?
+ 1 : 0);
+
self->aq_fw_ops->set_state(self, MPI_RESET);
err = aq_hw_err_from_flags(self);
@@ -719,14 +735,24 @@ static int hw_atl2_hw_ring_rx_init(struct aq_hw_s *self,
struct aq_ring_s *aq_ring,
struct aq_ring_param_s *aq_ring_param)
{
- return hw_atl_b0_hw_ring_rx_init(self, aq_ring, aq_ring_param);
+ int res = hw_atl_b0_hw_ring_rx_init(self, aq_ring, aq_ring_param);
+
+ if (aq_ptp_ring(aq_ring->aq_nic, aq_ring))
+ hw_atl2_hw_rx_ptp_ring_init(self, aq_ring);
+
+ return res;
}
static int hw_atl2_hw_ring_tx_init(struct aq_hw_s *self,
struct aq_ring_s *aq_ring,
struct aq_ring_param_s *aq_ring_param)
{
- return hw_atl_b0_hw_ring_tx_init(self, aq_ring, aq_ring_param);
+ int res = hw_atl_b0_hw_ring_tx_init(self, aq_ring, aq_ring_param);
+
+ if (aq_ptp_ring(aq_ring->aq_nic, aq_ring))
+ hw_atl2_hw_tx_ptp_ring_init(self, aq_ring);
+
+ return res;
}
#define IS_FILTER_ENABLED(_F_) ((packet_filter & (_F_)) ? 1U : 0U)
@@ -886,6 +912,138 @@ static struct aq_stats_s *hw_atl2_utils_get_hw_stats(struct aq_hw_s *self)
return &self->curr_stats;
}
+static u32 hw_atl2_tsg_int_clk_freq(struct aq_hw_s *self)
+{
+ return AQ2_HW_PTP_COUNTER_HZ;
+}
+
+static void hw_atl2_enable_ptp(struct aq_hw_s *self,
+ unsigned int param, int enable)
+{
+ self->clk_select = param;
+
+ /* enable tsg counter */
+ hw_atl2_tsg_clock_reset(self, self->clk_select);
+ hw_atl2_tsg_clock_en(self, !self->clk_select, enable);
+ hw_atl2_tsg_clock_en(self, self->clk_select, enable);
+
+ if (enable)
+ hw_atl2_adj_clock_freq(self, 0);
+
+ hw_atl2_tpb_tps_highest_priority_tc_enable_set(self, enable);
+}
+
+static void aq_get_ptp_ts(struct aq_hw_s *self, u64 *stamp)
+{
+ if (stamp)
+ *stamp = hw_atl2_tsg_clock_read(self, self->clk_select);
+}
+
+static u64 hw_atl2_hw_ring_tx_ptp_get_ts(struct aq_ring_s *ring)
+{
+ struct hw_atl2_txts_s *txts;
+
+ txts = (struct hw_atl2_txts_s *)&ring->dx_ring[ring->sw_head *
+ HW_ATL2_TXD_SIZE];
+ /* DD + TS_VALID */
+ if ((txts->ctrl & HW_ATL2_TXTS_DD) && (txts->ctrl & HW_ATL2_TXTS_TS_VALID))
+ return txts->ts;
+
+ return 0;
+}
+
+static u16 hw_atl2_hw_rx_extract_ts(struct aq_hw_s *self, u8 *p,
+ unsigned int len, u64 *timestamp)
+{
+ unsigned int offset = HW_ATL2_RX_TS_SIZE;
+ u8 *ptr;
+
+ if (len <= offset || !timestamp)
+ return 0;
+
+ ptr = p + (len - offset);
+ memcpy(timestamp, ptr, sizeof(*timestamp));
+
+ return HW_ATL2_RX_TS_SIZE;
+}
+
+static int hw_atl2_adj_sys_clock(struct aq_hw_s *self, s64 delta)
+{
+ if (delta >= 0)
+ hw_atl2_tsg_clock_add(self, self->clk_select, (u64)delta);
+ else
+ hw_atl2_tsg_clock_sub(self, self->clk_select, (u64)(-delta));
+
+ return 0;
+}
+
+static int hw_atl2_adj_clock_freq(struct aq_hw_s *self, s32 ppb)
+{
+ u32 freq = hw_atl2_tsg_int_clk_freq(self);
+ u64 divisor = 0, base_ns;
+ u32 nsi_frac = 0, nsi;
+ u32 nsi_rem;
+
+ base_ns = div_u64((u64)((s64)ppb + NSEC_PER_SEC) * NSEC_PER_SEC, freq);
+ nsi = (u32)div_u64_rem(base_ns, NSEC_PER_SEC, &nsi_rem);
+ if (nsi_rem != 0) {
+ divisor = div_u64(mul_u32_u32(NSEC_PER_SEC, NSEC_PER_SEC),
+ nsi_rem);
+ nsi_frac = (u32)div64_u64(AQ_FRAC_PER_NS * NSEC_PER_SEC,
+ divisor);
+ }
+
+ hw_atl2_tsg_clock_increment_set(self, self->clk_select, nsi, nsi_frac);
+
+ return 0;
+}
+
+static int hw_atl2_hw_tx_ptp_ring_init(struct aq_hw_s *self,
+ struct aq_ring_s *aq_ring)
+{
+ hw_atl2_tdm_tx_desc_timestamp_writeback_en_set(self, true,
+ aq_ring->idx);
+ hw_atl2_tdm_tx_desc_timestamp_en_set(self, true, aq_ring->idx);
+ hw_atl2_tdm_tx_desc_avb_en_set(self, true, aq_ring->idx);
+
+ return aq_hw_err_from_flags(self);
+}
+
+static int hw_atl2_hw_rx_ptp_ring_init(struct aq_hw_s *self,
+ struct aq_ring_s *aq_ring)
+{
+ hw_atl2_rpf_rx_desc_timestamp_req_set(self,
+ self->clk_select == ATL_TSG_CLOCK_SEL_1 ? 2 : 1,
+ aq_ring->idx);
+ return aq_hw_err_from_flags(self);
+}
+
+static u32 hw_atl2_hw_get_clk_sel(struct aq_hw_s *self)
+{
+ return self->clk_select;
+}
+
+static int hw_atl2_gpio_pulse(struct aq_hw_s *self, u32 index, u32 clk_sel,
+ u64 start, u32 period, u32 hightime)
+{
+ u32 mode;
+
+ if (start == 0)
+ mode = HW_ATL2_GPIO_PIN_SPEC_MODE_GPIO;
+ else if (clk_sel == ATL_TSG_CLOCK_SEL_0)
+ mode = HW_ATL2_GPIO_PIN_SPEC_MODE_TSG0_EVENT_OUTPUT;
+ else
+ mode = HW_ATL2_GPIO_PIN_SPEC_MODE_TSG1_EVENT_OUTPUT;
+
+ if (index == 1 || index == 3) { /* Hardware limitation */
+ hw_atl2_gpio_special_mode_set(self, mode, index);
+ }
+
+ hw_atl2_tsg_ptp_gpio_gen_pulse(self, clk_sel, start, period, hightime);
+
+ return 0;
+}
+
static bool hw_atl2_rxf_l3_is_equal(struct hw_atl2_l3_filter *f1,
struct hw_atl2_l3_filter *f2)
{
@@ -1474,4 +1632,21 @@ const struct aq_hw_ops hw_atl2_ops = {
.hw_set_offload = hw_atl_b0_hw_offload_set,
.hw_set_loopback = hw_atl_b0_set_loopback,
.hw_set_fc = hw_atl_b0_set_fc,
+
+ .hw_ring_hwts_rx_fill = NULL,
+ .hw_ring_hwts_rx_receive = NULL,
+
+ .hw_get_ptp_ts = aq_get_ptp_ts,
+ .hw_adj_clock_freq = hw_atl2_adj_clock_freq,
+ .hw_adj_sys_clock = hw_atl2_adj_sys_clock,
+ .hw_gpio_pulse = hw_atl2_gpio_pulse,
+
+ .enable_ptp = hw_atl2_enable_ptp,
+ .hw_ring_tx_ptp_get_ts = hw_atl2_hw_ring_tx_ptp_get_ts,
+ .rx_extract_ts = hw_atl2_hw_rx_extract_ts,
+ .hw_tx_ptp_ring_init = hw_atl2_hw_tx_ptp_ring_init,
+ .hw_rx_ptp_ring_init = hw_atl2_hw_rx_ptp_ring_init,
+ .hw_get_clk_sel = hw_atl2_hw_get_clk_sel,
+ .extract_hwts = NULL,
+ .hw_extts_gpio_enable = NULL,
};
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.h
index 346f0dc9912e..4b905231ae73 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.h
@@ -7,6 +7,18 @@
#define HW_ATL2_H
#include "aq_common.h"
+#define HW_ATL2_RX_TS_SIZE 8
+
+#define HW_ATL2_PTP_OFFSET_INGRESS_100 768
+#define HW_ATL2_PTP_OFFSET_EGRESS_100 336
+#define HW_ATL2_PTP_OFFSET_INGRESS_1000 510
+#define HW_ATL2_PTP_OFFSET_EGRESS_1000 105
+#define HW_ATL2_PTP_OFFSET_INGRESS_2500 2447
+#define HW_ATL2_PTP_OFFSET_EGRESS_2500 634
+#define HW_ATL2_PTP_OFFSET_INGRESS_5000 1426
+#define HW_ATL2_PTP_OFFSET_EGRESS_5000 361
+#define HW_ATL2_PTP_OFFSET_INGRESS_10000 997
+#define HW_ATL2_PTP_OFFSET_EGRESS_10000 203
extern const struct aq_hw_caps_s hw_atl2_caps_aqc113;
extern const struct aq_hw_caps_s hw_atl2_caps_aqc115c;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_internal.h
index 31d7cae6641a..e0687fb4350a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_internal.h
@@ -29,7 +29,8 @@
#define HW_ATL2_TXBUF_MAX 128U
#define HW_ATL2_PTP_TXBUF_SIZE 8U
-#define HW_ATL2_RXBUF_MAX 192U
+/* Reduced from 192 to reserve space for PTP RX timestamp trailer */
+#define HW_ATL2_RXBUF_MAX 172U
#define HW_ATL2_PTP_RXBUF_SIZE 16U
#define HW_ATL2_RSS_REDIRECTION_MAX 64U
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.h
index c84955bc14ae..6a90e6389ebd 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.h
@@ -8,6 +8,16 @@
#include "aq_hw.h"
+/* Hardware tx launch time descriptor */
+struct hw_atl2_txts_s {
+ u64 ts;
+ u32 ctrl;
+ u32 reserved;
+};
+
+#define HW_ATL2_TXTS_DD BIT(3)
+#define HW_ATL2_TXTS_TS_VALID BIT(20)
+
/* F W A P I */
struct link_options_s {
--
2.43.0
next prev parent reply other threads:[~2026-05-06 13:59 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-06 13:56 [PATCH net-next 0/9] net: atlantic: add PTP support for AQC113 (Antigua) sukhdeeps
2026-05-06 13:56 ` [PATCH net-next 1/9] net: atlantic: correct L3L4 filter flow_type masking and IPv6 handling masking and IPv6 handling sukhdeeps
2026-05-06 13:56 ` [PATCH net-next 2/9] net: atlantic: move active_ipv4/ipv6 bitmap updates after HW write updates after HW write sukhdeeps
2026-05-12 9:53 ` Paolo Abeni
2026-05-06 13:57 ` [PATCH net-next 3/9] net: atlantic: decouple aq_set_data_fl3l4() from driver internals driver internals sukhdeeps
2026-05-06 13:57 ` [PATCH net-next 4/9] net: atlantic: add AQC113 hardware register definitions and accessors definitions and accessors sukhdeeps
2026-05-06 13:57 ` [PATCH net-next 5/9] net: atlantic: add AQC113 filter data structures and firmware query and firmware query firmware query sukhdeeps
2026-05-12 9:53 ` Paolo Abeni
2026-05-06 13:57 ` [PATCH net-next 6/9] net: atlantic: implement AQC113 L2/L3/L4 RX filter management filter management management sukhdeeps
2026-05-06 22:43 ` Vadim Fedorenko
2026-05-08 6:56 ` [EXTERNAL] " Sukhdeep Soni [C]
2026-05-12 9:54 ` Paolo Abeni
2026-05-06 13:57 ` [PATCH net-next 7/9] net: atlantic: add AQC113 PTP traffic class and TX path setup TX path setup sukhdeeps
2026-05-12 9:54 ` Paolo Abeni
2026-05-06 13:57 ` [PATCH net-next 8/9] net: atlantic: extend hw_ops and TX descriptor for AQC113 PTP for AQC113 PTP sukhdeeps
2026-05-06 13:57 ` sukhdeeps [this message]
2026-05-12 9:54 ` [PATCH net-next 9/9] net: atlantic: add PTP support for AQC113 (Antigua) (Antigua) Paolo Abeni
2026-05-08 12:01 ` [PATCH net-next v2 0/9] net: atlantic: add PTP support for AQC113 (Antigua) sukhdeeps
2026-05-08 12:01 ` [PATCH net-next v2 1/9] net: atlantic: correct L3L4 filter flow_type masking and IPv6 handling masking and IPv6 handling sukhdeeps
2026-05-08 12:01 ` [PATCH net-next v2 2/9] net: atlantic: move active_ipv4/ipv6 bitmap updates after HW write updates after HW write sukhdeeps
2026-05-08 12:01 ` [PATCH net-next v2 3/9] net: atlantic: decouple aq_set_data_fl3l4() from driver internals driver internals sukhdeeps
2026-05-08 12:01 ` [PATCH net-next v2 4/9] net: atlantic: add AQC113 hardware register definitions and accessors definitions and accessors sukhdeeps
2026-05-08 12:01 ` [PATCH net-next v2 5/9] net: atlantic: add AQC113 filter data structures and firmware query and firmware query firmware query sukhdeeps
2026-05-08 12:01 ` [PATCH net-next v2 6/9] net: atlantic: implement AQC113 L2/L3/L4 RX filter management filter management management sukhdeeps
2026-05-12 10:00 ` Paolo Abeni
2026-05-12 10:04 ` Paolo Abeni
2026-05-08 12:01 ` [PATCH net-next v2 7/9] net: atlantic: add AQC113 PTP traffic class and TX path setup TX path setup sukhdeeps
2026-05-08 12:01 ` [PATCH net-next v2 8/9] net: atlantic: extend hw_ops and TX descriptor for AQC113 PTP for AQC113 PTP sukhdeeps
2026-05-08 12:01 ` [PATCH net-next v2 9/9] net: atlantic: add PTP support for AQC113 (Antigua) (Antigua) sukhdeeps
2026-05-12 10:01 ` Paolo Abeni
2026-05-12 10:17 ` Paolo Abeni
2026-05-08 23:06 ` [PATCH net-next v2 0/9] net: atlantic: add PTP support for AQC113 (Antigua) Jakub Kicinski
2026-05-11 12:26 ` [EXTERNAL] " Sukhdeep Soni [C]
2026-05-11 23:50 ` Jakub Kicinski
2026-05-12 11:27 ` Simon Horman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260506135706.2834-10-sukhdeeps@marvell.com \
--to=sukhdeeps@marvell.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=epomozov@marvell.com \
--cc=irusskikh@marvell.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=richardcochran@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.