diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c index e419c73b32ce..4be7b629bfac 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c @@ -181,6 +181,20 @@ aq_check_approve_fvlan(struct aq_nic_s *aq_nic, return 0; } +static bool aq_is_ipv6_flow_type(const struct ethtool_rx_flow_spec *fsp) +{ + switch (fsp->flow_type & ~FLOW_EXT) { + case TCP_V6_FLOW: + case UDP_V6_FLOW: + case SCTP_V6_FLOW: + case IPV6_FLOW: + case IPV6_USER_FLOW: + return true; + default: + return false; + } +} + static int __must_check aq_check_filter(struct aq_nic_s *aq_nic, struct ethtool_rx_flow_spec *fsp) @@ -466,31 +480,23 @@ static int aq_add_del_fvlan(struct aq_nic_s *aq_nic, return aq_filters_vlans_update(aq_nic); } -static int aq_set_data_fl3l4(struct aq_nic_s *aq_nic, - struct aq_rx_filter *aq_rx_fltr, - struct aq_rx_filter_l3l4 *data, bool add) +int aq_set_data_fl3l4(const struct ethtool_rx_flow_spec *fsp, + struct aq_rx_filter_l3l4 *data, + int location, bool add) { - struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic); - const struct ethtool_rx_flow_spec *fsp = &aq_rx_fltr->aq_fsp; + u32 flow = fsp->flow_type & ~FLOW_EXT; memset(data, 0, sizeof(*data)); - data->is_ipv6 = rx_fltrs->fl3l4.is_ipv6; - data->location = HW_ATL_GET_REG_LOCATION_FL3L4(fsp->location); - - if (!add) { - if (!data->is_ipv6) - rx_fltrs->fl3l4.active_ipv4 &= ~BIT(data->location); - else - rx_fltrs->fl3l4.active_ipv6 &= - ~BIT((data->location) / 4); + data->is_ipv6 = aq_is_ipv6_flow_type(fsp); + data->location = location; + if (!add) return 0; - } data->cmd |= HW_ATL_RX_ENABLE_FLTR_L3L4; - switch (fsp->flow_type) { + switch (flow) { case TCP_V4_FLOW: case TCP_V6_FLOW: data->cmd |= HW_ATL_RX_ENABLE_CMP_PROT_L4; @@ -514,11 +520,9 @@ static int aq_set_data_fl3l4(struct aq_nic_s *aq_nic, ntohl(fsp->h_u.tcp_ip4_spec.ip4src); data->ip_dst[0] = ntohl(fsp->h_u.tcp_ip4_spec.ip4dst); - rx_fltrs->fl3l4.active_ipv4 |= BIT(data->location); } else { int i; - rx_fltrs->fl3l4.active_ipv6 |= BIT((data->location) / 4); for (i = 0; i < HW_ATL_RX_CNT_REG_ADDR_IPV6; ++i) { data->ip_dst[i] = ntohl(fsp->h_u.tcp_ip6_spec.ip6dst[i]); @@ -527,23 +531,23 @@ static int aq_set_data_fl3l4(struct aq_nic_s *aq_nic, } data->cmd |= HW_ATL_RX_ENABLE_L3_IPV6; } - if (fsp->flow_type != IP_USER_FLOW && - fsp->flow_type != IPV6_USER_FLOW) { - if (!data->is_ipv6) { - data->p_dst = - ntohs(fsp->h_u.tcp_ip4_spec.pdst); - data->p_src = - ntohs(fsp->h_u.tcp_ip4_spec.psrc); - } else { - data->p_dst = - ntohs(fsp->h_u.tcp_ip6_spec.pdst); - data->p_src = - ntohs(fsp->h_u.tcp_ip6_spec.psrc); - } + if (flow == TCP_V4_FLOW || flow == UDP_V4_FLOW || + flow == SCTP_V4_FLOW) { + data->p_dst = ntohs(fsp->h_u.tcp_ip4_spec.pdst); + data->p_src = ntohs(fsp->h_u.tcp_ip4_spec.psrc); } - if (data->ip_src[0] && !data->is_ipv6) + if (flow == TCP_V6_FLOW || flow == UDP_V6_FLOW || + flow == SCTP_V6_FLOW) { + data->p_dst = ntohs(fsp->h_u.tcp_ip6_spec.pdst); + data->p_src = ntohs(fsp->h_u.tcp_ip6_spec.psrc); + } + if (data->ip_src[0] || + (data->is_ipv6 && (data->ip_src[1] || data->ip_src[2] || + data->ip_src[3]))) data->cmd |= HW_ATL_RX_ENABLE_CMP_SRC_ADDR_L3; - if (data->ip_dst[0] && !data->is_ipv6) + if (data->ip_dst[0] || + (data->is_ipv6 && (data->ip_dst[1] || data->ip_dst[2] || + data->ip_dst[3]))) data->cmd |= HW_ATL_RX_ENABLE_CMP_DEST_ADDR_L3; if (data->p_dst) data->cmd |= HW_ATL_RX_ENABLE_CMP_DEST_PORT_L4; @@ -573,16 +577,38 @@ static int aq_set_fl3l4(struct aq_hw_s *aq_hw, static int aq_add_del_fl3l4(struct aq_nic_s *aq_nic, struct aq_rx_filter *aq_rx_fltr, bool add) { + struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic); const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops; struct aq_hw_s *aq_hw = aq_nic->aq_hw; struct aq_rx_filter_l3l4 data; + int location; + int err; if (unlikely(aq_rx_fltr->aq_fsp.location < AQ_RX_FIRST_LOC_FL3L4 || - aq_rx_fltr->aq_fsp.location > AQ_RX_LAST_LOC_FL3L4 || - aq_set_data_fl3l4(aq_nic, aq_rx_fltr, &data, add))) + aq_rx_fltr->aq_fsp.location > AQ_RX_LAST_LOC_FL3L4)) return -EINVAL; - return aq_set_fl3l4(aq_hw, aq_hw_ops, &data); + location = HW_ATL_GET_REG_LOCATION_FL3L4(aq_rx_fltr->aq_fsp.location); + + aq_set_data_fl3l4(&aq_rx_fltr->aq_fsp, &data, location, add); + + err = aq_set_fl3l4(aq_hw, aq_hw_ops, &data); + if (err) + return err; + + if (add) { + if (!data.is_ipv6) + rx_fltrs->fl3l4.active_ipv4 |= BIT(data.location); + else + rx_fltrs->fl3l4.active_ipv6 |= BIT(data.location / 4); + } else { + if (!data.is_ipv6) + rx_fltrs->fl3l4.active_ipv4 &= ~BIT(data.location); + else + rx_fltrs->fl3l4.active_ipv6 &= ~BIT(data.location / 4); + } + + return 0; } static int aq_add_del_rule(struct aq_nic_s *aq_nic, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.h b/drivers/net/ethernet/aquantia/atlantic/aq_filters.h index 122e06c88a33..96e89c8e52d0 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.h @@ -32,5 +32,8 @@ int aq_clear_rxnfc_all_rules(struct aq_nic_s *aq_nic); int aq_reapply_rxnfc_all_rules(struct aq_nic_s *aq_nic); int aq_filters_vlans_update(struct aq_nic_s *aq_nic); int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic); +int aq_set_data_fl3l4(const struct ethtool_rx_flow_spec *fsp, + struct aq_rx_filter_l3l4 *data, + int location, bool add); #endif /* AQ_FILTERS_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 57ea59026a2c..338c956ad1f7 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -15,10 +15,14 @@ #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 +#define AQ_HW_TXD_CTL_TS_EN 0x40000000U +#define AQ_HW_TXD_CTL_TS_TSG0 0x80000000U + enum aq_tc_mode { AQ_TC_MODE_INVALID = -1, AQ_TC_MODE_8TCS, @@ -38,6 +42,8 @@ enum aq_tc_mode { #define AQ_FRAC_PER_NS 0x100000000LL +#define AQ2_HW_PTP_COUNTER_HZ 156250000ll + /* Used for rate to Mbps conversion */ #define AQ_MBPS_DIVISOR 125000 /* 1000000 / 8 */ @@ -109,6 +115,7 @@ struct aq_stats_s { #define AQ_HW_IRQ_MSIX 3U #define AQ_HW_SERVICE_IRQS 1U +#define AQ_HW_PTP_IRQS 1U #define AQ_HW_POWER_STATE_D0 0U #define AQ_HW_POWER_STATE_D3 3U @@ -157,6 +164,15 @@ enum aq_priv_flags { AQ_HW_LOOPBACK_PHYEXT_SYS, }; +enum { + AQ_HW_PTP_DISABLE = 0, + AQ_HW_PTP_L2_ENABLE = BIT(1), + AQ_HW_PTP_L4_ENABLE = BIT(2), +}; + +#define ATL_TSG_CLOCK_SEL_0 0 +#define ATL_TSG_CLOCK_SEL_1 1 + #define AQ_HW_LOOPBACK_MASK (BIT(AQ_HW_LOOPBACK_DMA_SYS) |\ BIT(AQ_HW_LOOPBACK_PKT_SYS) |\ BIT(AQ_HW_LOOPBACK_DMA_NET) |\ @@ -198,6 +214,7 @@ struct aq_hw_s { u32 rpc_tid; struct hw_atl_utils_fw_rpc rpc; s64 ptp_clk_offset; + s8 clk_select; u16 phy_id; void *priv; }; @@ -323,11 +340,15 @@ struct aq_hw_ops { int (*hw_ts_to_sys_clock)(struct aq_hw_s *self, u64 ts, u64 *time); - int (*hw_gpio_pulse)(struct aq_hw_s *self, u32 index, u64 start, - u32 period); + int (*hw_gpio_pulse)(struct aq_hw_s *self, u32 index, + u32 clk_sel, u64 start, + u32 period, u32 hightime); int (*hw_extts_gpio_enable)(struct aq_hw_s *self, u32 index, - u32 enable); + u32 channel, int enable); + + void (*enable_ptp)(struct aq_hw_s *self, unsigned int param, + int enable); int (*hw_get_sync_ts)(struct aq_hw_s *self, u64 *ts); @@ -337,6 +358,14 @@ struct aq_hw_ops { int (*extract_hwts)(struct aq_hw_s *self, u8 *p, unsigned int len, u64 *timestamp); + u64 (*hw_ring_tx_ptp_get_ts)(struct aq_ring_s *ring); + + int (*hw_tx_ptp_ring_init)(struct aq_hw_s *self, + struct aq_ring_s *aq_ring); + int (*hw_rx_ptp_ring_init)(struct aq_hw_s *self, + struct aq_ring_s *aq_ring); + u32 (*hw_get_clk_sel)(struct aq_hw_s *self); + int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc); int (*hw_set_loopback)(struct aq_hw_s *self, u32 mode, bool enable); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c index 4ef4fe64b8ac..1da14786fe5c 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c @@ -19,8 +19,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -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 diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index ef9447810071..01792f7abf96 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,14 @@ 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); + /* AQC113 TSG requires >= 100 Mbps full-duplex: below 100 Mbps + * timestamp resolution is insufficient for IEEE 1588, and + * half-duplex collision domains make TX/RX correlation unreliable. + */ + 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 +294,7 @@ 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); + if (err) goto exit; @@ -450,7 +466,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 +519,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; @@ -683,6 +714,7 @@ unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb, unsigned int ret = 0U; unsigned int dx; u8 l4proto = 0; + s32 clk_sel; if (ipver == 4) l4proto = ip_hdr(skb)->protocol; @@ -795,6 +827,17 @@ unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb, dx_buff->is_eop = 1U; dx_buff->skb = skb; dx_buff->xdpf = NULL; + if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS && + self->aq_hw_ops->enable_ptp && + self->aq_hw_ops->hw_get_clk_sel && + aq_ptp_ring(self, ring)) { + clk_sel = (s32)self->aq_hw_ops->hw_get_clk_sel(self->aq_hw); + if (clk_sel < 0) + goto exit; + dx_buff->request_ts = 1U; + dx_buff->clk_sel = (u32)clk_sel; + ring->ptp_ts_deadline = jiffies + HZ; + } goto exit; mapping_error: diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index 39e1b606a75a..005d6ef4fc36 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -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; @@ -293,8 +294,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 9df8918216f6..558ac9237f75 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,11 +61,18 @@ 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; spinlock_t ptp_lock; spinlock_t ptp_ring_lock; + struct mutex ptp_filter_lock; /* serializes aq_ptp_dpath_enable() */ struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_info; @@ -64,7 +83,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 +92,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 +100,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 +120,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; } } @@ -268,6 +284,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 @@ -366,6 +394,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 +410,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, - start, (u32)period); + aq_ptp->ptp_clock_sel, start, + (u32)period, PTP_GPIO_HIGHTIME); mutex_unlock(&aq_nic->fwreq_mutex); return 0; @@ -454,6 +485,7 @@ 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, + aq_ptp->ptp_clock_sel, enable); } @@ -543,14 +575,191 @@ 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 void 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; + + aq_set_data_fl3l4(fsp, + &aq_ptp->udp_filter[*flt_idx], + aq_ptp->udp_filter[*flt_idx].location, + true); + + netdev_dbg(aq_nic->ndev, + "PTP MC filter prepared. Loc: %x\n", + aq_ptp->udp_filter[*flt_idx].location); + (*flt_idx)++; +} + +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 }; + 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; + int err = 0, i = 0; + int flt_idx = 0; + + netdev_dbg(aq_nic->ndev, + "%sable ptp filters: %x.\n", + enable_flags ? "En" : "Dis", enable_flags); + + if (enable_flags) { + /* Clear all existing L4 filters before applying new config */ + 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 (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)); + aq_ptp_add_a2_filter(aq_ptp, fsp, + &flt_idx); + + 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)); + aq_ptp_add_a2_filter(aq_ptp, fsp, + &flt_idx); + + 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)); + aq_ptp_add_a2_filter(aq_ptp, fsp, + &flt_idx); + + aq_ptp_fill_udpv4_mc(fsp, rx_queue, + cpu_to_be32(PTP_IPV4_MC_ADDR2)); + aq_ptp_add_a2_filter(aq_ptp, fsp, + &flt_idx); + } + } + + 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 && (enable_flags & AQ_HW_PTP_L2_ENABLE) && + 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,59 +781,61 @@ 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; + unsigned int ptp_en_flags = AQ_HW_PTP_DISABLE; - aq_ptp->eth_type_filter.ethertype = ETH_P_1588; - aq_ptp->eth_type_filter.queue = aq_ptp->ptp_rx.idx; + 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); - } - 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); - } - aq_utils_obj_clear(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP); + mutex_lock(&aq_ptp->ptp_filter_lock); + 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); } + mutex_unlock(&aq_ptp->ptp_filter_lock); if (err) return -EREMOTEIO; - aq_ptp->hwtstamp_config = *config; + if (ptp_en_flags != AQ_HW_PTP_DISABLE) + aq_utils_obj_set(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP); + else + aq_utils_obj_clear(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP); + aq_ptp->hwtstamp_config = *config; return 0; } @@ -673,21 +884,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 +1031,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 +1050,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 +1088,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 +1128,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 +1151,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 +1192,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 +1206,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 +1215,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_hwts_rx_free(&aq_ptp->hwts_rx); err_exit_ptp_rx: aq_ring_free(&aq_ptp->ptp_rx); err_exit_ptp_tx: @@ -1011,7 +1234,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 +1259,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 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 +1309,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 +1367,46 @@ 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) { + mutex_lock(&aq_ptp->ptp_filter_lock); + unsigned int ptp_en_flags = + aq_ptp_parse_rx_filters(state == AQ_PTP_LINK_UP ? + aq_ptp->hwtstamp_config.rx_filter : + HWTSTAMP_FILTER_NONE); + if (aq_ptp_dpath_enable(aq_ptp, ptp_en_flags, aq_ptp->ptp_rx.idx)) + netdev_warn(aq_nic->ndev, + "PTP RX filter restore failed in link change\n"); + mutex_unlock(&aq_ptp->ptp_filter_lock); + } } 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,20 +1416,44 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) return 0; } - if (!aq_nic->aq_fw_ops->enable_ptp) { + if (a1_ptp) { + if (!aq_nic->aq_fw_ops->enable_ptp) { + aq_nic->aq_ptp = NULL; + return 0; + } + } + + /* 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; } - hw_atl_utils_mpi_read_stats(aq_nic->aq_hw, &mbox); + 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 (!(mbox.info.caps_ex & BIT(CAPS_EX_PHY_PTP_EN))) { - aq_nic->aq_ptp = NULL; - return 0; + 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_offset_init(&mbox.info.ptp_offset); - aq_ptp = kzalloc_obj(*aq_ptp); if (!aq_ptp) { err = -ENOMEM; @@ -1190,10 +1462,13 @@ 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); + mutex_init(&aq_ptp->ptp_filter_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 +1485,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,31 +1531,47 @@ 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; + cancel_delayed_work_sync(&aq_ptp->poll_sync); + + /* 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); + 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); + mutex_destroy(&aq_ptp->ptp_filter_lock); 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; + kfree(aq_ptp); } struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h index 5e643ec7cc06..96cbfa59ac75 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,8 @@ 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); +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); @@ -80,7 +87,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 +129,9 @@ 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 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; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index e270327e47fd..8ff07de2bd52 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -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; } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h index d627ace850ff..a70b880ada67 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h @@ -85,7 +85,9 @@ struct __packed aq_ring_buff_s { u32 is_error:1; u32 is_vlan:1; u32 is_lro:1; - u32 rsvd3:3; + u32 request_ts:1; + u32 clk_sel:1; + u32 rsvd3:1; u16 eop_index; u16 rsvd4; }; @@ -152,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 { diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index c7895bfb2ecf..6c25ad264b19 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -736,6 +736,15 @@ int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self, struct aq_ring_s *ring, txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_WB; is_gso = false; is_vlan = false; + + if (ATL_HW_IS_CHIP_FEATURE(self, ANTIGUA) && + unlikely(buff->request_ts)) { + txd->ctl |= AQ_HW_TXD_CTL_TS_EN; + if (buff->clk_sel != ATL_TSG_CLOCK_SEL_1) + txd->ctl |= AQ_HW_TXD_CTL_TS_TSG0; + /* The only DD+TS is required */ + txd->ctl &= ~HW_ATL_B0_TXD_CTL_CMD_WB; + } } } ring->sw_tail = aq_ring_next_dx(ring, ring->sw_tail); @@ -1323,8 +1332,8 @@ static int hw_atl_b0_adj_clock_freq(struct aq_hw_s *self, s32 ppb) return self->aq_fw_ops->send_fw_request(self, &fwreq, size); } -static int hw_atl_b0_gpio_pulse(struct aq_hw_s *self, u32 index, - u64 start, u32 period) +static int hw_atl_b0_gpio_pulse(struct aq_hw_s *self, u32 index, u32 clk_sel, + u64 start, u32 period, u32 hightime) { struct hw_fw_request_iface fwreq; size_t size; @@ -1342,7 +1351,7 @@ static int hw_atl_b0_gpio_pulse(struct aq_hw_s *self, u32 index, } static int hw_atl_b0_extts_gpio_enable(struct aq_hw_s *self, u32 index, - u32 enable) + u32 channel, int enable) { /* Enable/disable Sync1588 GPIO Timestamping */ aq_phy_write_reg(self, MDIO_MMD_PCS, 0xc611, enable ? 0x71 : 0); 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 0ce9caae8799..25dd7150aaaf 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c @@ -7,10 +7,12 @@ #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" #include "hw_atl/hw_atl_llh_internal.h" +#include "hw_atl2.h" #include "hw_atl2_utils.h" #include "hw_atl2_llh.h" #include "hw_atl2_internal.h" @@ -19,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, \ @@ -86,6 +97,38 @@ const struct aq_hw_caps_s hw_atl2_caps_aqc116c = { AQ_NIC_RATE_10M, }; +/* Find tag with the same action or new free tag + * top - top inclusive tag value + * action - action for ActionResolverTable + */ +static int hw_atl2_filter_tag_get(struct hw_atl2_tag_policy *tags, + int top, u16 action) +{ + int i; + + for (i = 1; i <= top; i++) + if (tags[i].usage > 0 && tags[i].action == action) { + tags[i].usage++; + return i; + } + + for (i = 1; i <= top; i++) + if (tags[i].usage == 0) { + tags[i].usage = 1; + tags[i].action = action; + return i; + } + + return -ENOSPC; +} + +static void hw_atl2_filter_tag_put(struct hw_atl2_tag_policy *tags, + int tag) +{ + if (tags[tag].usage > 0) + tags[tag].usage--; +} + static u32 hw_atl2_sem_act_rslvr_get(struct aq_hw_s *self) { return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL2_FW_SM_ACT_RSLVR); @@ -94,13 +137,30 @@ 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; err = hw_atl2_utils_soft_reset(self); if (err) return err; - memset(priv, 0, sizeof(*priv)); + memset(&priv->last_stats, 0, sizeof(priv->last_stats)); + memset(priv->l3_v4_filters, 0, sizeof(priv->l3_v4_filters)); + memset(priv->l3_v6_filters, 0, sizeof(priv->l3_v6_filters)); + memset(priv->l4_filters, 0, sizeof(priv->l4_filters)); + memset(priv->etype_policy, 0, sizeof(priv->etype_policy)); + for (i = 0; i < HW_ATL2_RPF_L3L4_FILTERS; i++) { + priv->l3l4_filters[i].l3_index = -1; + 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); @@ -109,6 +169,24 @@ static int hw_atl2_hw_reset(struct aq_hw_s *self) return err; } +static int hw_atl2_tc_ptp_set(struct aq_hw_s *self) +{ + /* Init TC2 for PTP_TX */ + hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, HW_ATL2_PTP_TXBUF_SIZE, + AQ_HW_PTP_TC); + + /* Init TC2 for PTP_RX */ + hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, HW_ATL2_PTP_RXBUF_SIZE, + AQ_HW_PTP_TC); + + /* No flow control for PTP */ + hw_atl_rpb_rx_xoff_en_per_tc_set(self, 0U, AQ_HW_PTP_TC); + + hw_atl2_tpb_tps_highest_priority_tc_set(self, AQ_HW_PTP_TC); + + return aq_hw_err_from_flags(self); +} + static int hw_atl2_hw_queue_to_tc_map_set(struct aq_hw_s *self) { struct aq_nic_cfg_s *cfg = self->aq_nic_cfg; @@ -167,6 +245,11 @@ static int hw_atl2_hw_qos_set(struct aq_hw_s *self) unsigned int prio = 0U; u32 tc = 0U; + if (cfg->is_ptp) { + tx_buff_size -= HW_ATL2_PTP_TXBUF_SIZE; + rx_buff_size -= HW_ATL2_PTP_RXBUF_SIZE; + } + /* TPS Descriptor rate init */ hw_atl_tps_tx_pkt_shed_desc_rate_curr_time_res_set(self, 0x0U); hw_atl_tps_tx_pkt_shed_desc_rate_lim_set(self, 0xA); @@ -200,6 +283,9 @@ static int hw_atl2_hw_qos_set(struct aq_hw_s *self) hw_atl_b0_set_fc(self, self->aq_nic_cfg->fc.req, tc); } + if (cfg->is_ptp) + hw_atl2_tc_ptp_set(self); + /* QoS 802.1p priority -> TC mapping */ for (prio = 0; prio < 8; ++prio) hw_atl_rpf_rpb_user_priority_tc_map_set(self, prio, @@ -217,8 +303,9 @@ static int hw_atl2_hw_rss_set(struct aq_hw_s *self, u8 *indirection_table = rss_params->indirection_table; const u32 num_tcs = aq_hw_num_tcs(self); u32 rpf_redir2_enable; - int tc; - int i; + u32 queue; + u32 tc; + u32 i; rpf_redir2_enable = num_tcs > 4 ? 1 : 0; @@ -226,10 +313,9 @@ static int hw_atl2_hw_rss_set(struct aq_hw_s *self, for (i = HW_ATL2_RSS_REDIRECTION_MAX; i--;) { for (tc = 0; tc != num_tcs; tc++) { - hw_atl2_new_rpf_rss_redir_set(self, tc, i, - tc * - aq_hw_q_per_tc(self) + - indirection_table[i]); + queue = tc * aq_hw_q_per_tc(self) + + indirection_table[i]; + hw_atl2_new_rpf_rss_redir_set(self, tc, i, queue); } } @@ -373,13 +459,27 @@ static int hw_atl2_hw_init_tx_path(struct aq_hw_s *self) hw_atl2_tpb_tx_buf_clk_gate_en_set(self, 0U); + if (hw_atl2_phi_ext_tag_get(self)) { + hw_atl2_tdm_tx_data_read_req_limit_set(self, 0x7F); + hw_atl2_tdm_tx_desc_read_req_limit_set(self, 0x0F); + } + return aq_hw_err_from_flags(self); } +/* Initialise new rx filters + * L2 promisc OFF + * VLAN promisc OFF + * + * User priority to TC + */ static void hw_atl2_hw_init_new_rx_filters(struct aq_hw_s *self) { u8 *prio_tc_map = self->aq_nic_cfg->prio_tc_map; struct hw_atl2_priv *priv = self->priv; + u32 art_first_sec, art_last_sec; + u32 art_sections; + u32 art_mask; u16 action; u8 index; int i; @@ -394,9 +494,20 @@ static void hw_atl2_hw_init_new_rx_filters(struct aq_hw_s *self) * REC entry is used for further processing. If multiple entries match, * the lowest REC entry, Action field will be selected. */ - hw_atl2_rpf_act_rslvr_section_en_set(self, 0xFFFF); + art_last_sec = min_t(u32, + priv->art_base_index / 8 + priv->art_count / 8, + 16U); + art_first_sec = min_t(u32, priv->art_base_index / 8, 16U); + art_mask = (BIT(art_last_sec) - 1) - (BIT(art_first_sec) - 1); + if (!art_mask) { + /* ART base index is out of range, enabling all sections */ + art_mask = 0xFFFF; + } + art_sections = hw_atl2_rpf_act_rslvr_section_en_get(self) | art_mask; + hw_atl2_rpf_act_rslvr_section_en_set(self, art_sections); + hw_atl2_rpf_l3_v6_v4_select_set(self, 1); hw_atl2_rpfl2_uc_flr_tag_set(self, HW_ATL2_RPF_TAG_BASE_UC, - HW_ATL2_MAC_UC); + priv->l2_filters_base_index); hw_atl2_rpfl2_bc_flr_tag_set(self, HW_ATL2_RPF_TAG_BASE_UC); /* FW reserves the beginning of ART, thus all driver entries must @@ -484,6 +595,7 @@ static int hw_atl2_act_rslvr_table_set(struct aq_hw_s *self, u8 location, static int hw_atl2_hw_init_rx_path(struct aq_hw_s *self) { struct aq_nic_cfg_s *cfg = self->aq_nic_cfg; + struct hw_atl2_priv *priv = self->priv; int i; /* Rx TC/RSS number config */ @@ -499,7 +611,9 @@ static int hw_atl2_hw_init_rx_path(struct aq_hw_s *self) /* Multicast filters */ for (i = HW_ATL2_MAC_MAX; i--;) { - hw_atl_rpfl2_uc_flr_en_set(self, (i == 0U) ? 1U : 0U, i); + hw_atl_rpfl2_uc_flr_en_set(self, + (i == priv->l2_filters_base_index) ? + 1U : 0U, i); hw_atl_rpfl2unicast_flr_act_set(self, 1U, i); } @@ -530,6 +644,35 @@ static int hw_atl2_hw_init_rx_path(struct aq_hw_s *self) return aq_hw_err_from_flags(self); } +static int hw_atl2_hw_mac_addr_set(struct aq_hw_s *self, const u8 *mac_addr) +{ + struct hw_atl2_priv *priv = self->priv; + u32 location = priv->l2_filters_base_index; + unsigned int h; + unsigned int l; + int err; + + if (!mac_addr) { + err = -EINVAL; + goto err_exit; + } + h = (mac_addr[0] << 8) | (mac_addr[1]); + l = (mac_addr[2] << 24) | (mac_addr[3] << 16) | + (mac_addr[4] << 8) | mac_addr[5]; + + hw_atl_rpfl2_uc_flr_en_set(self, 0U, location); + hw_atl_rpfl2unicast_dest_addresslsw_set(self, l, location); + hw_atl_rpfl2unicast_dest_addressmsw_set(self, h, location); + hw_atl_rpfl2unicast_flr_act_set(self, 1U, location); + hw_atl2_rpfl2_uc_flr_tag_set(self, HW_ATL2_RPF_TAG_BASE_UC, location); + hw_atl_rpfl2_uc_flr_en_set(self, 1U, location); + + err = aq_hw_err_from_flags(self); + +err_exit: + return err; +} + static int hw_atl2_hw_init(struct aq_hw_s *self, const u8 *mac_addr) { static u32 aq_hw_atl2_igcr_table_[4][2] = { @@ -540,23 +683,14 @@ static int hw_atl2_hw_init(struct aq_hw_s *self, const u8 *mac_addr) }; struct aq_nic_cfg_s *aq_nic_cfg = self->aq_nic_cfg; - struct hw_atl2_priv *priv = self->priv; - u8 base_index, count; int err; - err = hw_atl2_utils_get_action_resolve_table_caps(self, &base_index, - &count); - if (err) - return err; - - priv->art_base_index = 8 * base_index; - hw_atl2_init_launchtime(self); hw_atl2_hw_init_tx_path(self); hw_atl2_hw_init_rx_path(self); - hw_atl_b0_hw_mac_addr_set(self, mac_addr); + hw_atl2_hw_mac_addr_set(self, mac_addr); self->aq_fw_ops->set_link_speed(self, aq_nic_cfg->link_speed_msk); self->aq_fw_ops->set_state(self, MPI_INIT); @@ -600,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) @@ -628,6 +772,8 @@ static int hw_atl2_hw_multicast_list_set(struct aq_hw_s *self, [ETH_ALEN], u32 count) { + struct hw_atl2_priv *priv = self->priv; + u32 base_location = priv->l2_filters_base_index + 1; struct aq_nic_cfg_s *cfg = self->aq_nic_cfg; int err = 0; @@ -643,18 +789,18 @@ static int hw_atl2_hw_multicast_list_set(struct aq_hw_s *self, u32 l = (ar_mac[i][2] << 24) | (ar_mac[i][3] << 16) | (ar_mac[i][4] << 8) | ar_mac[i][5]; - hw_atl_rpfl2_uc_flr_en_set(self, 0U, HW_ATL2_MAC_MIN + i); + hw_atl_rpfl2_uc_flr_en_set(self, 0U, base_location + i); hw_atl_rpfl2unicast_dest_addresslsw_set(self, l, - HW_ATL2_MAC_MIN + i); + base_location + i); hw_atl_rpfl2unicast_dest_addressmsw_set(self, h, - HW_ATL2_MAC_MIN + i); + base_location + i); - hw_atl2_rpfl2_uc_flr_tag_set(self, 1, HW_ATL2_MAC_MIN + i); + hw_atl2_rpfl2_uc_flr_tag_set(self, 1, base_location + i); hw_atl_rpfl2_uc_flr_en_set(self, (cfg->is_mc_list_enabled), - HW_ATL2_MAC_MIN + i); + base_location + i); } err = aq_hw_err_from_flags(self); @@ -767,6 +913,640 @@ 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) +{ + if (f1->cmd != f2->cmd) + return false; + + if (f1->cmd & HW_ATL2_RPF_L3_CMD_SA_EN) + if (f1->srcip[0] != f2->srcip[0]) + return false; + + if (f1->cmd & HW_ATL2_RPF_L3_CMD_DA_EN) + if (f1->dstip[0] != f2->dstip[0]) + return false; + + if (f1->cmd & (HW_ATL2_RPF_L3_CMD_PROTO_EN | + HW_ATL2_RPF_L3_V6_CMD_PROTO_EN)) + if (f1->proto != f2->proto) + return false; + + if (f1->cmd & HW_ATL2_RPF_L3_V6_CMD_SA_EN) + if (memcmp(f1->srcip, f2->srcip, 16)) + return false; + + if (f1->cmd & HW_ATL2_RPF_L3_V6_CMD_DA_EN) + if (memcmp(f1->dstip, f2->dstip, 16)) + return false; + + return true; +} + +static int hw_atl2_new_fl3l4_find_l3(struct aq_hw_s *self, + struct hw_atl2_l3_filter *l3) +{ + struct hw_atl2_priv *priv = self->priv; + struct hw_atl2_l3_filter *l3_filters; + int i, first, last; + + if (l3->cmd & HW_ATL2_RPF_L3_V6_CMD_EN) { + l3_filters = priv->l3_v6_filters; + first = priv->l3_v6_filter_base_index; + last = priv->l3_v6_filter_base_index + + priv->l3_v6_filter_count; + } else { + l3_filters = priv->l3_v4_filters; + first = priv->l3_v4_filter_base_index; + last = priv->l3_v4_filter_base_index + + priv->l3_v4_filter_count; + } + for (i = first; i < last; i++) { + if (hw_atl2_rxf_l3_is_equal(&l3_filters[i], l3)) + return i; + } + + for (i = first; i < last; i++) { + u32 l3_enable_mask = HW_ATL2_RPF_L3_CMD_EN | + HW_ATL2_RPF_L3_V6_CMD_EN; + + if (!(l3_filters[i].cmd & l3_enable_mask)) + return i; + } + + return -ENOSPC; +} + +static void hw_atl2_rxf_l3_get(struct aq_hw_s *self, + struct hw_atl2_l3_filter *l3, int idx, + const struct hw_atl2_l3_filter *_l3) +{ + int i; + + l3->usage++; + if (l3->usage == 1) { + l3->cmd = _l3->cmd; + for (i = 0; i < 4; i++) { + l3->srcip[i] = _l3->srcip[i]; + l3->dstip[i] = _l3->dstip[i]; + } + l3->proto = _l3->proto; + + if (l3->cmd & HW_ATL2_RPF_L3_CMD_EN) { + hw_atl2_rpf_l3_v4_cmd_set(self, l3->cmd, idx); + hw_atl2_rpf_l3_v4_tag_set(self, idx + 1, idx); + hw_atl2_rpf_l3_v4_dest_addr_set(self, + idx, + l3->dstip[0]); + hw_atl2_rpf_l3_v4_src_addr_set(self, + idx, + l3->srcip[0]); + } else { + hw_atl2_rpf_l3_v6_cmd_set(self, l3->cmd, idx); + hw_atl2_rpf_l3_v6_tag_set(self, idx + 1, idx); + hw_atl2_rpf_l3_v6_dest_addr_set(self, + idx, + l3->dstip); + hw_atl2_rpf_l3_v6_src_addr_set(self, + idx, + l3->srcip); + } + } +} + +static void hw_atl2_rxf_l3_put(struct aq_hw_s *self, + struct hw_atl2_l3_filter *l3, int idx) +{ + if (l3->usage) + l3->usage--; + + if (!l3->usage) { + if (l3->cmd & HW_ATL2_RPF_L3_V6_CMD_EN) + hw_atl2_rpf_l3_v6_cmd_set(self, 0, idx); + else + hw_atl2_rpf_l3_v4_cmd_set(self, 0, idx); + l3->cmd = 0; + } +} + +static bool hw_atl2_rxf_l4_is_equal(struct hw_atl2_l4_filter *f1, + struct hw_atl2_l4_filter *f2) +{ + if (f1->cmd != f2->cmd) + return false; + + if (f1->cmd & HW_ATL2_RPF_L4_CMD_SP_EN) + if (f1->sport != f2->sport) + return false; + + if (f1->cmd & HW_ATL2_RPF_L4_CMD_DP_EN) + if (f1->dport != f2->dport) + return false; + + return true; +} + +static int hw_atl2_new_fl3l4_find_l4(struct aq_hw_s *self, + struct hw_atl2_l4_filter *l4) +{ + struct hw_atl2_priv *priv = self->priv; + int i, first, last; + + first = priv->l4_filter_base_index; + last = priv->l4_filter_base_index + priv->l4_filter_count; + + for (i = first; i < last; i++) + if (hw_atl2_rxf_l4_is_equal(&priv->l4_filters[i], l4)) + return i; + + for (i = first; i < last; i++) + if ((priv->l4_filters[i].cmd & HW_ATL2_RPF_L4_CMD_EN) == 0) + return i; + + return -ENOSPC; +} + +static void hw_atl2_rxf_l4_put(struct aq_hw_s *self, + struct hw_atl2_l4_filter *l4, int idx) +{ + if (l4->usage) + l4->usage--; + + if (!l4->usage) { + l4->cmd = 0; + hw_atl2_rpf_l4_cmd_set(self, l4->cmd, idx); + } +} + +static void hw_atl2_rxf_l4_get(struct aq_hw_s *self, + struct hw_atl2_l4_filter *l4, int idx, + const struct hw_atl2_l4_filter *_l4) +{ + l4->usage++; + if (l4->usage == 1) { + l4->cmd = _l4->cmd; + l4->sport = _l4->sport; + l4->dport = _l4->dport; + + hw_atl2_rpf_l4_cmd_set(self, l4->cmd, idx); + hw_atl2_rpf_l4_tag_set(self, idx + 1, idx); + hw_atl_rpf_l4_spd_set(self, l4->sport, idx); + hw_atl_rpf_l4_dpd_set(self, l4->dport, idx); + } +} + +static int hw_atl2_new_fl3l4_configure(struct aq_hw_s *self, + struct aq_rx_filter_l3l4 *data) +{ + struct hw_atl2_priv *priv = self->priv; + s8 old_l3_index = priv->l3l4_filters[data->location].l3_index; + s8 old_l4_index = priv->l3l4_filters[data->location].l4_index; + u8 old_ipv6 = priv->l3l4_filters[data->location].ipv6; + struct hw_atl2_l3_filter *l3_filters; + struct hw_atl2_l3_filter l3; + struct hw_atl2_l4_filter l4; + s8 l3_idx = -1; + s8 l4_idx = -1; + + if (!(data->cmd & HW_ATL_RX_ENABLE_FLTR_L3L4)) + return 0; + + memset(&l3, 0, sizeof(l3)); + memset(&l4, 0, sizeof(l4)); + + /* convert legacy filter to new */ + if (data->cmd & HW_ATL_RX_ENABLE_CMP_PROT_L4) { + l3.cmd |= data->is_ipv6 ? HW_ATL2_RPF_L3_V6_CMD_PROTO_EN : + HW_ATL2_RPF_L3_CMD_PROTO_EN; + l3.cmd |= data->is_ipv6 ? HW_ATL2_RPF_L3_V6_CMD_EN : + HW_ATL2_RPF_L3_CMD_EN; + switch (data->cmd & 0x7) { + case HW_ATL_RX_TCP: + l3.cmd |= IPPROTO_TCP << (data->is_ipv6 ? 0x18 : 8); + break; + case HW_ATL_RX_UDP: + l3.cmd |= IPPROTO_UDP << (data->is_ipv6 ? 0x18 : 8); + break; + case HW_ATL_RX_SCTP: + l3.cmd |= IPPROTO_SCTP << (data->is_ipv6 ? 0x18 : 8); + break; + case HW_ATL_RX_ICMP: + l3.cmd |= IPPROTO_ICMP << (data->is_ipv6 ? 0x18 : 8); + break; + } + } + + if (data->cmd & HW_ATL_RX_ENABLE_CMP_SRC_ADDR_L3) { + if (data->is_ipv6) { + l3.cmd |= HW_ATL2_RPF_L3_V6_CMD_SA_EN | + HW_ATL2_RPF_L3_V6_CMD_EN; + memcpy(l3.srcip, data->ip_src, sizeof(l3.srcip)); + } else { + l3.cmd |= HW_ATL2_RPF_L3_CMD_SA_EN | + HW_ATL2_RPF_L3_CMD_EN; + l3.srcip[0] = data->ip_src[0]; + } + } + if (data->cmd & HW_ATL_RX_ENABLE_CMP_DEST_ADDR_L3) { + if (data->is_ipv6) { + l3.cmd |= HW_ATL2_RPF_L3_V6_CMD_DA_EN | + HW_ATL2_RPF_L3_V6_CMD_EN; + memcpy(l3.dstip, data->ip_dst, sizeof(l3.dstip)); + } else { + l3.cmd |= HW_ATL2_RPF_L3_CMD_DA_EN | + HW_ATL2_RPF_L3_CMD_EN; + l3.dstip[0] = data->ip_dst[0]; + } + } + + if (data->cmd & HW_ATL_RX_ENABLE_CMP_DEST_PORT_L4) { + l4.cmd |= HW_ATL2_RPF_L4_CMD_DP_EN | HW_ATL2_RPF_L4_CMD_EN; + l4.dport = data->p_dst; + } + if (data->cmd & HW_ATL_RX_ENABLE_CMP_SRC_PORT_L4) { + l4.cmd |= HW_ATL2_RPF_L4_CMD_SP_EN | HW_ATL2_RPF_L4_CMD_EN; + l4.sport = data->p_src; + } + + /* find L3 and L4 filters */ + if (l3.cmd & (HW_ATL2_RPF_L3_CMD_EN | HW_ATL2_RPF_L3_V6_CMD_EN)) { + l3_idx = hw_atl2_new_fl3l4_find_l3(self, &l3); + if (l3_idx < 0) + return l3_idx; + + if (l3.cmd & HW_ATL2_RPF_L3_V6_CMD_EN) + l3_filters = priv->l3_v6_filters; + else + l3_filters = priv->l3_v4_filters; + + if (priv->l3l4_filters[data->location].l3_index != l3_idx || + old_ipv6 != !!(l3.cmd & HW_ATL2_RPF_L3_V6_CMD_EN)) + hw_atl2_rxf_l3_get(self, &l3_filters[l3_idx], + l3_idx, &l3); + } + + if (old_l3_index != -1) { + if (old_ipv6) + l3_filters = priv->l3_v6_filters; + else + l3_filters = priv->l3_v4_filters; + + if (!(hw_atl2_rxf_l3_is_equal(&l3, + &l3_filters[old_l3_index]))) { + hw_atl2_rxf_l3_put(self, + &l3_filters[old_l3_index], + old_l3_index); + } + } + if (l3.cmd & HW_ATL2_RPF_L3_V6_CMD_EN) + priv->l3l4_filters[data->location].ipv6 = 1; + else + priv->l3l4_filters[data->location].ipv6 = 0; + priv->l3l4_filters[data->location].l3_index = l3_idx; + + if (l4.cmd & HW_ATL2_RPF_L4_CMD_EN) { + l4_idx = hw_atl2_new_fl3l4_find_l4(self, &l4); + if (l4_idx < 0) + return l4_idx; + + if (priv->l3l4_filters[data->location].l4_index != l4_idx) + hw_atl2_rxf_l4_get(self, &priv->l4_filters[l4_idx], + l4_idx, &l4); + } + + if (old_l4_index != -1) { + if (!(hw_atl2_rxf_l4_is_equal(&priv->l4_filters[old_l4_index], + &l4))) { + hw_atl2_rxf_l4_put(self, + &priv->l4_filters[old_l4_index], + old_l4_index); + } + } + priv->l3l4_filters[data->location].l4_index = l4_idx; + + return 0; +} + +static int hw_atl2_hw_fl3l4_set(struct aq_hw_s *self, + struct aq_rx_filter_l3l4 *data) +{ + struct hw_atl2_priv *priv = self->priv; + struct hw_atl2_l3_filter *l3_filters; + struct hw_atl2_l3_filter *l3 = NULL; + struct hw_atl2_l4_filter *l4 = NULL; + u8 location = data->location; + u32 req_tag = 0; + u16 action = 0; + int l3_index; + int l4_index; + u32 mask = 0; + u8 index; + u8 ipv6; + int res; + + res = hw_atl2_new_fl3l4_configure(self, data); + if (res) + return res; + + l3_index = priv->l3l4_filters[location].l3_index; + l4_index = priv->l3l4_filters[location].l4_index; + ipv6 = priv->l3l4_filters[location].ipv6; + if (ipv6) + l3_filters = priv->l3_v6_filters; + else + l3_filters = priv->l3_v4_filters; + + if (!(data->cmd & HW_ATL_RX_ENABLE_FLTR_L3L4)) { + if (l3_index > -1) + hw_atl2_rxf_l3_put(self, &l3_filters[l3_index], + l3_index); + + if (l4_index > -1) + hw_atl2_rxf_l4_put(self, &priv->l4_filters[l4_index], + l4_index); + + priv->l3l4_filters[location].l3_index = -1; + priv->l3l4_filters[location].l4_index = -1; + index = priv->art_base_index + HW_ATL2_RPF_L3L4_USER_INDEX + + location; + hw_atl2_act_rslvr_table_set(self, index, 0, 0, + HW_ATL2_ACTION_DISABLE); + + return 0; + } + + if (l3_index != -1) + l3 = &l3_filters[l3_index]; + if (l4_index != -1) + l4 = &priv->l4_filters[l4_index]; + + if (l4 && (l4->cmd & HW_ATL2_RPF_L4_CMD_EN)) { + req_tag |= (l4_index + 1) << HW_ATL2_RPF_TAG_L4_OFFSET; + mask |= HW_ATL2_RPF_TAG_L4_MASK; + } + + if (l3) { + if (l3->cmd & HW_ATL2_RPF_L3_V6_CMD_EN) { + req_tag |= (l3_index + 1) << + HW_ATL2_RPF_TAG_L3_V6_OFFSET; + mask |= HW_ATL2_RPF_TAG_L3_V6_MASK; + } else { + req_tag |= (l3_index + 1) << + HW_ATL2_RPF_TAG_L3_V4_OFFSET; + mask |= HW_ATL2_RPF_TAG_L3_V4_MASK; + } + } + + if (data->cmd & (HW_ATL_RX_HOST << HW_ATL2_RPF_L3_L4_ACTF_SHIFT)) + action = HW_ATL2_ACTION_ASSIGN_QUEUE((data->cmd & + HW_ATL2_RPF_L3_L4_RXQF_MSK) >> + HW_ATL2_RPF_L3_L4_RXQF_SHIFT); + else + action = HW_ATL2_ACTION_DROP; + + index = priv->art_base_index + HW_ATL2_RPF_L3L4_USER_INDEX + location; + hw_atl2_act_rslvr_table_set(self, index, req_tag, mask, action); + return 0; +} + +static int hw_atl2_hw_fl2_set(struct aq_hw_s *self, + struct aq_rx_filter_l2 *data) +{ + struct hw_atl2_priv *priv = self->priv; + u32 mask = HW_ATL2_RPF_TAG_ET_MASK; + u32 req_tag = 0; + u16 action = 0; + u32 location; + u8 index; + int tag; + + location = priv->etype_filter_base_index + data->location; + + hw_atl_rpf_etht_flr_set(self, data->ethertype, location); + hw_atl_rpf_etht_user_priority_en_set(self, + !!data->user_priority_en, + location); + if (data->user_priority_en) { + hw_atl_rpf_etht_user_priority_set(self, + data->user_priority, + location); + req_tag |= data->user_priority << HW_ATL2_RPF_TAG_PCP_OFFSET; + mask |= HW_ATL2_RPF_TAG_PCP_MASK; + } + + if (data->queue < 0) { + hw_atl_rpf_etht_flr_act_set(self, 0U, location); + hw_atl_rpf_etht_rx_queue_en_set(self, 0U, location); + action = HW_ATL2_ACTION_DROP; + } else { + hw_atl_rpf_etht_flr_act_set(self, 1U, location); + hw_atl_rpf_etht_rx_queue_en_set(self, 1U, location); + hw_atl_rpf_etht_rx_queue_set(self, data->queue, location); + action = HW_ATL2_ACTION_ASSIGN_QUEUE(data->queue); + } + + tag = hw_atl2_filter_tag_get(priv->etype_policy, + priv->etype_filter_tag_top, + action); + + if (tag < 0) + return -ENOSPC; + + req_tag |= tag << HW_ATL2_RPF_TAG_ET_OFFSET; + hw_atl2_rpf_etht_flr_tag_set(self, tag, location); + index = priv->art_base_index + HW_ATL2_RPF_ET_PCP_USER_INDEX + + data->location; + hw_atl2_act_rslvr_table_set(self, index, req_tag, mask, action); + + hw_atl_rpf_etht_flr_en_set(self, 1U, location); + + return aq_hw_err_from_flags(self); +} + +static int hw_atl2_hw_fl2_clear(struct aq_hw_s *self, + struct aq_rx_filter_l2 *data) +{ + struct hw_atl2_priv *priv = self->priv; + u32 location; + u8 index; + u32 tag; + + location = priv->etype_filter_base_index + data->location; + hw_atl_rpf_etht_flr_en_set(self, 0U, location); + hw_atl_rpf_etht_flr_set(self, 0U, location); + hw_atl_rpf_etht_user_priority_en_set(self, 0U, location); + + index = priv->art_base_index + HW_ATL2_RPF_ET_PCP_USER_INDEX + + data->location; + hw_atl2_act_rslvr_table_set(self, index, 0, 0, + HW_ATL2_ACTION_DISABLE); + tag = hw_atl2_rpf_etht_flr_tag_get(self, location); + hw_atl2_filter_tag_put(priv->etype_policy, tag); + + return aq_hw_err_from_flags(self); +} + +/* + * Set VLAN filter table + * Configure VLAN filter table to accept (and assign the queue) traffic + * for the particular vlan ids. + * Note: use this function under vlan promisc mode not to lost the traffic + * + * param - aq_hw_s + * param - aq_rx_filter_vlan VLAN filter configuration + * return 0 - OK, <0 - error + */ static int hw_atl2_hw_vlan_set(struct aq_hw_s *self, struct aq_rx_filter_vlan *aq_vlans) { @@ -825,7 +1605,7 @@ static int hw_atl2_hw_vlan_ctrl(struct aq_hw_s *self, bool enable) const struct aq_hw_ops hw_atl2_ops = { .hw_soft_reset = hw_atl2_utils_soft_reset, .hw_prepare = hw_atl2_utils_initfw, - .hw_set_mac_address = hw_atl_b0_hw_mac_addr_set, + .hw_set_mac_address = hw_atl2_hw_mac_addr_set, .hw_init = hw_atl2_hw_init, .hw_reset = hw_atl2_hw_reset, .hw_start = hw_atl_b0_hw_start, @@ -848,6 +1628,9 @@ const struct aq_hw_ops hw_atl2_ops = { .hw_ring_rx_init = hw_atl2_hw_ring_rx_init, .hw_ring_tx_init = hw_atl2_hw_ring_tx_init, .hw_packet_filter_set = hw_atl2_hw_packet_filter_set, + .hw_filter_l2_set = hw_atl2_hw_fl2_set, + .hw_filter_l2_clear = hw_atl2_hw_fl2_clear, + .hw_filter_l3l4_set = hw_atl2_hw_fl3l4_set, .hw_filter_vlan_set = hw_atl2_hw_vlan_set, .hw_filter_vlan_ctrl = hw_atl2_hw_vlan_ctrl, .hw_multicast_list_set = hw_atl2_hw_multicast_list_set, @@ -855,9 +1638,27 @@ const struct aq_hw_ops hw_atl2_ops = { .hw_rss_set = hw_atl2_hw_rss_set, .hw_rss_hash_set = hw_atl_b0_hw_rss_hash_set, .hw_tc_rate_limit_set = hw_atl2_hw_init_tx_tc_rate_limit, + .hw_get_regs = hw_atl2_utils_hw_get_regs, .hw_get_hw_stats = hw_atl2_utils_get_hw_stats, .hw_get_fw_version = hw_atl2_utils_get_fw_version, .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 5a89bb8722f9..c36127900de3 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 @@ -27,8 +27,11 @@ #define HW_ATL2_INT_MASK (0xFFFFFFFFU) #define HW_ATL2_TXBUF_MAX 128U -#define HW_ATL2_RXBUF_MAX 192U +#define HW_ATL2_PTP_TXBUF_SIZE 8U +/* 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 #define HW_ATL2_TC_MAX 8U @@ -84,6 +87,19 @@ enum HW_ATL2_RPF_ART_INDEX { HW_ATL_VLAN_MAX_FILTERS, }; +#define HW_ATL2_RPF_L3_CMD_EN BIT(0) +#define HW_ATL2_RPF_L3_CMD_SA_EN BIT(1) +#define HW_ATL2_RPF_L3_CMD_DA_EN BIT(2) +#define HW_ATL2_RPF_L3_CMD_PROTO_EN BIT(3) +#define HW_ATL2_RPF_L3_V6_CMD_EN BIT(0x10) +#define HW_ATL2_RPF_L3_V6_CMD_SA_EN BIT(0x11) +#define HW_ATL2_RPF_L3_V6_CMD_DA_EN BIT(0x12) +#define HW_ATL2_RPF_L3_V6_CMD_PROTO_EN BIT(0x13) +#define HW_ATL2_RPF_L4_CMD_EN BIT(0) +#define HW_ATL2_RPF_L4_CMD_DP_EN BIT(1) +#define HW_ATL2_RPF_L4_CMD_SP_EN BIT(2) +#define HW_ATL2_ART_TOTAL_ENTRIES 128 + #define HW_ATL2_ACTION(ACTION, RSS, INDEX, VALID) \ ((((ACTION) & 0x3U) << 8) | \ (((RSS) & 0x1U) << 7) | \ @@ -94,6 +110,13 @@ enum HW_ATL2_RPF_ART_INDEX { #define HW_ATL2_ACTION_DISABLE HW_ATL2_ACTION(0, 0, 0, 0) #define HW_ATL2_ACTION_ASSIGN_QUEUE(QUEUE) HW_ATL2_ACTION(1, 0, (QUEUE), 1) #define HW_ATL2_ACTION_ASSIGN_TC(TC) HW_ATL2_ACTION(1, 1, (TC), 1) +#define HW_ATL2_RPF_L3L4_FILTERS 8 +#define HW_ATL2_RPF_L3V4_FILTERS 8 +#define HW_ATL2_RPF_L3V6_FILTERS 6 +#define HW_ATL2_RPF_L4_FILTERS 8 +#define HW_ATL2_RPF_VLAN_FILTERS 16 +#define HW_ATL2_RPF_ETYPE_FILTERS 16 +#define HW_ATL2_RPF_ETYPE_TAGS 7 enum HW_ATL2_RPF_RSS_HASH_TYPE { HW_ATL2_RPF_RSS_HASH_TYPE_NONE = 0, @@ -119,9 +142,54 @@ enum HW_ATL2_RPF_RSS_HASH_TYPE { #define HW_ATL_MCAST_FLT_ANY_TO_HOST 0x00010FFFU +struct hw_atl2_l3_filter { + u8 proto; + u8 usage; + u32 cmd; + u32 srcip[4]; + u32 dstip[4]; +}; + +struct hw_atl2_l4_filter { + u8 usage; + u32 cmd; + u16 sport; + u16 dport; +}; + +struct hw_atl2_l3l4_filter { + s8 l3_index; + s8 l4_index; + u8 ipv6; +}; + +struct hw_atl2_tag_policy { + u16 action; + u16 usage; +}; + struct hw_atl2_priv { + struct hw_atl2_l3_filter l3_v4_filters[HW_ATL2_RPF_L3L4_FILTERS]; + struct hw_atl2_l3_filter l3_v6_filters[HW_ATL2_RPF_L3L4_FILTERS]; + struct hw_atl2_l4_filter l4_filters[HW_ATL2_RPF_L3L4_FILTERS]; + struct hw_atl2_l3l4_filter l3l4_filters[HW_ATL2_RPF_L3L4_FILTERS]; + struct hw_atl2_tag_policy etype_policy[HW_ATL2_RPF_ETYPE_FILTERS]; struct statistics_s last_stats; unsigned int art_base_index; + unsigned int art_count; + unsigned int l2_filters_base_index; + unsigned int l2_filter_count; + unsigned int etype_filter_base_index; + unsigned int etype_filter_count; + unsigned int etype_filter_tag_top; + unsigned int vlan_filter_base_index; + unsigned int vlan_filter_count; + unsigned int l3_v4_filter_base_index; + unsigned int l3_v4_filter_count; + unsigned int l3_v6_filter_base_index; + unsigned int l3_v6_filter_count; + unsigned int l4_filter_base_index; + unsigned int l4_filter_count; }; #endif /* HW_ATL2_INTERNAL_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_llh.c index cd954b11d24a..2414e60b2028 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_llh.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_llh.c @@ -7,6 +7,13 @@ #include "hw_atl2_llh_internal.h" #include "aq_hw_utils.h" +u32 hw_atl2_phi_ext_tag_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL2_PHI_EXT_TAG_EN_ADR, + HW_ATL2_PHI_EXT_TAG_EN_MSK, + HW_ATL2_PHI_EXT_TAG_EN_SHIFT); +} + void hw_atl2_rpf_redirection_table2_select_set(struct aq_hw_s *aq_hw, u32 select) { @@ -66,6 +73,266 @@ void hw_atl2_rpf_vlan_flr_tag_set(struct aq_hw_s *aq_hw, u32 tag, u32 filter) tag); } +void hw_atl2_rpf_etht_flr_tag_set(struct aq_hw_s *aq_hw, u32 tag, u32 filter) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_ET_TAG_ADR(filter), + HW_ATL2_RPF_ET_TAG_MSK, + HW_ATL2_RPF_ET_TAG_SHIFT, tag); +} + +u32 hw_atl2_rpf_etht_flr_tag_get(struct aq_hw_s *aq_hw, u32 filter) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL2_RPF_ET_TAG_ADR(filter), + HW_ATL2_RPF_ET_TAG_MSK, + HW_ATL2_RPF_ET_TAG_SHIFT); +} + +void hw_atl2_rpf_l3_v4_dest_addr_set(struct aq_hw_s *aq_hw, u32 filter, u32 val) +{ + u32 addr_set = 6 + ((filter < 4) ? 0 : 1); + u32 dword = filter % 4; + + aq_hw_write_reg(aq_hw, HW_ATL2_RPF_L3_DA_DW_ADR(addr_set, dword), val); +} + +void hw_atl2_rpf_l3_v4_src_addr_set(struct aq_hw_s *aq_hw, u32 filter, u32 val) +{ + u32 addr_set = 6 + ((filter < 4) ? 0 : 1); + u32 dword = filter % 4; + + aq_hw_write_reg(aq_hw, HW_ATL2_RPF_L3_SA_DW_ADR(addr_set, dword), val); +} + +void hw_atl2_rpf_l3_v6_dest_addr_set(struct aq_hw_s *aq_hw, u8 location, + u32 *ipv6_dst) +{ + int i; + + for (i = 0; i < 4; ++i) + aq_hw_write_reg(aq_hw, + HW_ATL2_RPF_L3_DA_DW_ADR(location, 3 - i), + ipv6_dst[i]); +} + +void hw_atl2_rpf_l3_v6_src_addr_set(struct aq_hw_s *aq_hw, u8 location, + u32 *ipv6_src) +{ + int i; + + for (i = 0; i < 4; ++i) + aq_hw_write_reg(aq_hw, + HW_ATL2_RPF_L3_SA_DW_ADR(location, 3 - i), + ipv6_src[i]); +} + +void hw_atl2_rpf_l3_v4_cmd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L3_V4_CMD_ADR(filter), + HW_ATL2_RPF_L3_V4_CMD_MSK, + HW_ATL2_RPF_L3_V4_CMD_SHIFT, val); +} + +void hw_atl2_rpf_l3_v6_cmd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L3_V6_CMD_ADR(filter), + HW_ATL2_RPF_L3_V6_CMD_MSK, + HW_ATL2_RPF_L3_V6_CMD_SHIFT, val); +} + +void hw_atl2_rpf_l3_v6_v4_select_set(struct aq_hw_s *aq_hw, u32 val) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L3_V6_V4_SELECT_ADR, + HW_ATL2_RPF_L3_V6_V4_SELECT_MSK, + HW_ATL2_RPF_L3_V6_V4_SELECT_SHIFT, val); +} + +void hw_atl2_rpf_l3_v4_tag_set(struct aq_hw_s *aq_hw, u32 val, u32 filter) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L3_V4_TAG_ADR(filter), + HW_ATL2_RPF_L3_V4_TAG_MSK, + HW_ATL2_RPF_L3_V4_TAG_SHIFT, val); +} + +void hw_atl2_rpf_l3_v6_tag_set(struct aq_hw_s *aq_hw, u32 val, u32 filter) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L3_V6_TAG_ADR(filter), + HW_ATL2_RPF_L3_V6_TAG_MSK, + HW_ATL2_RPF_L3_V6_TAG_SHIFT, val); +} + +void hw_atl2_rpf_l4_tag_set(struct aq_hw_s *aq_hw, u32 val, u32 filter) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L4_TAG_ADR(filter), + HW_ATL2_RPF_L4_TAG_MSK, + HW_ATL2_RPF_L4_TAG_SHIFT, val); +} + +void hw_atl2_rpf_l4_cmd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_RPF_L4_CMD_ADR(filter), + HW_ATL2_RPF_L4_CMD_MSK, + HW_ATL2_RPF_L4_CMD_SHIFT, val); +} + +/* tsg */ +static void hw_atl2_clock_modif_value_set(struct aq_hw_s *aq_hw, + u32 clock_sel, u64 ns) +{ + aq_hw_write_reg64(aq_hw, + HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_MODIF_VAL_LSW), + ns); +} + +void hw_atl2_tsg_clock_en(struct aq_hw_s *aq_hw, + u32 clock_sel, u32 clock_enable) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_CFG), + HW_ATL2_TSG_CLOCK_EN_MSK, + HW_ATL2_TSG_CLOCK_EN_SHIFT, + clock_enable); +} + +void hw_atl2_tsg_clock_reset(struct aq_hw_s *aq_hw, u32 clock_sel) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_CFG), + HW_ATL2_TSG_SYNC_RESET_MSK, + HW_ATL2_TSG_SYNC_RESET_SHIFT, 1); + aq_hw_write_reg_bit(aq_hw, HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_CFG), + HW_ATL2_TSG_SYNC_RESET_MSK, + HW_ATL2_TSG_SYNC_RESET_SHIFT, 0); +} + +u64 hw_atl2_tsg_clock_read(struct aq_hw_s *aq_hw, u32 clock_sel) +{ + return aq_hw_read_reg64(aq_hw, + HW_ATL2_TSG_REG_ADR(clock_sel, + READ_CUR_NS_LSW)); +} + +void hw_atl2_tsg_clock_add(struct aq_hw_s *aq_hw, u32 clock_sel, u64 ns) +{ + hw_atl2_clock_modif_value_set(aq_hw, clock_sel, ns); + aq_hw_write_reg(aq_hw, + HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_MODIF_CTRL), + HW_ATL2_TSG_ADD_COUNTER_MSK); +} + +void hw_atl2_tsg_clock_sub(struct aq_hw_s *aq_hw, u32 clock_sel, u64 ns) +{ + hw_atl2_clock_modif_value_set(aq_hw, clock_sel, ns); + aq_hw_write_reg(aq_hw, + HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_MODIF_CTRL), + HW_ATL2_TSG_SUBTRACT_COUNTER_MSK); +} + +void hw_atl2_tsg_clock_increment_set(struct aq_hw_s *aq_hw, + u32 clock_sel, u32 ns, u32 fns) +{ + u32 nsfns = (ns & 0xff) | (fns & 0xffffff00); + + aq_hw_write_reg(aq_hw, + HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_INC_CFG), + nsfns); + aq_hw_write_reg(aq_hw, + HW_ATL2_TSG_REG_ADR(clock_sel, CLOCK_MODIF_CTRL), + HW_ATL2_TSG_LOAD_INC_CFG_MSK); +} + +void hw_atl2_tpb_tps_highest_priority_tc_enable_set(struct aq_hw_s *aq_hw, + u32 tps_highest_prio_tc_en) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_TPB_HIGHEST_PRIO_TC_EN_ADR, + HW_ATL2_TPB_HIGHEST_PRIO_TC_EN_MSK, + HW_ATL2_TPB_HIGHEST_PRIO_TC_EN_SHIFT, + tps_highest_prio_tc_en); +} + +void hw_atl2_tpb_tps_highest_priority_tc_set(struct aq_hw_s *aq_hw, + u32 tps_highest_prio_tc) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_TPB_HIGHEST_PRIO_TC_ADR, + HW_ATL2_TPB_HIGHEST_PRIO_TC_MSK, + HW_ATL2_TPB_HIGHEST_PRIO_TC_SHIFT, + tps_highest_prio_tc); +} + +void hw_atl2_tsg_gpio_isr_to_host_set(struct aq_hw_s *aq_hw, + int on, u32 clock_sel) +{ + aq_hw_write_reg_bit(aq_hw, + HW_ATL2_GLOBAL_HIGH_PRIO_INTERRUPT_1_MASK_ADR, + clock_sel == 1 ? HW_ATL2_TSG_TSG1_GPIO_INTERRUPT_MSK : + HW_ATL2_TSG_TSG0_GPIO_INTERRUPT_MSK, + clock_sel == 1 ? HW_ATL2_TSG_TSG1_GPIO_INTERRUPT_SHIFT : + HW_ATL2_TSG_TSG0_GPIO_INTERRUPT_SHIFT, + !!on); +} + +void hw_atl2_tsg_gpio_clear_status(struct aq_hw_s *aq_hw) +{ + aq_hw_read_reg(aq_hw, HW_ATL2_GLOBAL_INTERNAL_ALARMS_1_ADR); +} + +void hw_atl2_tsg_gpio_input_event_info_get(struct aq_hw_s *aq_hw, + u32 clock_sel, + u32 *event_count, + u64 *event_ts) +{ + if (event_count) + *event_count = aq_hw_read_reg(aq_hw, + HW_ATL2_TSG_REG_ADR(clock_sel, + EXT_CLK_COUNT)); + + if (event_ts) + *event_ts = aq_hw_read_reg64(aq_hw, + HW_ATL2_TSG_REG_ADR(clock_sel, + GPIO_EVENT_TS_LSW)); +} + +void hw_atl2_tsg_ptp_gpio_gen_pulse(struct aq_hw_s *aq_hw, u32 clk_sel, + u64 ts, u32 period, u32 hightime) +{ + u32 val = (HW_ATL2_TSG_GPIO_EVENT_MODE_SET_ON_TIME << + (HW_ATL2_TSG_GPIO_EVENT_MODE_SHIFT - + HW_ATL2_TSG_GPIO_OUTPUT_EN_SHIFT)) | + (HW_ATL2_TSG_GPIO_GEN_OUTPUT_EN_MSK) | + (HW_ATL2_TSG_GPIO_OUTPUT_EN_MSK); + + if (ts != 0) { + aq_hw_write_reg64(aq_hw, + HW_ATL2_TSG_REG_ADR(clk_sel, + GPIO_EVENT_GEN_TS_LSW), + ts); + + aq_hw_write_reg64(aq_hw, + HW_ATL2_TSG_REG_ADR(clk_sel, + GPIO_EVENT_HIGH_TIME_LSW), + hightime); + + aq_hw_write_reg64(aq_hw, + HW_ATL2_TSG_REG_ADR(clk_sel, + GPIO_EVENT_LOW_TIME_LSW), + (period - hightime)); + } + + aq_hw_write_reg_bit(aq_hw, + HW_ATL2_TSG_REG_ADR(clk_sel, GPIO_EVENT_GEN_CFG), + HW_ATL2_TSG_GPIO_EVENT_MODE_MSK | + HW_ATL2_TSG_GPIO_OUTPUT_EN_MSK | + HW_ATL2_TSG_GPIO_GEN_OUTPUT_EN_MSK, + HW_ATL2_TSG_GPIO_OUTPUT_EN_SHIFT, + (!ts ? 0 : val)); +} + +void hw_atl2_rpf_rx_desc_timestamp_req_set(struct aq_hw_s *aq_hw, u32 request, + u32 descriptor) +{ + aq_hw_write_reg_bit(aq_hw, + HW_ATL2_RPF_TIMESTAMP_REQ_DESCD_ADR(descriptor), + HW_ATL2_RPF_TIMESTAMP_REQ_DESCD_MSK, + HW_ATL2_RPF_TIMESTAMP_REQ_DESCD_SHIFT, request); +} + /* TX */ void hw_atl2_tpb_tx_tc_q_rand_map_en_set(struct aq_hw_s *aq_hw, @@ -93,6 +360,30 @@ void hw_atl2_reg_tx_intr_moder_ctrl_set(struct aq_hw_s *aq_hw, tx_intr_moderation_ctl); } +void hw_atl2_tdm_tx_desc_timestamp_writeback_en_set(struct aq_hw_s *aq_hw, + u32 enable, u32 descriptor) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_TDM_DESCD_TS_WRB_EN_ADR(descriptor), + HW_ATL2_TDM_DESCD_TS_WRB_EN_MSK, + HW_ATL2_TDM_DESCD_TS_WRB_EN_SHIFT, enable); +} + +void hw_atl2_tdm_tx_desc_timestamp_en_set(struct aq_hw_s *aq_hw, u32 enable, + u32 descriptor) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_TDM_DESCD_TS_EN_ADR(descriptor), + HW_ATL2_TDM_DESCD_TS_EN_MSK, + HW_ATL2_TDM_DESCD_TS_EN_SHIFT, enable); +} + +void hw_atl2_tdm_tx_desc_avb_en_set(struct aq_hw_s *aq_hw, u32 enable, + u32 descriptor) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_TDM_DESCD_AVB_EN_ADR(descriptor), + HW_ATL2_TDM_DESCD_AVB_EN_MSK, + HW_ATL2_TDM_DESCD_AVB_EN_SHIFT, enable); +} + void hw_atl2_tps_tx_pkt_shed_data_arb_mode_set(struct aq_hw_s *aq_hw, const u32 data_arb_mode) { @@ -122,6 +413,20 @@ void hw_atl2_tps_tx_pkt_shed_tc_data_weight_set(struct aq_hw_s *aq_hw, weight); } +void hw_atl2_tdm_tx_data_read_req_limit_set(struct aq_hw_s *aq_hw, u32 limit) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_TDM_TX_DATA_RD_REQ_LIMIT_ADR, + HW_ATL2_TDM_TX_DATA_RD_REQ_LIMIT_MSK, + HW_ATL2_TDM_TX_DATA_RD_REQ_LIMIT_SHIFT, limit); +} + +void hw_atl2_tdm_tx_desc_read_req_limit_set(struct aq_hw_s *aq_hw, u32 limit) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_TDM_TX_DESC_RD_REQ_LIMIT_ADR, + HW_ATL2_TDM_TX_DESC_RD_REQ_LIMIT_MSK, + HW_ATL2_TDM_TX_DESC_RD_REQ_LIMIT_SHIFT, limit); +} + u32 hw_atl2_get_hw_version(struct aq_hw_s *aq_hw) { return aq_hw_read_reg(aq_hw, HW_ATL2_FPGA_VER_ADR); @@ -164,6 +469,13 @@ void hw_atl2_rpf_act_rslvr_section_en_set(struct aq_hw_s *aq_hw, u32 sections) sections); } +u32 hw_atl2_rpf_act_rslvr_section_en_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL2_RPF_REC_TAB_EN_ADR, + HW_ATL2_RPF_REC_TAB_EN_MSK, + HW_ATL2_RPF_REC_TAB_EN_SHIFT); +} + void hw_atl2_mif_shared_buf_get(struct aq_hw_s *aq_hw, int offset, u32 *data, int len) { @@ -232,3 +544,13 @@ void hw_atl2_mif_host_req_int_clr(struct aq_hw_s *aq_hw, u32 val) return aq_hw_write_reg(aq_hw, HW_ATL2_MCP_HOST_REQ_INT_CLR_ADR, val); } + +void hw_atl2_gpio_special_mode_set(struct aq_hw_s *aq_hw, + u32 gpio_special_mode, + u32 pin) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL2_GPIO_PIN_SPEC_MODE_ADR(pin), + HW_ATL2_GPIO_PIN_SPEC_MODE_MSK, + HW_ATL2_GPIO_PIN_SPEC_MODE_SHIFT, + gpio_special_mode); +} diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_llh.h index 98c7a4621297..00dcc3e0184f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_llh.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_llh.h @@ -10,6 +10,9 @@ struct aq_hw_s; +/* Get Enable usage of extended tags from 32-255. */ +u32 hw_atl2_phi_ext_tag_get(struct aq_hw_s *aq_hw); + /* Set TX Interrupt Moderation Control Register */ void hw_atl2_reg_tx_intr_moder_ctrl_set(struct aq_hw_s *aq_hw, u32 tx_intr_moderation_ctl, @@ -19,7 +22,7 @@ void hw_atl2_reg_tx_intr_moder_ctrl_set(struct aq_hw_s *aq_hw, void hw_atl2_rpf_redirection_table2_select_set(struct aq_hw_s *aq_hw, u32 select); -/** Set RSS HASH type */ +/* Set RSS HASH type */ void hw_atl2_rpf_rss_hash_type_set(struct aq_hw_s *aq_hw, u32 rss_hash_type); /* set new RPF enable */ @@ -37,14 +40,91 @@ void hw_atl2_new_rpf_rss_redir_set(struct aq_hw_s *aq_hw, u32 tc, u32 index, /* Set VLAN filter tag */ void hw_atl2_rpf_vlan_flr_tag_set(struct aq_hw_s *aq_hw, u32 tag, u32 filter); +/* set ethertype filter tag */ +void hw_atl2_rpf_etht_flr_tag_set(struct aq_hw_s *aq_hw, u32 tag, u32 filter); + +/* get ethertype filter tag */ +u32 hw_atl2_rpf_etht_flr_tag_get(struct aq_hw_s *aq_hw, u32 filter); + +/* set L3 v4 dest address */ +void hw_atl2_rpf_l3_v4_dest_addr_set(struct aq_hw_s *aq_hw, + u32 filter, u32 val); + +/* set L3 v4 src address */ +void hw_atl2_rpf_l3_v4_src_addr_set(struct aq_hw_s *aq_hw, u32 filter, u32 val); + +/* set L3 v4 cmd */ +void hw_atl2_rpf_l3_v4_cmd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter); + +/* set L3 v6 cmd */ +void hw_atl2_rpf_l3_v6_cmd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter); + +/* set L3 v6 dest address */ +void hw_atl2_rpf_l3_v6_dest_addr_set(struct aq_hw_s *aq_hw, u8 location, + u32 *ipv6_dst); + +/* set L3 v6 src address */ +void hw_atl2_rpf_l3_v6_src_addr_set(struct aq_hw_s *aq_hw, u8 location, + u32 *ipv6_src); + +/* set L3 v6 v4 select */ +void hw_atl2_rpf_l3_v6_v4_select_set(struct aq_hw_s *aq_hw, u32 val); + +/* set L3 v4 tag */ +void hw_atl2_rpf_l3_v4_tag_set(struct aq_hw_s *aq_hw, u32 val, u32 filter); + +/* set L3 v6 tag */ +void hw_atl2_rpf_l3_v6_tag_set(struct aq_hw_s *aq_hw, u32 val, u32 filter); + +/* set L4 cmd */ +void hw_atl2_rpf_l4_cmd_set(struct aq_hw_s *aq_hw, u32 val, u32 filter); + +/* set L4 tag */ +void hw_atl2_rpf_l4_tag_set(struct aq_hw_s *aq_hw, u32 val, u32 filter); /* set tx random TC-queue mapping enable bit */ void hw_atl2_tpb_tx_tc_q_rand_map_en_set(struct aq_hw_s *aq_hw, const u32 tc_q_rand_map_en); +void hw_atl2_tpb_tps_highest_priority_tc_enable_set(struct aq_hw_s *aq_hw, + u32 tps_highest_prio_tc_en); + +void hw_atl2_tpb_tps_highest_priority_tc_set(struct aq_hw_s *aq_hw, + u32 tps_highest_prio_tc); + /* set tx buffer clock gate enable */ void hw_atl2_tpb_tx_buf_clk_gate_en_set(struct aq_hw_s *aq_hw, u32 clk_gate_en); +/* tsg */ + +void hw_atl2_tsg_clock_en(struct aq_hw_s *aq_hw, u32 clock_sel, + u32 clock_enable); + +void hw_atl2_tsg_clock_reset(struct aq_hw_s *aq_hw, u32 clock_sel); +u64 hw_atl2_tsg_clock_read(struct aq_hw_s *aq_hw, u32 clock_sel); +void hw_atl2_tsg_clock_add(struct aq_hw_s *aq_hw, u32 clock_sel, + u64 ns); +void hw_atl2_tsg_clock_sub(struct aq_hw_s *aq_hw, u32 clock_sel, + u64 ns); +void hw_atl2_tsg_clock_increment_set(struct aq_hw_s *aq_hw, u32 clock_sel, + u32 ns, u32 fns); +void hw_atl2_tsg_gpio_isr_to_host_set(struct aq_hw_s *aq_hw, int on, + u32 clock_sel); +void hw_atl2_tsg_gpio_clear_status(struct aq_hw_s *aq_hw); +void hw_atl2_tsg_gpio_input_event_info_get(struct aq_hw_s *aq_hw, + u32 clock_sel, + u32 *event_count, + u64 *event_ts); +/* Set Rx Descriptor0 Timestamp request */ +void hw_atl2_rpf_rx_desc_timestamp_req_set(struct aq_hw_s *aq_hw, u32 request, + u32 descriptor); +/* Set Tx Descriptor Timestamp writeback Enable */ +void hw_atl2_tdm_tx_desc_timestamp_writeback_en_set(struct aq_hw_s *aq_hw, + u32 enable, + u32 descriptor); +/* Set Tx Descriptor Timestamp enable */ +void hw_atl2_tdm_tx_desc_timestamp_en_set(struct aq_hw_s *aq_hw, u32 enable, + u32 descriptor); void hw_atl2_tps_tx_pkt_shed_data_arb_mode_set(struct aq_hw_s *aq_hw, const u32 data_arb_mode); @@ -57,6 +137,15 @@ void hw_atl2_tps_tx_pkt_shed_tc_data_max_credit_set(struct aq_hw_s *aq_hw, void hw_atl2_tps_tx_pkt_shed_tc_data_weight_set(struct aq_hw_s *aq_hw, const u32 tc, const u32 weight); +/* Set Tx Descriptor AVB enable */ +void hw_atl2_tdm_tx_desc_avb_en_set(struct aq_hw_s *aq_hw, u32 enable, + u32 descriptor); +void hw_atl2_tsg_ptp_gpio_gen_pulse(struct aq_hw_s *aq_hw, u32 clk_sel, + u64 ts, u32 period, u32 hightime); + +void hw_atl2_tdm_tx_data_read_req_limit_set(struct aq_hw_s *aq_hw, u32 limit); + +void hw_atl2_tdm_tx_desc_read_req_limit_set(struct aq_hw_s *aq_hw, u32 limit); u32 hw_atl2_get_hw_version(struct aq_hw_s *aq_hw); @@ -69,6 +158,9 @@ void hw_atl2_rpf_act_rslvr_record_set(struct aq_hw_s *aq_hw, u8 location, /* set enable action resolver section */ void hw_atl2_rpf_act_rslvr_section_en_set(struct aq_hw_s *aq_hw, u32 sections); +/* get enable action resolver section */ +u32 hw_atl2_rpf_act_rslvr_section_en_get(struct aq_hw_s *aq_hw); + /* get data from firmware shared input buffer */ void hw_atl2_mif_shared_buf_get(struct aq_hw_s *aq_hw, int offset, u32 *data, int len); @@ -99,4 +191,7 @@ u32 hw_atl2_mif_host_req_int_get(struct aq_hw_s *aq_hw); /* clear host interrupt request */ void hw_atl2_mif_host_req_int_clr(struct aq_hw_s *aq_hw, u32 val); +/* Set GPIO Special Mode */ +void hw_atl2_gpio_special_mode_set(struct aq_hw_s *aq_hw, + u32 gpio_special_mode, u32 pin); #endif /* HW_ATL2_LLH_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_llh_internal.h index e34c5cda061e..9b9be3ef1332 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_llh_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_llh_internal.h @@ -5,6 +5,11 @@ #ifndef HW_ATL2_LLH_INTERNAL_H #define HW_ATL2_LLH_INTERNAL_H +/* RX timestamp_req_desc{D} [1:0] Bitfield Definitions + */ +#define HW_ATL2_RPF_TIMESTAMP_REQ_DESCD_ADR(descr) (0x00005B08 + (descr) * 0x20) +#define HW_ATL2_RPF_TIMESTAMP_REQ_DESCD_MSK 0x00030000 +#define HW_ATL2_RPF_TIMESTAMP_REQ_DESCD_SHIFT 16 /* RX pif_rpf_redir_2_en_i Bitfield Definitions * PORT="pif_rpf_redir_2_en_i" @@ -114,7 +119,68 @@ #define HW_ATL2_RPF_VL_TAG_WIDTH 4 /* default value of bitfield vlan_req_tag0{f}[3:0] */ #define HW_ATL2_RPF_VL_TAG_DEFAULT 0x0 +/* register address for bitfield etype_req_tag0{f}[2:0] */ +#define HW_ATL2_RPF_ET_TAG_ADR(filter) (0x00005340 + (filter) * 0x4) +/* bitmask for bitfield etype_req_tag0{f}[2:0] */ +#define HW_ATL2_RPF_ET_TAG_MSK 0x00000007 +/* lower bit position of bitfield etype_req_tag0{f}[2:0] */ +#define HW_ATL2_RPF_ET_TAG_SHIFT 0 +/* Lower bit position of bitfield l3_l4_act{F}[2:0] */ +#define HW_ATL2_RPF_L3_L4_ACTF_SHIFT 16 +/* Bitmask for bitfield l3_l4_rxq{F}[4:0] */ +#define HW_ATL2_RPF_L3_L4_RXQF_MSK 0x00001F00u +/* Lower bit position of bitfield l3_l4_rxq{F}[4:0] */ +#define HW_ATL2_RPF_L3_L4_RXQF_SHIFT 8 +/* Register address for bitfield rpf_l3_v6_sa{F}_dw{D}[1F:0] */ +#define HW_ATL2_RPF_L3_SA_DW_ADR(filter, dword) \ + (0x00006400u + (filter) * 0x10 + (dword) * 0x4) +/* Register address for bitfield rpf_l3_v6_da{F}_dw{D}[1F:0] */ +#define HW_ATL2_RPF_L3_DA_DW_ADR(filter, dword) \ + (0x00006480u + (filter) * 0x10 + (dword) * 0x4) + +/* Register address for bitfield rpf_l3_cmd{F}[1F:0] */ +#define HW_ATL2_RPF_L3_V4_CMD_ADR(filter) (0x00006500u + (filter) * 0x4) +/* Bitmask for bitfield rpf_l3_cmd{F}[F:0] */ +#define HW_ATL2_RPF_L3_V4_CMD_MSK 0x0000FFFFu +/* Lower bit position of bitfield rpf_l3_cmd{F}[1F:0] */ +#define HW_ATL2_RPF_L3_V4_CMD_SHIFT 0 +/* Register address for bitfield rpf_l3_v6_cmd{F}[1F:0] */ +#define HW_ATL2_RPF_L3_V6_CMD_ADR(filter) (0x00006500u + (filter) * 0x4) +/* Bitmask for bitfield rpf_l3_v6_cmd{F}[F:0] */ +#define HW_ATL2_RPF_L3_V6_CMD_MSK 0xFF7F0000u +/* Lower bit position of bitfield rpf_l3_v6_cmd{F}[1F:0] */ +#define HW_ATL2_RPF_L3_V6_CMD_SHIFT 0 +/* Register address for bitfield rpf_l3_v6_cmd{F}[F:0] */ +#define HW_ATL2_RPF_L3_V6_V4_SELECT_ADR 0x00006500u +/* Bitmask for bitfield pif_rpf_l3_v6_v4_select*/ +#define HW_ATL2_RPF_L3_V6_V4_SELECT_MSK 0x00800000u +/* Lower bit position of bitfield pif_rpf_l3_v6_v4_select */ +#define HW_ATL2_RPF_L3_V6_V4_SELECT_SHIFT 23 +/* Register address for bitfield rpf_l3_v4_req_tag{F}[2:0] */ +#define HW_ATL2_RPF_L3_V4_TAG_ADR(filter) (0x00006500u + (filter) * 0x4) +/* Bitmask for bitfield rpf_l3_v4_req_tag{F}[2:0] */ +#define HW_ATL2_RPF_L3_V4_TAG_MSK 0x00000070u +/* Lower bit position of bitfield rpf_l3_v4_req_tag{F}[2:0] */ +#define HW_ATL2_RPF_L3_V4_TAG_SHIFT 4 +/* Register address for bitfield rpf_l3_v6_req_tag{F}[2:0] */ +#define HW_ATL2_RPF_L3_V6_TAG_ADR(filter) (0x00006500u + (filter) * 0x4) +/* Bitmask for bitfield rpf_l3_v6_req_tag{F}[2:0] */ +#define HW_ATL2_RPF_L3_V6_TAG_MSK 0x00700000 +/* Lower bit position of bitfield rpf_l3_v6_req_tag{F}[2:0] */ +#define HW_ATL2_RPF_L3_V6_TAG_SHIFT 20 +/* Register address for bitfield rpf_l4_cmd{F}[2:0] */ +#define HW_ATL2_RPF_L4_CMD_ADR(filter) (0x00006520u + (filter) * 0x4) +/* Bitmask for bitfield rpf_l4_cmd{F}[2:0] */ +#define HW_ATL2_RPF_L4_CMD_MSK 0x00000007u +/* Lower bit position of bitfield rpf_l4_cmd{F}[2:0] */ +#define HW_ATL2_RPF_L4_CMD_SHIFT 0 +/* Register address for bitfield rpf_l4_tag{F}[2:0] */ +#define HW_ATL2_RPF_L4_TAG_ADR(filter) (0x00006520u + (filter) * 0x4) +/* Bitmask for bitfield rpf_l4_tag{F}[2:0] */ +#define HW_ATL2_RPF_L4_TAG_MSK 0x00000070u +/* Lower bit position of bitfield rpf_l4_tag{F}[2:0] */ +#define HW_ATL2_RPF_L4_TAG_SHIFT 4 /* RX rx_q{Q}_tc_map[2:0] Bitfield Definitions * Preprocessor definitions for the bitfield "rx_q{Q}_tc_map[2:0]". * Parameter: Queue {Q} | bit-level stride | range [0, 31] @@ -131,7 +197,24 @@ #define HW_ATL2_RX_Q_TC_MAP_WIDTH 3 /* Default value of bitfield rx_q{Q}_tc_map[2:0] */ #define HW_ATL2_RX_Q_TC_MAP_DEFAULT 0x0 - +/* TX desc{D}_ts_wrb_en Bitfield Definitions + */ +#define HW_ATL2_TDM_DESCD_TS_WRB_EN_ADR(descriptor) \ + (0x00007C08 + (descriptor) * 0x40) +#define HW_ATL2_TDM_DESCD_TS_WRB_EN_MSK 0x00040000 +#define HW_ATL2_TDM_DESCD_TS_WRB_EN_SHIFT 18 +/* TX desc{D}_ts_en Bitfield Definitions + */ +#define HW_ATL2_TDM_DESCD_TS_EN_ADR(descriptor) \ + (0x00007C08 + (descriptor) * 0x40) +#define HW_ATL2_TDM_DESCD_TS_EN_MSK 0x00020000 +#define HW_ATL2_TDM_DESCD_TS_EN_SHIFT 17 +/* TX desc{D}_avb_en Bitfield Definitions + */ +#define HW_ATL2_TDM_DESCD_AVB_EN_ADR(descriptor) \ + (0x00007C08 + (descriptor) * 0x40) +#define HW_ATL2_TDM_DESCD_AVB_EN_MSK 0x00010000 +#define HW_ATL2_TDM_DESCD_AVB_EN_SHIFT 16 /* tx tx_tc_q_rand_map_en bitfield definitions * preprocessor definitions for the bitfield "tx_tc_q_rand_map_en". * port="pif_tpb_tx_tc_q_rand_map_en_i" @@ -221,7 +304,18 @@ #define HW_ATL2_TPS_DATA_TCTCREDIT_MAX_WIDTH 16 /* default value of bitfield data_tc{t}_credit_max[f:0] */ #define HW_ATL2_TPS_DATA_TCTCREDIT_MAX_DEFAULT 0x0 - +/* register address for bitfield pif_tpb_highest_prio_tc_en */ +#define HW_ATL2_TPB_HIGHEST_PRIO_TC_EN_ADR 0x00007180 +/* bitmask for bitfield pif_tpb_highest_prio_tc_en */ +#define HW_ATL2_TPB_HIGHEST_PRIO_TC_EN_MSK 0x00000100 +/* lower bit position of bitfield pif_tpb_highest_prio_tc_en */ +#define HW_ATL2_TPB_HIGHEST_PRIO_TC_EN_SHIFT 8 +/* register address for bitfield pif_tpb_highest_prio_tc */ +#define HW_ATL2_TPB_HIGHEST_PRIO_TC_ADR 0x00007180 +/* bitmask for bitfield pif_tpb_highest_prio_tc */ +#define HW_ATL2_TPB_HIGHEST_PRIO_TC_MSK 0x00000007 +/* lower bit position of bitfield pif_tpb_highest_prio_tc */ +#define HW_ATL2_TPB_HIGHEST_PRIO_TC_SHIFT 0 /* tx data_tc{t}_weight[e:0] bitfield definitions * preprocessor definitions for the bitfield "data_tc{t}_weight[e:0]". * parameter: tc {t} | stride size 0x4 | range [0, 7] @@ -248,7 +342,87 @@ */ #define HW_ATL2_TX_INTR_MODERATION_CTL_ADR(queue) (0x00007c28u + (queue) * 0x40) +/* TX tx_data_rd_req_limit[7:0] Bitfield Definitions + */ +#define HW_ATL2_TDM_TX_DATA_RD_REQ_LIMIT_ADR 0x00007B04 +#define HW_ATL2_TDM_TX_DATA_RD_REQ_LIMIT_MSK 0x0000FF00 +#define HW_ATL2_TDM_TX_DATA_RD_REQ_LIMIT_SHIFT 8 +/* TX tx_desc_rd_req_limit[4:0] Bitfield Definitions + */ +#define HW_ATL2_TDM_TX_DESC_RD_REQ_LIMIT_ADR 0x00007B04 +#define HW_ATL2_TDM_TX_DESC_RD_REQ_LIMIT_MSK 0x0000001F +#define HW_ATL2_TDM_TX_DESC_RD_REQ_LIMIT_SHIFT 0 +/* register address for bitfield uP Force Interrupt */ +#define HW_ATL2_GLB_CONTROL_2_ADR 0x00000404 +#define HW_ATL2_MIF_INTERRUPT_2_TO_ITR_MSK 0x00000100 +/* lower bit position of bitfield MIF Interrupt to ITR */ +#define HW_ATL2_MIF_INTERRUPT_TO_ITR_SHIFT 6 +#define HW_ATL2_EN_INTERRUPT_MIF2_TO_ITR_MSK 0x00001000 +/* lower bit position of bitfield Enable MIF Interrupt to ITR */ +#define HW_ATL2_EN_INTERRUPT_TO_ITR_SHIFT 0xA +#define HW_ATL2_GLOBAL_INTERNAL_ALARMS_1_ADR 0x00000924 +#define HW_ATL2_GLOBAL_HIGH_PRIO_INTERRUPT_1_MASK_ADR 0x00000964 +/* bitmask for bitfield TSG PTM GPIO interrupt */ +#define HW_ATL2_TSG_TSG1_GPIO_INTERRUPT_MSK 0x00000200 +/* lower bit position of bitfield TSG PTM GPIO interrupt */ +#define HW_ATL2_TSG_TSG1_GPIO_INTERRUPT_SHIFT 9 +/* bitmask for bitfield TSG0 GPIO interrupt */ +#define HW_ATL2_TSG_TSG0_GPIO_INTERRUPT_MSK 0x00000020 +/* lower bit position of bitfield TSG0 GPIO interrupt */ +#define HW_ATL2_TSG_TSG0_GPIO_INTERRUPT_SHIFT 5 +/* TSG registers */ +#define HW_ATL2_TSG_REG_ADR(clk, reg_name) \ + ((clk) == 0 ? HW_ATL2_CLK0_##reg_name##_ADR :\ + HW_ATL2_CLK1_##reg_name##_ADR) +#define HW_ATL2_CLK0_CLOCK_CFG_ADR 0x00000CA0u +#define HW_ATL2_CLK1_CLOCK_CFG_ADR 0x00000D50u +#define HW_ATL2_TSG_SYNC_RESET_MSK 0x00000001 +#define HW_ATL2_TSG_SYNC_RESET_SHIFT 0x00000000 +#define HW_ATL2_TSG_CLOCK_EN_MSK 0x00000002 +#define HW_ATL2_TSG_CLOCK_EN_SHIFT 0x00000001 +#define HW_ATL2_CLK0_CLOCK_MODIF_CTRL_ADR 0x00000CA4u +#define HW_ATL2_CLK1_CLOCK_MODIF_CTRL_ADR 0x00000D54u +#define HW_ATL2_TSG_SUBTRACT_COUNTER_MSK 0x00000002 +#define HW_ATL2_TSG_ADD_COUNTER_MSK 0x00000004 +#define HW_ATL2_TSG_LOAD_INC_CFG_MSK 0x00000008 +#define HW_ATL2_CLK0_CLOCK_MODIF_VAL_LSW_ADR 0x00000CA8u +#define HW_ATL2_CLK1_CLOCK_MODIF_VAL_LSW_ADR 0x00000D58u +#define HW_ATL2_CLK0_CLOCK_INC_CFG_ADR 0x00000CB0u +#define HW_ATL2_CLK1_CLOCK_INC_CFG_ADR 0x00000D60u +#define HW_ATL2_CLK0_READ_CUR_NS_LSW_ADR 0x00000CB8u +#define HW_ATL2_CLK1_READ_CUR_NS_LSW_ADR 0x00000D68u + +#define HW_ATL2_CLK0_GPIO_CFG_ADR 0x00000CC4u +#define HW_ATL2_CLK1_GPIO_CFG_ADR 0x00000D74u +#define HW_ATL2_TSG_GPIO_IN_MONITOR_EN_SHIFT 0x00000000 +#define HW_ATL2_TSG_GPIO_IN_MONITOR_EN_MSK 0x00000001 +#define HW_ATL2_TSG_GPIO_IN_MODE_SHIFT 0x00000001 +#define HW_ATL2_TSG_GPIO_IN_MODE_MSK 0x00000006 +#define HW_ATL2_TSG_GPIO_IN_MODE_POSEDGE 0x00000000 +#define HW_ATL2_CLK0_EXT_CLK_COUNT_ADR 0x00000CCCu +#define HW_ATL2_CLK1_EXT_CLK_COUNT_ADR 0x00000D7Cu +#define HW_ATL2_CLK0_GPIO_EVENT_TS_LSW_ADR 0x00000CD0u +#define HW_ATL2_CLK1_GPIO_EVENT_TS_LSW_ADR 0x00000D80u +#define HW_ATL2_CLK0_GPIO_EVENT_GEN_TS_LSW_ADR 0x00000CE0u +#define HW_ATL2_CLK1_GPIO_EVENT_GEN_TS_LSW_ADR 0x00000D90u +#define HW_ATL2_CLK0_GPIO_EVENT_GEN_CFG_ADR 0x00000CE8u +#define HW_ATL2_CLK1_GPIO_EVENT_GEN_CFG_ADR 0x00000D98u +#define HW_ATL2_TSG_GPIO_OUTPUT_EN_SHIFT 0x00000000 +#define HW_ATL2_TSG_GPIO_OUTPUT_EN_MSK 0x00000001 +#define HW_ATL2_TSG_GPIO_EVENT_MODE_SHIFT 0x00000001 +#define HW_ATL2_TSG_GPIO_EVENT_MODE_MSK 0x00000006 +#define HW_ATL2_TSG_GPIO_EVENT_MODE_SET_ON_TIME 0x00000003 +#define HW_ATL2_TSG_GPIO_GEN_OUTPUT_EN_MSK 0x00000008 +#define HW_ATL2_CLK0_GPIO_EVENT_HIGH_TIME_LSW_ADR 0x00000CF0u +#define HW_ATL2_CLK1_GPIO_EVENT_HIGH_TIME_LSW_ADR 0x00000DA0u +#define HW_ATL2_CLK0_GPIO_EVENT_LOW_TIME_LSW_ADR 0x00000CF8u +#define HW_ATL2_CLK1_GPIO_EVENT_LOW_TIME_LSW_ADR 0x00000DA8u +/* PCIE Extended tag enable Bitfield Definitions + */ +#define HW_ATL2_PHI_EXT_TAG_EN_ADR 0x00001000 +#define HW_ATL2_PHI_EXT_TAG_EN_MSK 0x00000020 +#define HW_ATL2_PHI_EXT_TAG_EN_SHIFT 5 /* Launch time control register */ #define HW_ATL2_LT_CTRL_ADR 0x00007a1c @@ -387,5 +561,25 @@ #define HW_ATL2_MCP_HOST_REQ_INT_ADR 0x00000F00u #define HW_ATL2_MCP_HOST_REQ_INT_SET_ADR 0x00000F04u #define HW_ATL2_MCP_HOST_REQ_INT_CLR_ADR 0x00000F08u - +/* Register address for bitfield PTP EXT GPIO TS SEL */ +#define HW_ATL2_TSG0_EXT_GPIO_TS_INPUT_SEL_ADR 0x00003664 +/* Bitmask for bitfield PTP EXT GPIO TS SEL */ +#define HW_ATL2_TSG0_EXT_GPIO_TS_INPUT_SEL_MSK 0x00001F00 +/* Lower bit position of bitfield PTP EXT GPIO TS SEL */ +#define HW_ATL2_TSG0_EXT_GPIO_TS_INPUT_SEL_SHIFT 8 +/* Register address for bitfield TSG EXT GPIO TS SEL */ +#define HW_ATL2_TSG1_EXT_GPIO_TS_INPUT_SEL_ADR 0x00003660 +/* Bitmask for bitfield TSG EXT GPIO TS SEL */ +#define HW_ATL2_TSG1_EXT_GPIO_TS_INPUT_SEL_MSK 0x00001F00 +/* Lower bit position of bitfield TSG EXT GPIO TS SEL */ +#define HW_ATL2_TSG1_EXT_GPIO_TS_INPUT_SEL_SHIFT 8 +/* Register address for bitfield GPIO{P} Special Mode */ +#define HW_ATL2_GPIO_PIN_SPEC_MODE_ADR(pin) (0x00003698 + (pin) * 0x4) +/* Bitmask for bitfield GPIO{P} Special Mode */ +#define HW_ATL2_GPIO_PIN_SPEC_MODE_MSK 0x0000000C +/* Lower bit position of bitfield GPIO{P} Special Mode */ +#define HW_ATL2_GPIO_PIN_SPEC_MODE_SHIFT 2 +#define HW_ATL2_GPIO_PIN_SPEC_MODE_TSG1_EVENT_OUTPUT 0 +#define HW_ATL2_GPIO_PIN_SPEC_MODE_TSG0_EVENT_OUTPUT 2 +#define HW_ATL2_GPIO_PIN_SPEC_MODE_GPIO 3 #endif /* HW_ATL2_LLH_INTERNAL_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c index 0fe6257d9c08..ef549e172dd9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c @@ -128,3 +128,37 @@ int hw_atl2_utils_soft_reset(struct aq_hw_s *self) err_exit: return err; } + +static const u32 hw_atl2_utils_hw_mac_regs[] = { + 0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U, + 0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U, + 0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U, + 0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U, + 0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U, + 0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U, + 0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U, + 0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U, + 0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U, + 0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U, + 0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U, + 0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U, + 0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U, + 0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U, + 0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U, + 0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U, + 0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU, + 0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU, +}; + +int hw_atl2_utils_hw_get_regs(struct aq_hw_s *self, + const struct aq_hw_caps_s *aq_hw_caps, + u32 *regs_buff) +{ + unsigned int i; + + for (i = 0; i < min_t(u32, aq_hw_caps->mac_regs_count, + ARRAY_SIZE(hw_atl2_utils_hw_mac_regs)); i++) + regs_buff[i] = aq_hw_read_reg(self, + hw_atl2_utils_hw_mac_regs[i]); + return 0; +} 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 6bad64c77b87..e02ed522b004 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 { + __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 { @@ -626,10 +636,13 @@ int hw_atl2_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops); int hw_atl2_utils_soft_reset(struct aq_hw_s *self); +int hw_atl2_utils_hw_get_regs(struct aq_hw_s *self, + const struct aq_hw_caps_s *aq_hw_caps, + u32 *regs_buff); + u32 hw_atl2_utils_get_fw_version(struct aq_hw_s *self); -int hw_atl2_utils_get_action_resolve_table_caps(struct aq_hw_s *self, - u8 *base_index, u8 *count); +int hw_atl2_utils_get_filter_caps(struct aq_hw_s *self); extern const struct aq_fw_ops aq_a2_fw_ops; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c index 7370e3f76b62..dc9b2ef4640b 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c @@ -121,6 +121,10 @@ static int aq_a2_fw_init(struct aq_hw_s *self) u32 val; int err; + err = hw_atl2_utils_get_filter_caps(self); + if (err) + return err; + hw_atl2_shared_buffer_get(self, link_control, link_control); link_control.mode = AQ_HOST_MODE_ACTIVE; hw_atl2_shared_buffer_write(self, link_control, link_control); @@ -606,18 +610,77 @@ u32 hw_atl2_utils_get_fw_version(struct aq_hw_s *self) version.bundle.build; } -int hw_atl2_utils_get_action_resolve_table_caps(struct aq_hw_s *self, - u8 *base_index, u8 *count) +int hw_atl2_utils_get_filter_caps(struct aq_hw_s *self) { + struct hw_atl2_priv *priv = self->priv; struct filter_caps_s filter_caps; + u32 tag_top; int err; err = hw_atl2_shared_buffer_read_safe(self, filter_caps, &filter_caps); if (err) return err; - *base_index = filter_caps.rslv_tbl_base_index; - *count = filter_caps.rslv_tbl_count; + priv->art_base_index = filter_caps.rslv_tbl_base_index * 8; + priv->art_count = filter_caps.rslv_tbl_count * 8; + if (priv->art_count == 0) + priv->art_count = HW_ATL2_ART_TOTAL_ENTRIES; + priv->l2_filters_base_index = filter_caps.l2_filters_base_index; + if (priv->l2_filters_base_index >= HW_ATL2_MAC_MAX) + priv->l2_filters_base_index = HW_ATL2_MAC_UC; + priv->l2_filter_count = filter_caps.l2_filter_count; + priv->etype_filter_base_index = filter_caps.ethertype_filter_base_index; + priv->etype_filter_count = filter_caps.ethertype_filter_count; + priv->etype_filter_tag_top = + (priv->etype_filter_count >= HW_ATL2_RPF_ETYPE_TAGS) ? + (HW_ATL2_RPF_ETYPE_TAGS) : (HW_ATL2_RPF_ETYPE_TAGS >> 1); + priv->vlan_filter_base_index = filter_caps.vlan_filter_base_index; + /* 0 - no tag, 1 - reserved for vlan-filter-offload filters */ + tag_top = + (filter_caps.vlan_filter_count == HW_ATL2_RPF_VLAN_FILTERS) ? + (HW_ATL2_RPF_VLAN_FILTERS - 2) : + (HW_ATL2_RPF_VLAN_FILTERS / 2 - 2); + + if (filter_caps.vlan_filter_count > 2) { + priv->vlan_filter_count = min_t(u32, + filter_caps.vlan_filter_count - 2, + tag_top); + } else { + pr_debug("atlantic: FW vlan_filter_count=%u <= 2, no usable VLAN filters\n", + filter_caps.vlan_filter_count); + priv->vlan_filter_count = 0; + } + + priv->l3_v4_filter_base_index = filter_caps.l3_ip4_filter_base_index; + if (priv->l3_v4_filter_base_index >= HW_ATL2_RPF_L3V4_FILTERS) { + priv->l3_v4_filter_base_index = 0; + priv->l3_v4_filter_count = 0; + } else { + priv->l3_v4_filter_count = min_t(u32, + filter_caps.l3_ip4_filter_count, + HW_ATL2_RPF_L3V4_FILTERS - 1); + } + + priv->l3_v6_filter_base_index = filter_caps.l3_ip6_filter_base_index; + if (priv->l3_v6_filter_base_index >= HW_ATL2_RPF_L3V6_FILTERS) { + priv->l3_v6_filter_base_index = 0; + priv->l3_v6_filter_count = 0; + } else { + priv->l3_v6_filter_count = min_t(u32, + filter_caps.l3_ip6_filter_count, + HW_ATL2_RPF_L3V6_FILTERS - 1); + } + + priv->l4_filter_base_index = filter_caps.l4_filter_base_index; + if (priv->l4_filter_base_index >= HW_ATL2_RPF_L4_FILTERS) { + priv->l4_filter_base_index = 0; + priv->l4_filter_count = 0; + } else { + priv->l4_filter_count = min_t(u32, + filter_caps.l4_filter_count, + HW_ATL2_RPF_L4_FILTERS - 1); + } + return 0; }