mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-27 16:49:22 -04:00
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:
committed by
Jakub Kicinski
parent
f4f2bfe2b2
commit
f6a7a4bcc5
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user