[PATCH net-next 0/5] ionic: queue and filter mgmt updates

STALE1831d

8 messages, 1 author, 2021-08-26 · open the first message on its own page

[PATCH net-next 0/5] ionic: queue and filter mgmt updates

From: Shannon Nelson <hidden>
Date: 2021-08-26 01:25:08

After a pair of simple code cleanups, we change the mac filter
management to split the updates between the driver's filter
list and the device's filter list so that we can keep the calls
to dev_uc_sync() and dev_mc_sync() under the netif_addr_lock
in ndo_set_rx_mode, and then sync the driver's list to the
device later in the rx_mode work task.

Shannon Nelson (5):
  ionic: remove old work task types
  ionic: flatten calls to set-rx-mode
  ionic: sync the filters in the work task
  ionic: refactor ionic_lif_addr to remove a layer
  ionic: handle mac filter overflow

 .../net/ethernet/pensando/ionic/ionic_dev.c   |  13 ++
 .../net/ethernet/pensando/ionic/ionic_lif.c   | 218 ++++++++++--------
 .../net/ethernet/pensando/ionic/ionic_lif.h   |   8 +-
 .../ethernet/pensando/ionic/ionic_rx_filter.c | 143 +++++++++++-
 .../ethernet/pensando/ionic/ionic_rx_filter.h |  14 +-
 5 files changed, 285 insertions(+), 111 deletions(-)

-- 
2.17.1

[PATCH net-next 1/5] ionic: remove old work task types

From: Shannon Nelson <hidden>
Date: 2021-08-26 01:25:09

With the move of mac filter handling to outside of the
ndo_rx_mode context using the IONIC_DW_TYPE_RX_MODE,
we no longer are using IONIC_DW_TYPE_RX_ADDR_ADD and
IONIC_DW_TYPE_RX_ADDR_DEL and they can be removed.

Signed-off-by: Shannon Nelson <redacted>
---
 drivers/net/ethernet/pensando/ionic/ionic_lif.c | 6 ------
 drivers/net/ethernet/pensando/ionic/ionic_lif.h | 2 --
 2 files changed, 8 deletions(-)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index f52c47a71f4b..1940052acc77 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -92,12 +92,6 @@ static void ionic_lif_deferred_work(struct work_struct *work)
 		case IONIC_DW_TYPE_RX_MODE:
 			ionic_lif_rx_mode(lif);
 			break;
-		case IONIC_DW_TYPE_RX_ADDR_ADD:
-			ionic_lif_addr_add(lif, w->addr);
-			break;
-		case IONIC_DW_TYPE_RX_ADDR_DEL:
-			ionic_lif_addr_del(lif, w->addr);
-			break;
 		case IONIC_DW_TYPE_LINK_STATUS:
 			ionic_link_status_check(lif);
 			break;
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
index 69ab59fedb6c..31ee1a025fd8 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
@@ -98,8 +98,6 @@ struct ionic_qcq {
 
 enum ionic_deferred_work_type {
 	IONIC_DW_TYPE_RX_MODE,
-	IONIC_DW_TYPE_RX_ADDR_ADD,
-	IONIC_DW_TYPE_RX_ADDR_DEL,
 	IONIC_DW_TYPE_LINK_STATUS,
 	IONIC_DW_TYPE_LIF_RESET,
 };
-- 
2.17.1

[PATCH net-next 2/5] ionic: flatten calls to set-rx-mode

From: Shannon Nelson <hidden>
Date: 2021-08-26 01:25:10

Since only two functions call through ionic_set_rx_mode(), one
that can sleep and one that can't, we can split the function
and put the bits of code into the callers.  This removes an
unnecessary calling layer.

Signed-off-by: Shannon Nelson <redacted>
---
 .../net/ethernet/pensando/ionic/ionic_lif.c   | 27 +++++++------------
 1 file changed, 9 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index 1940052acc77..60bc1251d995 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -1444,28 +1444,19 @@ static void ionic_lif_rx_mode(struct ionic_lif *lif)
 	mutex_unlock(&lif->config_lock);
 }
 
-static void ionic_set_rx_mode(struct net_device *netdev, bool can_sleep)
+static void ionic_ndo_set_rx_mode(struct net_device *netdev)
 {
 	struct ionic_lif *lif = netdev_priv(netdev);
 	struct ionic_deferred_work *work;
 
-	if (!can_sleep) {
-		work = kzalloc(sizeof(*work), GFP_ATOMIC);
-		if (!work) {
-			netdev_err(lif->netdev, "rxmode change dropped\n");
-			return;
-		}
-		work->type = IONIC_DW_TYPE_RX_MODE;
-		netdev_dbg(lif->netdev, "deferred: rx_mode\n");
-		ionic_lif_deferred_enqueue(&lif->deferred, work);
-	} else {
-		ionic_lif_rx_mode(lif);
+	work = kzalloc(sizeof(*work), GFP_ATOMIC);
+	if (!work) {
+		netdev_err(lif->netdev, "rxmode change dropped\n");
+		return;
 	}
-}
-
-static void ionic_ndo_set_rx_mode(struct net_device *netdev)
-{
-	ionic_set_rx_mode(netdev, CAN_NOT_SLEEP);
+	work->type = IONIC_DW_TYPE_RX_MODE;
+	netdev_dbg(lif->netdev, "deferred: rx_mode\n");
+	ionic_lif_deferred_enqueue(&lif->deferred, work);
 }
 
 static __le64 ionic_netdev_features_to_nic(netdev_features_t features)
@@ -2101,7 +2092,7 @@ static int ionic_txrx_init(struct ionic_lif *lif)
 	if (lif->netdev->features & NETIF_F_RXHASH)
 		ionic_lif_rss_init(lif);
 
-	ionic_set_rx_mode(lif->netdev, CAN_SLEEP);
+	ionic_lif_rx_mode(lif);
 
 	return 0;
 
-- 
2.17.1

[PATCH net-next 3/5] ionic: sync the filters in the work task

From: Shannon Nelson <hidden>
Date: 2021-08-26 01:25:13

In order to separate the atomic needs of __dev_uc_sync()
and __dev_mc_sync() from the safe rx_mode handling, we need
to have the ndo handler manipulate the driver's filter list,
and later have the driver sync the filters to the firmware,
outside of the atomic context.

Here we put __dev_mc_sync() and __dev_uc_sync() back into the
ndo callback to give them their netif_addr_lock context and
have them update the driver's filter list, flagging changes
that should be made to the device filter list.  Later, in the
rx_mode handler, we read those hints and sync up the device's
list as needed.

It is possible for multiple add/delete requests to come from
the stack before the rx_mode task processes the list, but the
handling of the sync status flag should keep everything sorted
correctly.  For example, if a delete of an existing filter is
followed by another add before the rx_mode task is run, as can
happen when going in and out of a bond, the add will cancel
the delete and no actual changes will be sent to the device.

We also add a check in the watchdog to see if there are any
stray unsync'd filters, possibly left over from a filter
overflow and waiting to get sync'd after some other filter
gets removed to make room.

Signed-off-by: Shannon Nelson <redacted>
---
 .../net/ethernet/pensando/ionic/ionic_dev.c   |  13 ++
 .../net/ethernet/pensando/ionic/ionic_lif.c   | 108 +++++++++----
 .../net/ethernet/pensando/ionic/ionic_lif.h   |   6 +
 .../ethernet/pensando/ionic/ionic_rx_filter.c | 143 ++++++++++++++++--
 .../ethernet/pensando/ionic/ionic_rx_filter.h |  14 +-
 5 files changed, 247 insertions(+), 37 deletions(-)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
index 9aac647290f7..0d6858ab511c 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
@@ -15,6 +15,7 @@ static void ionic_watchdog_cb(struct timer_list *t)
 {
 	struct ionic *ionic = from_timer(ionic, t, watchdog_timer);
 	struct ionic_lif *lif = ionic->lif;
+	struct ionic_deferred_work *work;
 	int hb;
 
 	mod_timer(&ionic->watchdog_timer,
@@ -31,6 +32,18 @@ static void ionic_watchdog_cb(struct timer_list *t)
 	if (hb >= 0 &&
 	    !test_bit(IONIC_LIF_F_FW_RESET, lif->state))
 		ionic_link_status_check_request(lif, CAN_NOT_SLEEP);
+
+	if (test_bit(IONIC_LIF_F_FILTER_SYNC_NEEDED, lif->state)) {
+		work = kzalloc(sizeof(*work), GFP_ATOMIC);
+		if (!work) {
+			netdev_err(lif->netdev, "rxmode change dropped\n");
+			return;
+		}
+
+		work->type = IONIC_DW_TYPE_RX_MODE;
+		netdev_dbg(lif->netdev, "deferred: rx_mode\n");
+		ionic_lif_deferred_enqueue(&lif->deferred, work);
+	}
 }
 
 void ionic_init_devinfo(struct ionic *ionic)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index 60bc1251d995..7812991f4736 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -30,9 +30,6 @@ static const u8 ionic_qtype_versions[IONIC_QTYPE_MAX] = {
 				      */
 };
 
-static void ionic_lif_rx_mode(struct ionic_lif *lif);
-static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr);
-static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr);
 static void ionic_link_status_check(struct ionic_lif *lif);
 static void ionic_lif_handle_fw_down(struct ionic_lif *lif);
 static void ionic_lif_handle_fw_up(struct ionic_lif *lif);
@@ -1072,7 +1069,11 @@ static int ionic_lif_add_hwstamp_rxfilt(struct ionic_lif *lif, u64 pkt_class)
 	if (err && err != -EEXIST)
 		return err;
 
-	return ionic_rx_filter_save(lif, 0, qid, 0, &ctx);
+	spin_lock_bh(&lif->rx_filters.lock);
+	err = ionic_rx_filter_save(lif, 0, qid, 0, &ctx, IONIC_FILTER_STATE_SYNCED);
+	spin_unlock_bh(&lif->rx_filters.lock);
+
+	return err;
 }
 
 int ionic_lif_set_hwstamp_rxfilt(struct ionic_lif *lif, u64 pkt_class)
@@ -1245,7 +1246,7 @@ void ionic_get_stats64(struct net_device *netdev,
 	ns->tx_errors = ns->tx_aborted_errors;
 }
 
-static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
+int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
 {
 	struct ionic_admin_ctx ctx = {
 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
@@ -1256,26 +1257,64 @@ static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
 		},
 	};
 	struct ionic_rx_filter *f;
-	int err;
+	int err = 0;
 
-	/* don't bother if we already have it */
 	spin_lock_bh(&lif->rx_filters.lock);
 	f = ionic_rx_filter_by_addr(lif, addr);
+	if (f) {
+		/* don't bother if we already have it and it is sync'd */
+		if (f->state == IONIC_FILTER_STATE_SYNCED) {
+			spin_unlock_bh(&lif->rx_filters.lock);
+			return 0;
+		}
+
+		/* mark preemptively as sync'd to block any parallel attempts */
+		f->state = IONIC_FILTER_STATE_SYNCED;
+	} else {
+		/* save as SYNCED to catch any DEL requests while processing */
+		memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN);
+		err = ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx,
+					   IONIC_FILTER_STATE_SYNCED);
+	}
 	spin_unlock_bh(&lif->rx_filters.lock);
-	if (f)
-		return 0;
+	if (err)
+		return err;
 
 	netdev_dbg(lif->netdev, "rx_filter add ADDR %pM\n", addr);
 
-	memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN);
 	err = ionic_adminq_post_wait(lif, &ctx);
-	if (err && err != -EEXIST)
+
+	spin_lock_bh(&lif->rx_filters.lock);
+	if (err && err != -EEXIST) {
+		/* set the state back to NEW so we can try again later */
+		f = ionic_rx_filter_by_addr(lif, addr);
+		if (f && f->state == IONIC_FILTER_STATE_SYNCED)
+			f->state = IONIC_FILTER_STATE_NEW;
+
+		spin_unlock_bh(&lif->rx_filters.lock);
 		return err;
+	}
+
+	f = ionic_rx_filter_by_addr(lif, addr);
+	if (f && f->state == IONIC_FILTER_STATE_OLD) {
+		/* Someone requested a delete while we were adding
+		 * so update the filter info with the results from the add
+		 * and the data will be there for the delete on the next
+		 * sync cycle.
+		 */
+		err = ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx,
+					   IONIC_FILTER_STATE_OLD);
+	} else {
+		err = ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx,
+					   IONIC_FILTER_STATE_SYNCED);
+	}
 
-	return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx);
+	spin_unlock_bh(&lif->rx_filters.lock);
+
+	return err;
 }
 
-static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
+int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
 {
 	struct ionic_admin_ctx ctx = {
 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
@@ -1285,6 +1324,7 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
 		},
 	};
 	struct ionic_rx_filter *f;
+	int state;
 	int err;
 
 	spin_lock_bh(&lif->rx_filters.lock);
@@ -1297,13 +1337,16 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
 	netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n",
 		   addr, f->filter_id);
 
+	state = f->state;
 	ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
 	ionic_rx_filter_free(lif, f);
 	spin_unlock_bh(&lif->rx_filters.lock);
 
-	err = ionic_adminq_post_wait(lif, &ctx);
-	if (err && err != -EEXIST)
-		return err;
+	if (state != IONIC_FILTER_STATE_NEW) {
+		err = ionic_adminq_post_wait(lif, &ctx);
+		if (err && err != -EEXIST)
+			return err;
+	}
 
 	return 0;
 }
@@ -1347,15 +1390,15 @@ static int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add)
 
 static int ionic_addr_add(struct net_device *netdev, const u8 *addr)
 {
-	return ionic_lif_addr(netdev_priv(netdev), addr, ADD_ADDR);
+	return ionic_lif_list_addr(netdev_priv(netdev), addr, ADD_ADDR);
 }
 
 static int ionic_addr_del(struct net_device *netdev, const u8 *addr)
 {
-	return ionic_lif_addr(netdev_priv(netdev), addr, DEL_ADDR);
+	return ionic_lif_list_addr(netdev_priv(netdev), addr, DEL_ADDR);
 }
 
-static void ionic_lif_rx_mode(struct ionic_lif *lif)
+void ionic_lif_rx_mode(struct ionic_lif *lif)
 {
 	struct net_device *netdev = lif->netdev;
 	unsigned int nfilters;
@@ -1376,14 +1419,15 @@ static void ionic_lif_rx_mode(struct ionic_lif *lif)
 	rx_mode |= (nd_flags & IFF_PROMISC) ? IONIC_RX_MODE_F_PROMISC : 0;
 	rx_mode |= (nd_flags & IFF_ALLMULTI) ? IONIC_RX_MODE_F_ALLMULTI : 0;
 
-	/* sync unicast addresses
-	 * next check to see if we're in an overflow state
+	/* sync the mac filters */
+	ionic_rx_filter_sync(lif);
+
+	/* check for overflow state
 	 *    if so, we track that we overflowed and enable NIC PROMISC
 	 *    else if the overflow is set and not needed
 	 *       we remove our overflow flag and check the netdev flags
 	 *       to see if we can disable NIC PROMISC
 	 */
-	__dev_uc_sync(netdev, ionic_addr_add, ionic_addr_del);
 	nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
 	if (netdev_uc_count(netdev) + 1 > nfilters) {
 		rx_mode |= IONIC_RX_MODE_F_PROMISC;
@@ -1394,8 +1438,6 @@ static void ionic_lif_rx_mode(struct ionic_lif *lif)
 			rx_mode &= ~IONIC_RX_MODE_F_PROMISC;
 	}
 
-	/* same for multicast */
-	__dev_mc_sync(netdev, ionic_addr_add, ionic_addr_del);
 	nfilters = le32_to_cpu(lif->identity->eth.max_mcast_filters);
 	if (netdev_mc_count(netdev) > nfilters) {
 		rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
@@ -1449,6 +1491,13 @@ static void ionic_ndo_set_rx_mode(struct net_device *netdev)
 	struct ionic_lif *lif = netdev_priv(netdev);
 	struct ionic_deferred_work *work;
 
+	/* Sync the kernel filter list with the driver filter list */
+	__dev_uc_sync(netdev, ionic_addr_add, ionic_addr_del);
+	__dev_mc_sync(netdev, ionic_addr_add, ionic_addr_del);
+
+	/* Shove off the rest of the rxmode work to the work task
+	 * which will include syncing the filters to the firmware.
+	 */
 	work = kzalloc(sizeof(*work), GFP_ATOMIC);
 	if (!work) {
 		netdev_err(lif->netdev, "rxmode change dropped\n");
@@ -1677,13 +1726,13 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa)
 	if (!is_zero_ether_addr(netdev->dev_addr)) {
 		netdev_info(netdev, "deleting mac addr %pM\n",
 			    netdev->dev_addr);
-		ionic_addr_del(netdev, netdev->dev_addr);
+		ionic_lif_addr_del(netdev_priv(netdev), netdev->dev_addr);
 	}
 
 	eth_commit_mac_addr_change(netdev, addr);
 	netdev_info(netdev, "updating mac addr %pM\n", mac);
 
-	return ionic_addr_add(netdev, mac);
+	return ionic_lif_addr_add(netdev_priv(netdev), mac);
 }
 
 static void ionic_stop_queues_reconfig(struct ionic_lif *lif)
@@ -1789,7 +1838,12 @@ static int ionic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto,
 	if (err)
 		return err;
 
-	return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx);
+	spin_lock_bh(&lif->rx_filters.lock);
+	err = ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx,
+				   IONIC_FILTER_STATE_SYNCED);
+	spin_unlock_bh(&lif->rx_filters.lock);
+
+	return err;
 }
 
 static int ionic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto,
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
index 31ee1a025fd8..cad193d358e8 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
@@ -145,6 +145,7 @@ enum ionic_lif_state_flags {
 	IONIC_LIF_F_SW_DEBUG_STATS,
 	IONIC_LIF_F_UP,
 	IONIC_LIF_F_LINK_CHECK_REQUESTED,
+	IONIC_LIF_F_FILTER_SYNC_NEEDED,
 	IONIC_LIF_F_FW_RESET,
 	IONIC_LIF_F_SPLIT_INTR,
 	IONIC_LIF_F_BROKEN,
@@ -293,6 +294,10 @@ int ionic_lif_alloc(struct ionic *ionic);
 int ionic_lif_init(struct ionic_lif *lif);
 void ionic_lif_free(struct ionic_lif *lif);
 void ionic_lif_deinit(struct ionic_lif *lif);
+
+int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr);
+int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr);
+
 int ionic_lif_register(struct ionic_lif *lif);
 void ionic_lif_unregister(struct ionic_lif *lif);
 int ionic_lif_identify(struct ionic *ionic, u8 lif_type,
@@ -340,6 +345,7 @@ int ionic_lif_set_hwstamp_rxfilt(struct ionic_lif *lif, u64 pkt_class);
 
 int ionic_lif_rss_config(struct ionic_lif *lif, u16 types,
 			 const u8 *key, const u32 *indir);
+void ionic_lif_rx_mode(struct ionic_lif *lif);
 int ionic_reconfigure_queues(struct ionic_lif *lif,
 			     struct ionic_queue_params *qparam);
 
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c
index d71316d9ded2..7e3a5634c161 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c
@@ -4,6 +4,7 @@
 #include <linux/netdevice.h>
 #include <linux/dynamic_debug.h>
 #include <linux/etherdevice.h>
+#include <linux/list.h>
 
 #include "ionic.h"
 #include "ionic_lif.h"
@@ -120,11 +121,12 @@ void ionic_rx_filters_deinit(struct ionic_lif *lif)
 }
 
 int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
-			 u32 hash, struct ionic_admin_ctx *ctx)
+			 u32 hash, struct ionic_admin_ctx *ctx,
+			 enum ionic_filter_state state)
 {
 	struct device *dev = lif->ionic->dev;
 	struct ionic_rx_filter_add_cmd *ac;
-	struct ionic_rx_filter *f;
+	struct ionic_rx_filter *f = NULL;
 	struct hlist_head *head;
 	unsigned int key;
 
@@ -133,9 +135,11 @@ int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
 	switch (le16_to_cpu(ac->match)) {
 	case IONIC_RX_FILTER_MATCH_VLAN:
 		key = le16_to_cpu(ac->vlan.vlan);
+		f = ionic_rx_filter_by_vlan(lif, le16_to_cpu(ac->vlan.vlan));
 		break;
 	case IONIC_RX_FILTER_MATCH_MAC:
 		key = *(u32 *)ac->mac.addr;
+		f = ionic_rx_filter_by_addr(lif, ac->mac.addr);
 		break;
 	case IONIC_RX_FILTER_MATCH_MAC_VLAN:
 		key = le16_to_cpu(ac->mac_vlan.vlan);
@@ -147,12 +151,19 @@ int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
 		return -EINVAL;
 	}
 
-	f = devm_kzalloc(dev, sizeof(*f), GFP_KERNEL);
-	if (!f)
-		return -ENOMEM;
+	if (f) {
+		/* remove from current linking so we can refresh it */
+		hlist_del(&f->by_id);
+		hlist_del(&f->by_hash);
+	} else {
+		f = devm_kzalloc(dev, sizeof(*f), GFP_ATOMIC);
+		if (!f)
+			return -ENOMEM;
+	}
 
 	f->flow_id = flow_id;
 	f->filter_id = le32_to_cpu(ctx->comp.rx_filter_add.filter_id);
+	f->state = state;
 	f->rxq_index = rxq_index;
 	memcpy(&f->cmd, ac, sizeof(f->cmd));
 	netdev_dbg(lif->netdev, "rx_filter add filter_id %d\n", f->filter_id);
@@ -160,8 +171,6 @@ int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
 	INIT_HLIST_NODE(&f->by_hash);
 	INIT_HLIST_NODE(&f->by_id);
 
-	spin_lock_bh(&lif->rx_filters.lock);
-
 	key = hash_32(key, IONIC_RX_FILTER_HASH_BITS);
 	head = &lif->rx_filters.by_hash[key];
 	hlist_add_head(&f->by_hash, head);
@@ -170,8 +179,6 @@ int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
 	head = &lif->rx_filters.by_id[key];
 	hlist_add_head(&f->by_id, head);
 
-	spin_unlock_bh(&lif->rx_filters.lock);
-
 	return 0;
 }
 
@@ -231,3 +238,121 @@ struct ionic_rx_filter *ionic_rx_filter_rxsteer(struct ionic_lif *lif)
 
 	return NULL;
 }
+
+int ionic_lif_list_addr(struct ionic_lif *lif, const u8 *addr, bool mode)
+{
+	struct ionic_rx_filter *f;
+	int err;
+
+	spin_lock_bh(&lif->rx_filters.lock);
+
+	f = ionic_rx_filter_by_addr(lif, addr);
+	if (mode == ADD_ADDR && !f) {
+		struct ionic_admin_ctx ctx = {
+			.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
+			.cmd.rx_filter_add = {
+				.opcode = IONIC_CMD_RX_FILTER_ADD,
+				.lif_index = cpu_to_le16(lif->index),
+				.match = cpu_to_le16(IONIC_RX_FILTER_MATCH_MAC),
+			},
+		};
+
+		memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN);
+		err = ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx,
+					   IONIC_FILTER_STATE_NEW);
+		if (err) {
+			spin_unlock_bh(&lif->rx_filters.lock);
+			return err;
+		}
+
+	} else if (mode == ADD_ADDR && f) {
+		if (f->state == IONIC_FILTER_STATE_OLD)
+			f->state = IONIC_FILTER_STATE_SYNCED;
+
+	} else if (mode == DEL_ADDR && f) {
+		if (f->state == IONIC_FILTER_STATE_NEW)
+			ionic_rx_filter_free(lif, f);
+		else if (f->state == IONIC_FILTER_STATE_SYNCED)
+			f->state = IONIC_FILTER_STATE_OLD;
+	} else if (mode == DEL_ADDR && !f) {
+		spin_unlock_bh(&lif->rx_filters.lock);
+		return -ENOENT;
+	}
+
+	spin_unlock_bh(&lif->rx_filters.lock);
+
+	set_bit(IONIC_LIF_F_FILTER_SYNC_NEEDED, lif->state);
+
+	return 0;
+}
+
+struct sync_item {
+	struct list_head list;
+	struct ionic_rx_filter f;
+};
+
+void ionic_rx_filter_sync(struct ionic_lif *lif)
+{
+	struct device *dev = lif->ionic->dev;
+	struct list_head sync_add_list;
+	struct list_head sync_del_list;
+	struct sync_item *sync_item;
+	struct ionic_rx_filter *f;
+	struct hlist_head *head;
+	struct hlist_node *tmp;
+	struct sync_item *spos;
+	unsigned int i;
+
+	INIT_LIST_HEAD(&sync_add_list);
+	INIT_LIST_HEAD(&sync_del_list);
+
+	clear_bit(IONIC_LIF_F_FILTER_SYNC_NEEDED, lif->state);
+
+	/* Copy the filters to be added and deleted
+	 * into a separate local list that needs no locking.
+	 */
+	spin_lock_bh(&lif->rx_filters.lock);
+	for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
+		head = &lif->rx_filters.by_id[i];
+		hlist_for_each_entry_safe(f, tmp, head, by_id) {
+			if (f->state == IONIC_FILTER_STATE_NEW ||
+			    f->state == IONIC_FILTER_STATE_OLD) {
+				sync_item = devm_kzalloc(dev, sizeof(*sync_item),
+							 GFP_KERNEL);
+				if (!sync_item)
+					goto loop_out;
+
+				sync_item->f = *f;
+
+				if (f->state == IONIC_FILTER_STATE_NEW)
+					list_add(&sync_item->list, &sync_add_list);
+				else
+					list_add(&sync_item->list, &sync_del_list);
+			}
+		}
+	}
+loop_out:
+	spin_unlock_bh(&lif->rx_filters.lock);
+
+	/* If the add or delete fails, it won't get marked as sync'd
+	 * and will be tried again in the next sync action.
+	 * Do the deletes first in case we're in an overflow state and
+	 * they can clear room for some new filters
+	 */
+	list_for_each_entry_safe(sync_item, spos, &sync_del_list, list) {
+		(void)ionic_lif_addr_del(lif, sync_item->f.cmd.mac.addr);
+
+		list_del(&sync_item->list);
+		devm_kfree(dev, sync_item);
+	}
+
+	list_for_each_entry_safe(sync_item, spos, &sync_add_list, list) {
+		(void)ionic_lif_addr_add(lif, sync_item->f.cmd.mac.addr);
+
+		if (sync_item->f.state != IONIC_FILTER_STATE_SYNCED)
+			set_bit(IONIC_LIF_F_FILTER_SYNC_NEEDED, lif->state);
+
+		list_del(&sync_item->list);
+		devm_kfree(dev, sync_item);
+	}
+}
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h
index 1ead48be3c83..a66e35f0833b 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h
@@ -5,10 +5,18 @@
 #define _IONIC_RX_FILTER_H_
 
 #define IONIC_RXQ_INDEX_ANY		(0xFFFF)
+
+enum ionic_filter_state {
+	IONIC_FILTER_STATE_SYNCED,
+	IONIC_FILTER_STATE_NEW,
+	IONIC_FILTER_STATE_OLD,
+};
+
 struct ionic_rx_filter {
 	u32 flow_id;
 	u32 filter_id;
 	u16 rxq_index;
+	enum ionic_filter_state state;
 	struct ionic_rx_filter_add_cmd cmd;
 	struct hlist_node by_hash;
 	struct hlist_node by_id;
@@ -28,9 +36,13 @@ void ionic_rx_filter_replay(struct ionic_lif *lif);
 int ionic_rx_filters_init(struct ionic_lif *lif);
 void ionic_rx_filters_deinit(struct ionic_lif *lif);
 int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
-			 u32 hash, struct ionic_admin_ctx *ctx);
+			 u32 hash, struct ionic_admin_ctx *ctx,
+			 enum ionic_filter_state state);
 struct ionic_rx_filter *ionic_rx_filter_by_vlan(struct ionic_lif *lif, u16 vid);
 struct ionic_rx_filter *ionic_rx_filter_by_addr(struct ionic_lif *lif, const u8 *addr);
 struct ionic_rx_filter *ionic_rx_filter_rxsteer(struct ionic_lif *lif);
+void ionic_rx_filter_sync(struct ionic_lif *lif);
+int ionic_lif_list_addr(struct ionic_lif *lif, const u8 *addr, bool mode);
+int ionic_rx_filters_need_sync(struct ionic_lif *lif);
 
 #endif /* _IONIC_RX_FILTER_H_ */
-- 
2.17.1

[PATCH net-next 4/5] ionic: refactor ionic_lif_addr to remove a layer

From: Shannon Nelson <hidden>
Date: 2021-08-26 01:25:14

The filter counting in ionic_lif_addr() really isn't useful,
and potentially misleading, especially when we're checking in
ionic_lif_rx_mode() to see if we need to go into PROMISC mode.
We can safely refactor this and remove a calling layer.

Signed-off-by: Shannon Nelson <redacted>
---
 .../net/ethernet/pensando/ionic/ionic_lif.c   | 41 +------------------
 1 file changed, 2 insertions(+), 39 deletions(-)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index 7812991f4736..b248c2e97582 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -1351,43 +1351,6 @@ int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
 	return 0;
 }
 
-static int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add)
-{
-	unsigned int nmfilters;
-	unsigned int nufilters;
-
-	if (add) {
-		/* Do we have space for this filter?  We test the counters
-		 * here before checking the need for deferral so that we
-		 * can return an overflow error to the stack.
-		 */
-		nmfilters = le32_to_cpu(lif->identity->eth.max_mcast_filters);
-		nufilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
-
-		if ((is_multicast_ether_addr(addr) && lif->nmcast < nmfilters))
-			lif->nmcast++;
-		else if (!is_multicast_ether_addr(addr) &&
-			 lif->nucast < nufilters)
-			lif->nucast++;
-		else
-			return -ENOSPC;
-	} else {
-		if (is_multicast_ether_addr(addr) && lif->nmcast)
-			lif->nmcast--;
-		else if (!is_multicast_ether_addr(addr) && lif->nucast)
-			lif->nucast--;
-	}
-
-	netdev_dbg(lif->netdev, "rx_filter %s %pM\n",
-		   add ? "add" : "del", addr);
-	if (add)
-		return ionic_lif_addr_add(lif, addr);
-	else
-		return ionic_lif_addr_del(lif, addr);
-
-	return 0;
-}
-
 static int ionic_addr_add(struct net_device *netdev, const u8 *addr)
 {
 	return ionic_lif_list_addr(netdev_priv(netdev), addr, ADD_ADDR);
@@ -3234,7 +3197,7 @@ static int ionic_station_set(struct ionic_lif *lif)
 		 */
 		if (!ether_addr_equal(ctx.comp.lif_getattr.mac,
 				      netdev->dev_addr))
-			ionic_lif_addr(lif, netdev->dev_addr, ADD_ADDR);
+			ionic_lif_addr_add(lif, netdev->dev_addr);
 	} else {
 		/* Update the netdev mac with the device's mac */
 		memcpy(addr.sa_data, ctx.comp.lif_getattr.mac, netdev->addr_len);
@@ -3251,7 +3214,7 @@ static int ionic_station_set(struct ionic_lif *lif)
 
 	netdev_dbg(lif->netdev, "adding station MAC addr %pM\n",
 		   netdev->dev_addr);
-	ionic_lif_addr(lif, netdev->dev_addr, ADD_ADDR);
+	ionic_lif_addr_add(lif, netdev->dev_addr);
 
 	return 0;
 }
-- 
2.17.1

[PATCH net-next 5/5] ionic: handle mac filter overflow

From: Shannon Nelson <hidden>
Date: 2021-08-26 01:25:16

Make sure we go into PROMISC mode when we have too many
filters by specifically counting the filters that successfully
get saved to the firmware.

The device advertises max_ucast_filters and max_mcast_filters,
but really only has max_ucast_filters slots available for
uc and mc filters combined.

Signed-off-by: Shannon Nelson <redacted>
---
 .../net/ethernet/pensando/ionic/ionic_lif.c   | 40 ++++++++++++++-----
 1 file changed, 29 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index b248c2e97582..e494d6b909c7 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -1256,6 +1256,8 @@ int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
 			.match = cpu_to_le16(IONIC_RX_FILTER_MATCH_MAC),
 		},
 	};
+	int nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
+	bool mc = is_multicast_ether_addr(addr);
 	struct ionic_rx_filter *f;
 	int err = 0;
 
@@ -1282,7 +1284,13 @@ int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
 
 	netdev_dbg(lif->netdev, "rx_filter add ADDR %pM\n", addr);
 
-	err = ionic_adminq_post_wait(lif, &ctx);
+	/* Don't bother with the write to FW if we know there's no room,
+	 * we can try again on the next sync attempt.
+	 */
+	if ((lif->nucast + lif->nmcast) >= nfilters)
+		err = -ENOSPC;
+	else
+		err = ionic_adminq_post_wait(lif, &ctx);
 
 	spin_lock_bh(&lif->rx_filters.lock);
 	if (err && err != -EEXIST) {
@@ -1292,9 +1300,18 @@ int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
 			f->state = IONIC_FILTER_STATE_NEW;
 
 		spin_unlock_bh(&lif->rx_filters.lock);
-		return err;
+
+		if (err == -ENOSPC)
+			return 0;
+		else
+			return err;
 	}
 
+	if (mc)
+		lif->nmcast++;
+	else
+		lif->nucast++;
+
 	f = ionic_rx_filter_by_addr(lif, addr);
 	if (f && f->state == IONIC_FILTER_STATE_OLD) {
 		/* Someone requested a delete while we were adding
@@ -1340,6 +1357,12 @@ int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
 	state = f->state;
 	ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
 	ionic_rx_filter_free(lif, f);
+
+	if (is_multicast_ether_addr(addr) && lif->nmcast)
+		lif->nmcast--;
+	else if (!is_multicast_ether_addr(addr) && lif->nucast)
+		lif->nucast--;
+
 	spin_unlock_bh(&lif->rx_filters.lock);
 
 	if (state != IONIC_FILTER_STATE_NEW) {
@@ -1392,21 +1415,16 @@ void ionic_lif_rx_mode(struct ionic_lif *lif)
 	 *       to see if we can disable NIC PROMISC
 	 */
 	nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
-	if (netdev_uc_count(netdev) + 1 > nfilters) {
+	if ((lif->nucast + lif->nmcast) >= nfilters) {
 		rx_mode |= IONIC_RX_MODE_F_PROMISC;
+		rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
 		lif->uc_overflow = true;
+		lif->mc_overflow = true;
 	} else if (lif->uc_overflow) {
 		lif->uc_overflow = false;
+		lif->mc_overflow = false;
 		if (!(nd_flags & IFF_PROMISC))
 			rx_mode &= ~IONIC_RX_MODE_F_PROMISC;
-	}
-
-	nfilters = le32_to_cpu(lif->identity->eth.max_mcast_filters);
-	if (netdev_mc_count(netdev) > nfilters) {
-		rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
-		lif->mc_overflow = true;
-	} else if (lif->mc_overflow) {
-		lif->mc_overflow = false;
 		if (!(nd_flags & IFF_ALLMULTI))
 			rx_mode &= ~IONIC_RX_MODE_F_ALLMULTI;
 	}
-- 
2.17.1

[PATCH 6/6] filter-debug

From: Shannon Nelson <hidden>
Date: 2021-08-26 01:25:17

Signed-off-by: Shannon Nelson <redacted>
---
 .../ethernet/pensando/ionic/ionic_ethtool.c   |  2 ++
 .../net/ethernet/pensando/ionic/ionic_lif.c   |  6 +++++
 .../ethernet/pensando/ionic/ionic_rx_filter.c | 27 +++++++++++++++++++
 .../ethernet/pensando/ionic/ionic_rx_filter.h |  1 +
 4 files changed, 36 insertions(+)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
index adc9fdb03e86..61b4b1772eb2 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
@@ -687,6 +687,8 @@ static u32 ionic_get_priv_flags(struct net_device *netdev)
 	struct ionic_lif *lif = netdev_priv(netdev);
 	u32 priv_flags = 0;
 
+	ionic_rx_filter_dump(lif);
+
 	if (test_bit(IONIC_LIF_F_SW_DEBUG_STATS, lif->state))
 		priv_flags |= IONIC_PRIV_F_SW_DBG_STATS;
 
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index 77394135d1cd..202155c866fe 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -1261,6 +1261,7 @@ int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
 	struct ionic_rx_filter *f;
 	int err = 0;
 
+dev_info(lif->ionic->dev, "%s: addr %pM mc %d\n", __func__, addr, mc);
 	spin_lock_bh(&lif->rx_filters.lock);
 	f = ionic_rx_filter_by_addr(lif, addr);
 	if (f) {
@@ -1345,6 +1346,7 @@ int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
 	int state;
 	int err;
 
+dev_info(lif->ionic->dev, "%s: addr %pM\n", __func__, addr);
 	spin_lock_bh(&lif->rx_filters.lock);
 	f = ionic_rx_filter_by_addr(lif, addr);
 	if (!f) {
@@ -1419,9 +1421,11 @@ void ionic_lif_rx_mode(struct ionic_lif *lif)
 	if ((lif->nucast + lif->nmcast) >= nfilters) {
 		rx_mode |= IONIC_RX_MODE_F_PROMISC;
 		rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
+if (!lif->uc_overflow) dev_info(lif->ionic->dev, "%s: uc_overflow toggled to true\n", __func__);
 		lif->uc_overflow = true;
 		lif->mc_overflow = true;
 	} else if (lif->uc_overflow) {
+if (lif->uc_overflow) dev_info(lif->ionic->dev, "%s: uc_overflow toggled to false\n", __func__);
 		lif->uc_overflow = false;
 		lif->mc_overflow = false;
 		if (!(nd_flags & IFF_PROMISC))
@@ -1701,6 +1705,7 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa)
 	if (ether_addr_equal(netdev->dev_addr, mac))
 		return 0;
 
+netdev_info(netdev, "%s: mac %pM\n", __func__, mac);
 	err = eth_prepare_mac_addr_change(netdev, addr);
 	if (err)
 		return err;
@@ -3200,6 +3205,7 @@ static int ionic_station_set(struct ionic_lif *lif)
 	struct sockaddr addr;
 	int err;
 
+dev_info(lif->ionic->dev, "%s: netdev addr %pM\n", __func__, netdev->dev_addr);
 	err = ionic_adminq_post_wait(lif, &ctx);
 	if (err)
 		return err;
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c
index 7e3a5634c161..ba0cbf487fd6 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c
@@ -244,6 +244,7 @@ int ionic_lif_list_addr(struct ionic_lif *lif, const u8 *addr, bool mode)
 	struct ionic_rx_filter *f;
 	int err;
 
+dev_info(lif->ionic->dev, "%s: addr %pM mode %d\n", __func__, addr, mode);
 	spin_lock_bh(&lif->rx_filters.lock);
 
 	f = ionic_rx_filter_by_addr(lif, addr);
@@ -349,6 +350,7 @@ void ionic_rx_filter_sync(struct ionic_lif *lif)
 	list_for_each_entry_safe(sync_item, spos, &sync_add_list, list) {
 		(void)ionic_lif_addr_add(lif, sync_item->f.cmd.mac.addr);
 
+dev_info(lif->ionic->dev, "%s: sync addr %pM state %d\n", __func__, sync_item->f.cmd.mac.addr, sync_item->f.state);
 		if (sync_item->f.state != IONIC_FILTER_STATE_SYNCED)
 			set_bit(IONIC_LIF_F_FILTER_SYNC_NEEDED, lif->state);
 
@@ -356,3 +358,28 @@ void ionic_rx_filter_sync(struct ionic_lif *lif)
 		devm_kfree(dev, sync_item);
 	}
 }
+
+void ionic_rx_filter_dump(struct ionic_lif *lif)
+{
+	struct device *dev = lif->ionic->dev;
+	struct ionic_rx_filter *f;
+	struct hlist_head *head;
+	struct hlist_node *tmp;
+	unsigned int i;
+
+	spin_lock_bh(&lif->rx_filters.lock);
+	for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
+		head = &lif->rx_filters.by_id[i];
+		hlist_for_each_entry_safe(f, tmp, head, by_id) {
+			dev_info(dev, "%s: mac %pM flow %d filter_id %d state %d rxq %d\n",
+				 __func__, f->cmd.mac.addr, f->flow_id, f->filter_id, f->state, f->rxq_index);
+
+		}
+	}
+	spin_unlock_bh(&lif->rx_filters.lock);
+
+	dev_info(dev, "%s: nucast %d nmcast %d\n",
+		 __func__, lif->nucast, lif->nmcast);
+	dev_info(dev, "%s: netdev_uc_count %d netdev_mc_count %d\n",
+		 __func__, netdev_uc_count(lif->netdev), netdev_mc_count(lif->netdev));
+}
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h
index a66e35f0833b..8a0b5460510f 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h
@@ -45,4 +45,5 @@ void ionic_rx_filter_sync(struct ionic_lif *lif);
 int ionic_lif_list_addr(struct ionic_lif *lif, const u8 *addr, bool mode);
 int ionic_rx_filters_need_sync(struct ionic_lif *lif);
 
+void ionic_rx_filter_dump(struct ionic_lif *lif);
 #endif /* _IONIC_RX_FILTER_H_ */
-- 
2.17.1

Re: [PATCH 6/6] filter-debug

From: Shannon Nelson <hidden>
Date: 2021-08-26 01:27:03

On 8/25/21 6:24 PM, Shannon Nelson wrote:
Signed-off-by: Shannon Nelson <redacted>
---

Argh... disregard.
sln

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help