Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+126 −91
Original line number Diff line number Diff line
@@ -49,6 +49,11 @@ enum {
 */
#define HUNT_FILTER_TBL_ROWS 8192

struct efx_ef10_dev_addr {
	u8 addr[ETH_ALEN];
	u16 id;
};

struct efx_ef10_filter_table {
/* The RX match field masks supported by this fw & hw, in order of priority */
	enum efx_filter_match_flags rx_match_flags[
@@ -69,11 +74,8 @@ struct efx_ef10_filter_table {
/* Shadow of net_device address lists, guarded by mac_lock */
#define EFX_EF10_FILTER_DEV_UC_MAX	32
#define EFX_EF10_FILTER_DEV_MC_MAX	256
	struct {
		u8 addr[ETH_ALEN];
		u16 id;
	} dev_uc_list[EFX_EF10_FILTER_DEV_UC_MAX],
	  dev_mc_list[EFX_EF10_FILTER_DEV_MC_MAX];
	struct efx_ef10_dev_addr dev_uc_list[EFX_EF10_FILTER_DEV_UC_MAX];
	struct efx_ef10_dev_addr dev_mc_list[EFX_EF10_FILTER_DEV_MC_MAX];
	int dev_uc_count;		/* negative for PROMISC */
	int dev_mc_count;		/* negative for PROMISC/ALLMULTI */
};
@@ -3746,23 +3748,10 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx)
	kfree(table);
}

/* 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)
static void efx_ef10_filter_mark_old(struct efx_nic *efx)
{
	struct efx_ef10_filter_table *table = efx->filter_state;
	struct net_device *net_dev = efx->net_dev;
	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;
	unsigned int filter_idx, i;

	if (!table)
		return;
@@ -3778,16 +3767,19 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
		table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD;
	}
	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 ||
	    netdev_uc_count(net_dev) >= EFX_EF10_FILTER_DEV_UC_MAX) {
		table->dev_uc_count = 0;
		uc_promisc = true;
	} else {
		*promisc = true;
	}
	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;
@@ -3796,11 +3788,19 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
		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 */
	    >= EFX_EF10_FILTER_DEV_MC_MAX) {
		table->dev_mc_count = 1;
		eth_broadcast_addr(table->dev_mc_list[0].addr);
		mc_promisc = true;
		*promisc = true;
	} else {
		table->dev_mc_count = 1 + netdev_mc_count(net_dev);
		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)
			ether_addr_copy(table->dev_mc_list[i].addr, mc->addr);
			i++;
		}
		if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI))
			mc_promisc = true;
	}
	netif_addr_unlock_bh(net_dev);

	/* Insert/renew unicast filters */
	for (i = 0; i < table->dev_uc_count; i++) {
		efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
				   EFX_FILTER_FLAG_RX_RSS,
				   0);
		efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
					 table->dev_uc_list[i].addr);
		rc = efx_ef10_filter_insert(efx, &spec, true);
		if (rc < 0) {
			/* Fall back to unicast-promisc */
			while (i--)
				efx_ef10_filter_remove_safe(
					efx, EFX_FILTER_PRI_AUTO,
					table->dev_uc_list[i].id);
			table->dev_uc_count = 0;
			uc_promisc = true;
			break;
		if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI))
			*promisc = true;
	}
		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);

static void efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
					     bool multicast, bool *promisc)
{
	struct efx_ef10_filter_table *table = efx->filter_state;
	struct efx_ef10_dev_addr *addr_list;
	struct efx_filter_spec spec;
	int *addr_count;
	unsigned int i;
	int rc;

	if (multicast) {
		addr_list = table->dev_mc_list;
		addr_count = &table->dev_mc_count;
	} else {
			table->dev_uc_list[table->dev_uc_count++].id = rc;
		}
		addr_list = table->dev_uc_list;
		addr_count = &table->dev_uc_count;
	}

	/* Insert/renew multicast filters */
	for (i = 0; i < table->dev_mc_count; i++) {
	/* Insert/renew filters */
	for (i = 0; i < *addr_count; i++) {
		efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
				   EFX_FILTER_FLAG_RX_RSS,
				   0);
		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);
		if (rc < 0) {
			/* Fall back to multicast-promisc.
			 * Leave the broadcast filter.
			/* Fall back to promiscuous, but leave the broadcast
			 * filter for multicast
			 */
			while (i > 1)
			while (i--) {
				if (multicast && i == 1)
					break;

				efx_ef10_filter_remove_safe(
					efx, EFX_FILTER_PRI_AUTO,
					table->dev_mc_list[--i].id);
			table->dev_mc_count = i;
			mc_promisc = true;
					addr_list[i].id);
			}
			*addr_count = i;
			*promisc = true;
			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_FLAG_RX_RSS,
				   0);

		if (multicast)
			efx_filter_set_mc_def(&spec);
		else
			efx_filter_set_uc_def(&spec);

		rc = efx_ef10_filter_insert(efx, &spec, true);
		if (rc < 0) {
			WARN_ON(1);
		} else {
			table->dev_mc_list[table->dev_mc_count++].id = rc;
		if (rc < 0)
			netif_warn(efx, drv, efx->net_dev,
				   "%scast mismatch filter insert failed.",
				   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.
/* 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;

	for (i = 0; i < HUNT_FILTER_TBL_ROWS; i++) {
		if (ACCESS_ONCE(table->entry[i].spec) &
		    EFX_EF10_FILTER_FLAG_AUTO_OLD) {
@@ -3965,6 +3968,38 @@ static int efx_ef10_vport_set_mac_address(struct efx_nic *efx)
	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)
{
	MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_SET_MAC_IN_LEN);