[PATCH v2 2/2] net: atlantic: AQC113: Limit multicast filters to available slots

From: Janne Grunau

Date: Sun Nov 08 2026 - 07:44:16 EST


Since commit 6c1ca112a6e4 ("net: atlantic: fix AQC113 HW init: ART,
L2 filter slot, MAC address") hw_atl2_hw_multicast_list_set() uses L2
filter slot above the firmware-assigned L2 filter slot for the MAC
address.
On Apple silicon systems with AQC113 the firmware returns
`l2_filters_base_index = 9` and `l2_filter_count = 29` which is
unfortunately less than AQ_HW_MULTICAST_ADDRESS_MAX (32).
Add a new `struct aq_hw_ops` function pointer
hw_get_num_multicast_addresses() so that atl2 variants can report the
lower number of available L2 filter slots. Use this potentially smaller
number in aq_nic_set_multicast_list() to decide when to switch to
promiscuous mode.

Fixes: 6c1ca112a6e4 ("net: atlantic: fix AQC113 HW init: ART, L2 filter slot, MAC address")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Janne Grunau <j@xxxxxxxxxx>
---
drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 2 ++
drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 7 ++++---
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c | 7 +++++++
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 7 +++++++
drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c | 11 ++++++++++-
5 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 338c956ad1f7..3a4465c11768 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -374,6 +374,8 @@ struct aq_hw_ops {

int (*hw_read_module_eeprom)(struct aq_hw_s *self, u8 dev_addr,
u8 reg_start_addr, int len, u8 *data);
+
+ int (*hw_get_num_multicast_addresses)(struct aq_hw_s *self);
};

struct aq_fw_ops {
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 01792f7abf96..a05e12e8661b 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -973,6 +973,7 @@ int aq_nic_set_packet_filter(struct aq_nic_s *self, unsigned int flags)
int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev)
{
const struct aq_hw_ops *hw_ops = self->aq_hw_ops;
+ int num_multicast_addresses = hw_ops->hw_get_num_multicast_addresses(self->aq_hw);
struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
unsigned int packet_filter = ndev->flags;
struct netdev_hw_addr *ha = NULL;
@@ -980,7 +981,7 @@ int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev)
int err = 0;

self->mc_list.count = 0;
- if (netdev_uc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) {
+ if (netdev_uc_count(ndev) > num_multicast_addresses) {
packet_filter |= IFF_PROMISC;
} else {
netdev_for_each_uc_addr(ha, ndev) {
@@ -990,7 +991,7 @@ int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev)

cfg->is_mc_list_enabled = !!(packet_filter & IFF_MULTICAST);
if (cfg->is_mc_list_enabled) {
- if (i + netdev_mc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) {
+ if (i + netdev_mc_count(ndev) > num_multicast_addresses) {
packet_filter |= IFF_ALLMULTI;
} else {
netdev_for_each_mc_addr(ha, ndev) {
@@ -1000,7 +1001,7 @@ int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev)
}
}

- if (i > 0 && i <= AQ_HW_MULTICAST_ADDRESS_MAX) {
+ if (i > 0 && i <= num_multicast_addresses) {
self->mc_list.count = i;
err = hw_ops->hw_multicast_list_set(self->aq_hw,
self->mc_list.ar,
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index 8de2cdd09213..1d69710c6be7 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
@@ -944,6 +944,11 @@ static int hw_atl_a0_hw_fl3l4_set(struct aq_hw_s *self,
return aq_hw_err_from_flags(self);
}

+static int hw_atl_a0_get_num_multicast_addresses(struct aq_hw_s *self)
+{
+ return AQ_HW_MULTICAST_ADDRESS_MAX;
+}
+
const struct aq_hw_ops hw_atl_ops_a0 = {
.hw_soft_reset = hw_atl_utils_soft_reset,
.hw_prepare = hw_atl_utils_initfw,
@@ -978,4 +983,6 @@ const struct aq_hw_ops hw_atl_ops_a0 = {
.hw_get_regs = hw_atl_utils_hw_get_regs,
.hw_get_hw_stats = hw_atl_utils_get_hw_stats,
.hw_get_fw_version = hw_atl_utils_get_fw_version,
+
+ .hw_get_num_multicast_addresses = hw_atl_a0_get_num_multicast_addresses,
};
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 6c25ad264b19..252455cfd106 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
@@ -1777,6 +1777,11 @@ static int hw_atl_b0_read_module_eeprom(struct aq_hw_s *self, u8 dev_addr,
return err;
}

+static int hw_atl_b0_get_num_multicast_addresses(struct aq_hw_s *self)
+{
+ return AQ_HW_MULTICAST_ADDRESS_MAX;
+}
+
const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_soft_reset = hw_atl_utils_soft_reset,
.hw_prepare = hw_atl_utils_initfw,
@@ -1836,4 +1841,6 @@ const struct aq_hw_ops hw_atl_ops_b0 = {

.hw_get_mac_temp = hw_atl_b0_get_mac_temp,
.hw_read_module_eeprom = hw_atl_b0_read_module_eeprom,
+
+ .hw_get_num_multicast_addresses = hw_atl_b0_get_num_multicast_addresses,
};
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 8d7a489aa5de..d0dc72bd098f 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
@@ -810,7 +810,7 @@ static int hw_atl2_hw_multicast_list_set(struct aq_hw_s *self,
struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
int err = 0;

- if (count > (HW_ATL2_MAC_MAX - HW_ATL2_MAC_MIN)) {
+ if (count > (priv->l2_filter_count - 1)) {
err = -EBADRQC;
goto err_exit;
}
@@ -1635,6 +1635,13 @@ static int hw_atl2_hw_vlan_ctrl(struct aq_hw_s *self, bool enable)
return aq_hw_err_from_flags(self);
}

+static int hw_atl2_get_num_multicast_addresses(struct aq_hw_s *self)
+{
+ struct hw_atl2_priv *priv = self->priv;
+
+ return min_t(int, priv->l2_filter_count - 1, AQ_HW_MULTICAST_ADDRESS_MAX);
+}
+
const struct aq_hw_ops hw_atl2_ops = {
.hw_soft_reset = hw_atl2_utils_soft_reset,
.hw_prepare = hw_atl2_utils_initfw,
@@ -1694,4 +1701,6 @@ const struct aq_hw_ops hw_atl2_ops = {
.hw_get_clk_sel = hw_atl2_hw_get_clk_sel,
.extract_hwts = NULL,
.hw_extts_gpio_enable = NULL,
+
+ .hw_get_num_multicast_addresses = hw_atl2_get_num_multicast_addresses,
};

--
2.56.0