Commit 822b96f8 authored by Daniel Pieczko's avatar Daniel Pieczko Committed by David S. Miller

sfc: re-factor efx_ef10_filter_sync_rx_mode()

This change is only re-factoring; there are no changes to functionality
 except for a slight elaboration of an error message (on mismatch filter
 insertion failure).
Signed-off-by: default avatarEdward Cree <ecree@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b6f568e2
...@@ -49,6 +49,11 @@ enum { ...@@ -49,6 +49,11 @@ enum {
*/ */
#define HUNT_FILTER_TBL_ROWS 8192 #define HUNT_FILTER_TBL_ROWS 8192
struct efx_ef10_dev_addr {
u8 addr[ETH_ALEN];
u16 id;
};
struct efx_ef10_filter_table { struct efx_ef10_filter_table {
/* The RX match field masks supported by this fw & hw, in order of priority */ /* The RX match field masks supported by this fw & hw, in order of priority */
enum efx_filter_match_flags rx_match_flags[ enum efx_filter_match_flags rx_match_flags[
...@@ -69,11 +74,8 @@ struct efx_ef10_filter_table { ...@@ -69,11 +74,8 @@ struct efx_ef10_filter_table {
/* Shadow of net_device address lists, guarded by mac_lock */ /* Shadow of net_device address lists, guarded by mac_lock */
#define EFX_EF10_FILTER_DEV_UC_MAX 32 #define EFX_EF10_FILTER_DEV_UC_MAX 32
#define EFX_EF10_FILTER_DEV_MC_MAX 256 #define EFX_EF10_FILTER_DEV_MC_MAX 256
struct { struct efx_ef10_dev_addr dev_uc_list[EFX_EF10_FILTER_DEV_UC_MAX];
u8 addr[ETH_ALEN]; struct efx_ef10_dev_addr dev_mc_list[EFX_EF10_FILTER_DEV_MC_MAX];
u16 id;
} dev_uc_list[EFX_EF10_FILTER_DEV_UC_MAX],
dev_mc_list[EFX_EF10_FILTER_DEV_MC_MAX];
int dev_uc_count; /* negative for PROMISC */ int dev_uc_count; /* negative for PROMISC */
int dev_mc_count; /* negative for PROMISC/ALLMULTI */ int dev_mc_count; /* negative for PROMISC/ALLMULTI */
}; };
...@@ -3746,23 +3748,10 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx) ...@@ -3746,23 +3748,10 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx)
kfree(table); kfree(table);
} }
/* Caller must hold efx->filter_sem for read if race against static void efx_ef10_filter_mark_old(struct efx_nic *efx)
* efx_ef10_filter_table_remove() is possible
*/
static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
{ {
struct efx_ef10_filter_table *table = efx->filter_state; struct efx_ef10_filter_table *table = efx->filter_state;
struct net_device *net_dev = efx->net_dev; unsigned int filter_idx, i;
struct efx_filter_spec spec;
bool remove_failed = false;
struct netdev_hw_addr *uc;
struct netdev_hw_addr *mc;
unsigned int filter_idx;
int i, rc;
bool uc_promisc = false, mc_promisc = false;
if (!efx_dev_registered(efx))
return;
if (!table) if (!table)
return; return;
...@@ -3778,29 +3767,40 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ...@@ -3778,29 +3767,40 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD;
} }
spin_unlock_bh(&efx->filter_lock); spin_unlock_bh(&efx->filter_lock);
}
static void efx_ef10_filter_uc_addr_list(struct efx_nic *efx, bool *promisc)
{
struct efx_ef10_filter_table *table = efx->filter_state;
struct net_device *net_dev = efx->net_dev;
struct netdev_hw_addr *uc;
unsigned int i;
/* Copy/convert the address lists; add the primary station
* address and broadcast address
*/
netif_addr_lock_bh(net_dev);
if (net_dev->flags & IFF_PROMISC || if (net_dev->flags & IFF_PROMISC ||
netdev_uc_count(net_dev) >= EFX_EF10_FILTER_DEV_UC_MAX) { netdev_uc_count(net_dev) >= EFX_EF10_FILTER_DEV_UC_MAX) {
table->dev_uc_count = 0; *promisc = true;
uc_promisc = true;
} else {
table->dev_uc_count = 1 + netdev_uc_count(net_dev);
ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr);
i = 1;
netdev_for_each_uc_addr(uc, net_dev) {
ether_addr_copy(table->dev_uc_list[i].addr, uc->addr);
i++;
}
} }
table->dev_uc_count = 1 + netdev_uc_count(net_dev);
ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr);
i = 1;
netdev_for_each_uc_addr(uc, net_dev) {
ether_addr_copy(table->dev_uc_list[i].addr, uc->addr);
i++;
}
}
static void efx_ef10_filter_mc_addr_list(struct efx_nic *efx, bool *promisc)
{
struct efx_ef10_filter_table *table = efx->filter_state;
struct net_device *net_dev = efx->net_dev;
struct netdev_hw_addr *mc;
unsigned int i;
if (netdev_mc_count(net_dev) + 2 /* room for broadcast and promisc */ if (netdev_mc_count(net_dev) + 2 /* room for broadcast and promisc */
>= EFX_EF10_FILTER_DEV_MC_MAX) { >= EFX_EF10_FILTER_DEV_MC_MAX) {
table->dev_mc_count = 1; table->dev_mc_count = 1;
eth_broadcast_addr(table->dev_mc_list[0].addr); eth_broadcast_addr(table->dev_mc_list[0].addr);
mc_promisc = true; *promisc = true;
} else { } else {
table->dev_mc_count = 1 + netdev_mc_count(net_dev); table->dev_mc_count = 1 + netdev_mc_count(net_dev);
eth_broadcast_addr(table->dev_mc_list[0].addr); eth_broadcast_addr(table->dev_mc_list[0].addr);
...@@ -3809,84 +3809,87 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ...@@ -3809,84 +3809,87 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); ether_addr_copy(table->dev_mc_list[i].addr, mc->addr);
i++; i++;
} }
if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI))
mc_promisc = true; *promisc = true;
} }
netif_addr_unlock_bh(net_dev); }
/* Insert/renew unicast filters */ static void efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
for (i = 0; i < table->dev_uc_count; i++) { bool multicast, bool *promisc)
efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, {
EFX_FILTER_FLAG_RX_RSS, struct efx_ef10_filter_table *table = efx->filter_state;
0); struct efx_ef10_dev_addr *addr_list;
efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, struct efx_filter_spec spec;
table->dev_uc_list[i].addr); int *addr_count;
rc = efx_ef10_filter_insert(efx, &spec, true); unsigned int i;
if (rc < 0) { int rc;
/* Fall back to unicast-promisc */
while (i--) if (multicast) {
efx_ef10_filter_remove_safe( addr_list = table->dev_mc_list;
efx, EFX_FILTER_PRI_AUTO, addr_count = &table->dev_mc_count;
table->dev_uc_list[i].id); } else {
table->dev_uc_count = 0; addr_list = table->dev_uc_list;
uc_promisc = true; addr_count = &table->dev_uc_count;
break;
}
table->dev_uc_list[i].id = rc;
}
if (uc_promisc) {
efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
EFX_FILTER_FLAG_RX_RSS,
0);
efx_filter_set_uc_def(&spec);
rc = efx_ef10_filter_insert(efx, &spec, true);
if (rc < 0) {
WARN_ON(1);
} else {
table->dev_uc_list[table->dev_uc_count++].id = rc;
}
} }
/* Insert/renew multicast filters */ /* Insert/renew filters */
for (i = 0; i < table->dev_mc_count; i++) { for (i = 0; i < *addr_count; i++) {
efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
EFX_FILTER_FLAG_RX_RSS, EFX_FILTER_FLAG_RX_RSS,
0); 0);
efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
table->dev_mc_list[i].addr); addr_list[i].addr);
rc = efx_ef10_filter_insert(efx, &spec, true); rc = efx_ef10_filter_insert(efx, &spec, true);
if (rc < 0) { if (rc < 0) {
/* Fall back to multicast-promisc. /* Fall back to promiscuous, but leave the broadcast
* Leave the broadcast filter. * filter for multicast
*/ */
while (i > 1) while (i--) {
if (multicast && i == 1)
break;
efx_ef10_filter_remove_safe( efx_ef10_filter_remove_safe(
efx, EFX_FILTER_PRI_AUTO, efx, EFX_FILTER_PRI_AUTO,
table->dev_mc_list[--i].id); addr_list[i].id);
table->dev_mc_count = i; }
mc_promisc = true; *addr_count = i;
*promisc = true;
break; break;
} }
table->dev_mc_list[i].id = rc; addr_list[i].id = rc;
} }
if (mc_promisc) {
if (*promisc) {
efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
EFX_FILTER_FLAG_RX_RSS, EFX_FILTER_FLAG_RX_RSS,
0); 0);
efx_filter_set_mc_def(&spec);
if (multicast)
efx_filter_set_mc_def(&spec);
else
efx_filter_set_uc_def(&spec);
rc = efx_ef10_filter_insert(efx, &spec, true); rc = efx_ef10_filter_insert(efx, &spec, true);
if (rc < 0) { if (rc < 0)
WARN_ON(1); netif_warn(efx, drv, efx->net_dev,
} else { "%scast mismatch filter insert failed.",
table->dev_mc_list[table->dev_mc_count++].id = rc; multicast ? "Multi" : "Uni");
} else
addr_list[(*addr_count)++].id = rc;
} }
}
/* Remove filters that weren't renewed. Since nothing else changes the AUTO_OLD
* flag or removes these filters, we don't need to hold the filter_lock while
* scanning for these filters.
*/
static void efx_ef10_filter_remove_old(struct efx_nic *efx)
{
struct efx_ef10_filter_table *table = efx->filter_state;
bool remove_failed = false;
int i;
/* Remove filters that weren't renewed. Since nothing else
* changes the AUTO_OLD flag or removes these filters, we
* don't need to hold the filter_lock while scanning for
* these filters.
*/
for (i = 0; i < HUNT_FILTER_TBL_ROWS; i++) { for (i = 0; i < HUNT_FILTER_TBL_ROWS; i++) {
if (ACCESS_ONCE(table->entry[i].spec) & if (ACCESS_ONCE(table->entry[i].spec) &
EFX_EF10_FILTER_FLAG_AUTO_OLD) { EFX_EF10_FILTER_FLAG_AUTO_OLD) {
...@@ -3965,6 +3968,38 @@ static int efx_ef10_vport_set_mac_address(struct efx_nic *efx) ...@@ -3965,6 +3968,38 @@ static int efx_ef10_vport_set_mac_address(struct efx_nic *efx)
return rc ? rc : rc2; return rc ? rc : rc2;
} }
/* Caller must hold efx->filter_sem for read if race against
* efx_ef10_filter_table_remove() is possible
*/
static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
{
struct efx_ef10_filter_table *table = efx->filter_state;
struct net_device *net_dev = efx->net_dev;
bool uc_promisc = false, mc_promisc = false;
if (!efx_dev_registered(efx))
return;
if (!table)
return;
efx_ef10_filter_mark_old(efx);
/* Copy/convert the address lists; add the primary station
* address and broadcast address
*/
netif_addr_lock_bh(net_dev);
efx_ef10_filter_uc_addr_list(efx, &uc_promisc);
efx_ef10_filter_mc_addr_list(efx, &mc_promisc);
netif_addr_unlock_bh(net_dev);
/* Insert/renew filters */
efx_ef10_filter_insert_addr_list(efx, false, &uc_promisc);
efx_ef10_filter_insert_addr_list(efx, true, &mc_promisc);
efx_ef10_filter_remove_old(efx);
}
static int efx_ef10_set_mac_address(struct efx_nic *efx) static int efx_ef10_set_mac_address(struct efx_nic *efx)
{ {
MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_SET_MAC_IN_LEN); MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_SET_MAC_IN_LEN);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment