From: Sukhdeep Singh Fix initialization issues in hw_atl2 to correctly support AQC113: - hw_atl2_hw_reset: replace unconditional priv memset with selective field clears so that l3l4_filters[].l3_index and l4_index can be initialized to -1 (not allocated) rather than 0; 0 is a valid filter index and would incorrectly appear as an occupied slot after a reset. - hw_atl2_hw_init_new_rx_filters: use firmware-reported ART section base and count (clamped to 16) instead of hardcoded 0xFFFF mask; enable simultaneous IPv4/IPv6 L3 filter mode (rpf_l3_v6_v4_select); tag the UC MAC slot using firmware-supplied l2_filters_base_index instead of hardcoded HW_ATL2_MAC_UC. - hw_atl2_hw_init_rx_path: enable only the firmware-assigned MAC slot (priv->l2_filters_base_index) instead of always slot 0. - Add hw_atl2_hw_mac_addr_set() that programs the MAC address into the firmware-assigned L2 filter slot. Wire into hw_atl2_ops replacing the A1 hw_atl_b0_hw_mac_addr_set; call it from hw_init. - Wire .hw_get_regs into hw_atl2_ops. Signed-off-by: Sukhdeep Singh --- .../aquantia/atlantic/hw_atl2/hw_atl2.c | 69 +++++++++++++++++-- .../atlantic/hw_atl2/hw_atl2_utils_fw.c | 2 + 2 files changed, 65 insertions(+), 6 deletions(-) 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..27a62fffbc29 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c @@ -11,6 +11,7 @@ #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" @@ -95,12 +96,21 @@ static int hw_atl2_hw_reset(struct aq_hw_s *self) { struct hw_atl2_priv *priv = self->priv; 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; + } self->aq_fw_ops->set_state(self, MPI_RESET); @@ -380,6 +390,9 @@ 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 +407,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 +508,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 +524,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 +557,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] = { @@ -556,7 +612,7 @@ static int hw_atl2_hw_init(struct aq_hw_s *self, const u8 *mac_addr) 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); @@ -825,7 +881,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, @@ -855,6 +911,7 @@ 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, 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 3011c7cd5259..0f603a37218c 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 @@ -627,6 +627,8 @@ int hw_atl2_utils_get_filter_caps(struct aq_hw_s *self) if (priv->art_count == 0) priv->art_count = 128; 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; -- 2.43.0