net: atlantic: add AQC113 PTP hardware ops in hw_atl2

Add the hardware-layer PTP implementation for AQC113 (Antigua):

- hw_atl2.h/hw_atl2_utils.h/hw_atl2_internal.h: add PTP offset
  constants, RX timestamp size (HW_ATL2_RX_TS_SIZE=8), and reduced
  HW_ATL2_RXBUF_MAX=172 (AQC113 on-chip RX packet buffer hardware
  limit for data TCs).

- hw_atl2.c: implement hw_atl2_enable_ptp() to reset and enable TSG
  clocks and set PTP TC scheduling priority after hardware reset.

- hw_atl2.c: implement hw_atl2_adj_sys_clock(), hw_atl2_adj_clock_freq(),
  and aq_get_ptp_ts() for TSG clock read/adjust/increment operations.

- hw_atl2.c: implement hw_atl2_gpio_pulse() for PPS output generation
  via TSG pulse generator.

- hw_atl2.c: implement hw_atl2_hw_tx_ptp_ring_init() and
  hw_atl2_hw_rx_ptp_ring_init() for PTP ring setup.

- hw_atl2.c: implement hw_atl2_hw_ring_tx_ptp_get_ts() to read TX
  timestamp from descriptor writeback, and hw_atl2_hw_rx_extract_ts()
  to extract RX timestamp from the 8-byte packet trailer.

- hw_atl2.c: add hw_atl2_hw_get_clk_sel() helper.

- Wire all new ops into hw_atl2_ops.

Signed-off-by: Sukhdeep Singh <sukhdeeps@marvell.com>
Link: https://patch.msgid.link/20260610115448.272-11-sukhdeeps@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Sukhdeep Singh
2026-06-10 17:24:46 +05:30
committed by Jakub Kicinski
parent f4f2bfe2b2
commit f6a7a4bcc5
5 changed files with 223 additions and 3 deletions

View File

@@ -250,6 +250,7 @@ static int aq_pci_probe(struct pci_dev *pdev,
goto err_ioremap;
}
self->aq_hw->aq_nic_cfg = aq_nic_get_cfg(self);
self->aq_hw->clk_select = -1;
if (self->aq_hw->aq_nic_cfg->aq_hw_caps->priv_data_len) {
int len = self->aq_hw->aq_nic_cfg->aq_hw_caps->priv_data_len;

View File

@@ -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, \
@@ -127,6 +137,7 @@ static u32 hw_atl2_sem_act_rslvr_get(struct aq_hw_s *self)
static int hw_atl2_hw_reset(struct aq_hw_s *self)
{
struct hw_atl2_priv *priv = self->priv;
s8 clk_sel;
int err;
int i;
@@ -144,6 +155,13 @@ static int hw_atl2_hw_reset(struct aq_hw_s *self)
priv->l3l4_filters[i].l4_index = -1;
}
clk_sel = READ_ONCE(self->clk_select);
if (clk_sel != -1)
hw_atl2_enable_ptp(self,
clk_sel,
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);
@@ -716,14 +734,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 (!res && aq_ptp_ring(aq_ring->aq_nic, aq_ring))
res = 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 (!res && aq_ptp_ring(aq_ring->aq_nic, aq_ring))
res = hw_atl2_hw_tx_ptp_ring_init(self, aq_ring);
return res;
}
#define IS_FILTER_ENABLED(_F_) ((packet_filter & (_F_)) ? 1U : 0U)
@@ -885,6 +913,157 @@ static struct aq_stats_s *hw_atl2_utils_get_hw_stats(struct aq_hw_s *self)
return &self->curr_stats;
}
static void hw_atl2_enable_ptp(struct aq_hw_s *self,
unsigned int param, int enable)
{
s8 sel = (s8)param;
WRITE_ONCE(self->clk_select, sel);
/* enable tsg counter */
hw_atl2_tsg_clock_reset(self, sel);
hw_atl2_tsg_clock_en(self, !sel, enable);
hw_atl2_tsg_clock_en(self, sel, 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)
{
s8 clk_sel = READ_ONCE(self->clk_select);
if (clk_sel < 0) {
if (stamp)
*stamp = 0;
return;
}
if (stamp)
*stamp = hw_atl2_tsg_clock_read(self, clk_sel);
}
static u64 hw_atl2_hw_ring_tx_ptp_get_ts(struct aq_ring_s *ring)
{
struct hw_atl2_txts_s *txts;
u32 ctrl;
txts = (struct hw_atl2_txts_s *)&ring->dx_ring[ring->sw_head *
HW_ATL2_TXD_SIZE];
/* DD + TS_VALID */
ctrl = le32_to_cpu(READ_ONCE(txts->ctrl));
if ((ctrl & HW_ATL2_TXTS_DD) && (ctrl & HW_ATL2_TXTS_TS_VALID)) {
dma_rmb();
return le64_to_cpu(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;
__le64 ts;
u8 *ptr;
if (len <= offset || !timestamp)
return 0;
ptr = p + (len - offset);
memcpy(&ts, ptr, sizeof(ts));
*timestamp = le64_to_cpu(ts);
return HW_ATL2_RX_TS_SIZE;
}
static int hw_atl2_adj_sys_clock(struct aq_hw_s *self, s64 delta)
{
s8 clk_sel = READ_ONCE(self->clk_select);
if (clk_sel < 0)
return -ENODEV;
if (delta >= 0)
hw_atl2_tsg_clock_add(self, clk_sel, (u64)delta);
else
hw_atl2_tsg_clock_sub(self, clk_sel, (u64)(-delta));
return 0;
}
static int hw_atl2_adj_clock_freq(struct aq_hw_s *self, s32 ppb)
{
u32 freq = AQ2_HW_PTP_COUNTER_HZ;
u64 divisor = 0, base_ns;
u32 nsi_frac = 0, nsi;
u32 nsi_rem;
s8 clk_sel;
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);
}
clk_sel = READ_ONCE(self->clk_select);
if (clk_sel < 0)
return -ENODEV;
hw_atl2_tsg_clock_increment_set(self, clk_sel, 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)
{
s8 clk_sel = READ_ONCE(self->clk_select);
hw_atl2_rpf_rx_desc_timestamp_req_set(self,
clk_sel == 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 READ_ONCE(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 (index != 1 && index != 3)
return -EINVAL;
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;
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)
{
@@ -1465,4 +1644,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,
};

View File

@@ -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;

View File

@@ -29,7 +29,8 @@
#define HW_ATL2_TXBUF_MAX 128U
#define HW_ATL2_PTP_TXBUF_SIZE 8U
#define HW_ATL2_RXBUF_MAX 192U
/* hw_atl2 on-chip RX packet buffer available for data TCs */
#define HW_ATL2_RXBUF_MAX 172U
#define HW_ATL2_PTP_RXBUF_SIZE 16U
#define HW_ATL2_RSS_REDIRECTION_MAX 64U

View File

@@ -8,6 +8,16 @@
#include "aq_hw.h"
/* Hardware tx launch time descriptor */
struct hw_atl2_txts_s {
__le64 ts;
__le32 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 {