]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: atlantic: fix AQC113 HW init: ART, L2 filter slot, MAC address
authorSukhdeep Singh <sukhdeeps@marvell.com>
Wed, 10 Jun 2026 11:54:42 +0000 (17:24 +0530)
committerJakub Kicinski <kuba@kernel.org>
Mon, 15 Jun 2026 22:38:43 +0000 (15:38 -0700)
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 <sukhdeeps@marvell.com>
Link: https://patch.msgid.link/20260610115448.272-7-sukhdeeps@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c

index ba9555fb8f116729424d2892bd5dd63c25f07301..ec5b2a03fd6f4a2fa1e521788292f0b205bb676c 100644 (file)
@@ -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] = {
@@ -547,7 +603,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);
@@ -619,6 +675,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;
 
@@ -634,18 +692,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);
@@ -816,7 +874,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,
@@ -846,6 +904,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,
index 12c3f42ab61185ce170113f902007a4c110eb910..dc9b2ef4640b123f57d205293ef98147734144d7 100644 (file)
@@ -626,6 +626,8 @@ int hw_atl2_utils_get_filter_caps(struct aq_hw_s *self)
        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;