git: c637a66be46c - releng/13.0 - ixl(4): Fix VLAN HW filtering

Eric Joyner erj at FreeBSD.org
Thu Mar 11 01:14:24 UTC 2021


The branch releng/13.0 has been updated by erj:

URL: https://cgit.FreeBSD.org/src/commit/?id=c637a66be46cca2bef968202af5a4970586908d0

commit c637a66be46cca2bef968202af5a4970586908d0
Author:     Krzysztof Galazka <krzysztof.galazka at intel.com>
AuthorDate: 2021-02-03 23:22:55 +0000
Commit:     Eric Joyner <erj at FreeBSD.org>
CommitDate: 2021-03-11 01:06:15 +0000

    ixl(4): Fix VLAN HW filtering
    
    X700 family of controllers has limited number of available VLAN
    HW filters. Driver did not handle properly a case when user
    assigned more VLANs to the interface which had all filters
    already in use. Fix that by disabling HW filtering when
    it is impossible to create filters for all requested VLANs.
    Keep track of registered VLANs using bitstring to be able
    to re-enable HW filtering when number of requested VLANs
    drops below the limit.
    
    Also switch all allocations to use M_IXL malloc type
    to ease detecting memory leaks in the driver.
    
    Reviewed by:    erj
    Tested by:      gowtham.kumar.ks at intel.com
    Approved by:    re (gjb)
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D28137
    
    (cherry picked from commit 7d4dceec103039e2b2fa90793ceeb71a8d6684aa)
    (cherry picked from commit 7e166d608eecf0188bbb7edf6b3d9abffe1dfc6b)
---
 sys/dev/ixl/i40e_osdep.c   |   4 +-
 sys/dev/ixl/iavf.h         |   7 +
 sys/dev/ixl/iavf_vc.c      |  20 +-
 sys/dev/ixl/if_iavf.c      |  20 +-
 sys/dev/ixl/if_ixl.c       |  81 ++++---
 sys/dev/ixl/ixl.h          |  49 ++--
 sys/dev/ixl/ixl_iw.c       |   8 +-
 sys/dev/ixl/ixl_pf.h       |  19 +-
 sys/dev/ixl/ixl_pf_iflib.c |  37 +--
 sys/dev/ixl/ixl_pf_iov.c   |   4 +-
 sys/dev/ixl/ixl_pf_main.c  | 551 ++++++++++++++++++++++++++++++---------------
 11 files changed, 487 insertions(+), 313 deletions(-)

diff --git a/sys/dev/ixl/i40e_osdep.c b/sys/dev/ixl/i40e_osdep.c
index df6848dff3f2..20eb02c85d67 100644
--- a/sys/dev/ixl/i40e_osdep.c
+++ b/sys/dev/ixl/i40e_osdep.c
@@ -51,14 +51,14 @@ i40e_dmamap_cb(void *arg, bus_dma_segment_t * segs, int nseg, int error)
 i40e_status
 i40e_allocate_virt_mem(struct i40e_hw *hw, struct i40e_virt_mem *mem, u32 size)
 {
-	mem->va = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
+	mem->va = malloc(size, M_IXL, M_NOWAIT | M_ZERO);
 	return (mem->va == NULL);
 }
 
 i40e_status
 i40e_free_virt_mem(struct i40e_hw *hw, struct i40e_virt_mem *mem)
 {
-	free(mem->va, M_DEVBUF);
+	free(mem->va, M_IXL);
 	mem->va = NULL;
 
 	return (I40E_SUCCESS);
diff --git a/sys/dev/ixl/iavf.h b/sys/dev/ixl/iavf.h
index e2a546f450d4..9a7716c5e5a2 100644
--- a/sys/dev/ixl/iavf.h
+++ b/sys/dev/ixl/iavf.h
@@ -43,6 +43,13 @@
 #define IAVF_MAX_QUEUES		16
 #define IAVF_AQ_TIMEOUT		(1 * hz)
 
+/* MacVlan Flags */
+#define IAVF_FILTER_USED	(u16)(1 << 0)
+#define IAVF_FILTER_VLAN	(u16)(1 << 1)
+#define IAVF_FILTER_ADD		(u16)(1 << 2)
+#define IAVF_FILTER_DEL		(u16)(1 << 3)
+#define IAVF_FILTER_MC		(u16)(1 << 4)
+
 #define IAVF_FLAG_AQ_ENABLE_QUEUES            (u32)(1 << 0)
 #define IAVF_FLAG_AQ_DISABLE_QUEUES           (u32)(1 << 1)
 #define IAVF_FLAG_AQ_ADD_MAC_FILTER           (u32)(1 << 2)
diff --git a/sys/dev/ixl/iavf_vc.c b/sys/dev/ixl/iavf_vc.c
index 2a77f390faaa..ed9cc8432438 100644
--- a/sys/dev/ixl/iavf_vc.c
+++ b/sys/dev/ixl/iavf_vc.c
@@ -456,7 +456,7 @@ iavf_add_vlans(struct iavf_sc *sc)
 
 	/* Get count of VLAN filters to add */
 	SLIST_FOREACH(f, sc->vlan_filters, next) {
-		if (f->flags & IXL_FILTER_ADD)
+		if (f->flags & IAVF_FILTER_ADD)
 			cnt++;
 	}
 
@@ -484,9 +484,9 @@ iavf_add_vlans(struct iavf_sc *sc)
 
 	/* Scan the filter array */
 	SLIST_FOREACH_SAFE(f, sc->vlan_filters, next, ftmp) {
-                if (f->flags & IXL_FILTER_ADD) {
+                if (f->flags & IAVF_FILTER_ADD) {
                         bcopy(&f->vlan, &v->vlan_id[i], sizeof(u16));
-			f->flags = IXL_FILTER_USED;
+			f->flags = IAVF_FILTER_USED;
                         i++;
                 }
                 if (i == cnt)
@@ -514,7 +514,7 @@ iavf_del_vlans(struct iavf_sc *sc)
 
 	/* Get count of VLAN filters to delete */
 	SLIST_FOREACH(f, sc->vlan_filters, next) {
-		if (f->flags & IXL_FILTER_DEL)
+		if (f->flags & IAVF_FILTER_DEL)
 			cnt++;
 	}
 
@@ -542,7 +542,7 @@ iavf_del_vlans(struct iavf_sc *sc)
 
 	/* Scan the filter array */
 	SLIST_FOREACH_SAFE(f, sc->vlan_filters, next, ftmp) {
-                if (f->flags & IXL_FILTER_DEL) {
+                if (f->flags & IAVF_FILTER_DEL) {
                         bcopy(&f->vlan, &v->vlan_id[i], sizeof(u16));
                         i++;
                         SLIST_REMOVE(sc->vlan_filters, f, iavf_vlan_filter, next);
@@ -575,7 +575,7 @@ iavf_add_ether_filters(struct iavf_sc *sc)
 
 	/* Get count of MAC addresses to add */
 	SLIST_FOREACH(f, sc->mac_filters, next) {
-		if (f->flags & IXL_FILTER_ADD)
+		if (f->flags & IAVF_FILTER_ADD)
 			cnt++;
 	}
 	if (cnt == 0) { /* Should not happen... */
@@ -597,9 +597,9 @@ iavf_add_ether_filters(struct iavf_sc *sc)
 
 	/* Scan the filter array */
 	SLIST_FOREACH(f, sc->mac_filters, next) {
-		if (f->flags & IXL_FILTER_ADD) {
+		if (f->flags & IAVF_FILTER_ADD) {
 			bcopy(f->macaddr, a->list[j].addr, ETHER_ADDR_LEN);
-			f->flags &= ~IXL_FILTER_ADD;
+			f->flags &= ~IAVF_FILTER_ADD;
 			j++;
 
 			iavf_dbg_vc(sc, "ADD: " MAC_FORMAT "\n",
@@ -633,7 +633,7 @@ iavf_del_ether_filters(struct iavf_sc *sc)
 
 	/* Get count of MAC addresses to delete */
 	SLIST_FOREACH(f, sc->mac_filters, next) {
-		if (f->flags & IXL_FILTER_DEL)
+		if (f->flags & IAVF_FILTER_DEL)
 			cnt++;
 	}
 	if (cnt == 0) {
@@ -655,7 +655,7 @@ iavf_del_ether_filters(struct iavf_sc *sc)
 
 	/* Scan the filter array */
 	SLIST_FOREACH_SAFE(f, sc->mac_filters, next, f_temp) {
-		if (f->flags & IXL_FILTER_DEL) {
+		if (f->flags & IAVF_FILTER_DEL) {
 			bcopy(f->macaddr, d->list[j].addr, ETHER_ADDR_LEN);
 			iavf_dbg_vc(sc, "DEL: " MAC_FORMAT "\n",
 			    MAC_FORMAT_ARGS(f->macaddr));
diff --git a/sys/dev/ixl/if_iavf.c b/sys/dev/ixl/if_iavf.c
index 2079e2d7306b..394656d27a2f 100644
--- a/sys/dev/ixl/if_iavf.c
+++ b/sys/dev/ixl/if_iavf.c
@@ -663,7 +663,7 @@ iavf_if_init(if_ctx_t ctx)
 	iavf_send_vc_msg(sc, IAVF_FLAG_AQ_DISABLE_QUEUES);
 
 	bcopy(IF_LLADDR(ifp), tmpaddr, ETHER_ADDR_LEN);
-	if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
+	if (!ixl_ether_is_equal(hw->mac.addr, tmpaddr) &&
 	    (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) {
 		error = iavf_del_mac_filter(sc, hw->mac.addr);
 		if (error == 0)
@@ -1233,7 +1233,7 @@ iavf_mc_filter_apply(void *arg, struct sockaddr_dl *sdl, u_int count __unused)
 	struct iavf_sc *sc = arg;
 	int error;
 
-	error = iavf_add_mac_filter(sc, (u8*)LLADDR(sdl), IXL_FILTER_MC);
+	error = iavf_add_mac_filter(sc, (u8*)LLADDR(sdl), IAVF_FILTER_MC);
 	return (!error);
 }
 
@@ -1404,7 +1404,7 @@ iavf_if_vlan_register(if_ctx_t ctx, u16 vtag)
 	v = malloc(sizeof(struct iavf_vlan_filter), M_IAVF, M_WAITOK | M_ZERO);
 	SLIST_INSERT_HEAD(sc->vlan_filters, v, next);
 	v->vlan = vtag;
-	v->flags = IXL_FILTER_ADD;
+	v->flags = IAVF_FILTER_ADD;
 
 	iavf_send_vc_msg(sc, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
 }
@@ -1422,7 +1422,7 @@ iavf_if_vlan_unregister(if_ctx_t ctx, u16 vtag)
 
 	SLIST_FOREACH(v, sc->vlan_filters, next) {
 		if (v->vlan == vtag) {
-			v->flags = IXL_FILTER_DEL;
+			v->flags = IAVF_FILTER_DEL;
 			++i;
 			--vsi->num_vlans;
 		}
@@ -1624,7 +1624,7 @@ iavf_find_mac_filter(struct iavf_sc *sc, u8 *macaddr)
 	bool match = FALSE;
 
 	SLIST_FOREACH(f, sc->mac_filters, next) {
-		if (cmp_etheraddr(f->macaddr, macaddr)) {
+		if (ixl_ether_is_equal(f->macaddr, macaddr)) {
 			match = TRUE;
 			break;
 		}
@@ -1828,9 +1828,9 @@ iavf_init_multi(struct iavf_sc *sc)
 
 	/* First clear any multicast filters */
 	SLIST_FOREACH(f, sc->mac_filters, next) {
-		if ((f->flags & IXL_FILTER_USED)
-		    && (f->flags & IXL_FILTER_MC)) {
-			f->flags |= IXL_FILTER_DEL;
+		if ((f->flags & IAVF_FILTER_USED)
+		    && (f->flags & IAVF_FILTER_MC)) {
+			f->flags |= IAVF_FILTER_DEL;
 			mcnt++;
 		}
 	}
@@ -2034,7 +2034,7 @@ iavf_add_mac_filter(struct iavf_sc *sc, u8 *macaddr, u16 flags)
 	    MAC_FORMAT_ARGS(macaddr));
 
 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
-	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
+	f->flags |= (IAVF_FILTER_ADD | IAVF_FILTER_USED);
 	f->flags |= flags;
 	return (0);
 }
@@ -2051,7 +2051,7 @@ iavf_del_mac_filter(struct iavf_sc *sc, u8 *macaddr)
 	if (f == NULL)
 		return (ENOENT);
 
-	f->flags |= IXL_FILTER_DEL;
+	f->flags |= IAVF_FILTER_DEL;
 	return (0);
 }
 
diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c
index 50eb448a1154..5a79b4403257 100644
--- a/sys/dev/ixl/if_ixl.c
+++ b/sys/dev/ixl/if_ixl.c
@@ -127,7 +127,6 @@ static void	 ixl_if_vflr_handle(if_ctx_t ctx);
 #endif
 
 /*** Other ***/
-static u_int	 ixl_mc_filter_apply(void *, struct sockaddr_dl *, u_int);
 static void	 ixl_save_pf_tunables(struct ixl_pf *);
 static int	 ixl_allocate_pci_resources(struct ixl_pf *);
 static void	 ixl_setup_ssctx(struct ixl_pf *pf);
@@ -862,7 +861,7 @@ ixl_if_detach(if_ctx_t ctx)
 
 	ixl_pf_qmgr_destroy(&pf->qmgr);
 	ixl_free_pci_resources(pf);
-	ixl_free_mac_filters(vsi);
+	ixl_free_filters(&vsi->ftl);
 	INIT_DBG_DEV(dev, "end");
 	return (0);
 }
@@ -937,9 +936,9 @@ ixl_if_init(if_ctx_t ctx)
 
 	/* Get the latest mac address... User might use a LAA */
 	bcopy(IF_LLADDR(vsi->ifp), tmpaddr, ETH_ALEN);
-	if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
+	if (!ixl_ether_is_equal(hw->mac.addr, tmpaddr) &&
 	    (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) {
-		ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
+		ixl_del_all_vlan_filters(vsi, hw->mac.addr);
 		bcopy(tmpaddr, hw->mac.addr, ETH_ALEN);
 		ret = i40e_aq_mac_address_write(hw,
 		    I40E_AQC_WRITE_TYPE_LAA_ONLY,
@@ -948,7 +947,10 @@ ixl_if_init(if_ctx_t ctx)
 			device_printf(dev, "LLA address change failed!!\n");
 			return;
 		}
-		ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
+		/*
+		 * New filters are configured by ixl_reconfigure_filters
+		 * at the end of ixl_init_locked.
+		 */
 	}
 
 	iflib_set_mac(ctx, hw->mac.addr);
@@ -1385,7 +1387,7 @@ ixl_if_update_admin_status(if_ctx_t ctx)
 	struct i40e_hw	*hw = &pf->hw;
 	u16		pending;
 
-	if (pf->state & IXL_PF_STATE_ADAPTER_RESETTING)
+	if (IXL_PF_IS_RESETTING(pf))
 		ixl_handle_empr_reset(pf);
 
 	/*
@@ -1418,32 +1420,22 @@ ixl_if_multi_set(if_ctx_t ctx)
 	struct ixl_pf *pf = iflib_get_softc(ctx);
 	struct ixl_vsi *vsi = &pf->vsi;
 	struct i40e_hw *hw = vsi->hw;
-	int mcnt, flags;
-	int del_mcnt;
+	int mcnt;
 
 	IOCTL_DEBUGOUT("ixl_if_multi_set: begin");
 
-	mcnt = min(if_llmaddr_count(iflib_get_ifp(ctx)), MAX_MULTICAST_ADDR);
 	/* Delete filters for removed multicast addresses */
-	del_mcnt = ixl_del_multi(vsi);
-	vsi->num_macs -= del_mcnt;
+	ixl_del_multi(vsi, false);
 
+	mcnt = min(if_llmaddr_count(iflib_get_ifp(ctx)), MAX_MULTICAST_ADDR);
 	if (__predict_false(mcnt == MAX_MULTICAST_ADDR)) {
 		i40e_aq_set_vsi_multicast_promiscuous(hw,
 		    vsi->seid, TRUE, NULL);
+		ixl_del_multi(vsi, true);
 		return;
 	}
-	/* (re-)install filters for all mcast addresses */
-	/* XXX: This bypasses filter count tracking code! */
-	mcnt = if_foreach_llmaddr(iflib_get_ifp(ctx), ixl_mc_filter_apply, vsi);
-	if (mcnt > 0) {
-		vsi->num_macs += mcnt;
-		flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
-		ixl_add_hw_filters(vsi, flags, mcnt);
-	}
 
-	ixl_dbg_filter(pf, "%s: filter mac total: %d\n",
-	    __func__, vsi->num_macs);
+	ixl_add_multi(vsi);
 	IOCTL_DEBUGOUT("ixl_if_multi_set: end");
 }
 
@@ -1661,12 +1653,35 @@ ixl_if_vlan_register(if_ctx_t ctx, u16 vtag)
 	struct ixl_pf *pf = iflib_get_softc(ctx);
 	struct ixl_vsi *vsi = &pf->vsi;
 	struct i40e_hw	*hw = vsi->hw;
+	if_t ifp = iflib_get_ifp(ctx);
 
 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
 		return;
 
+	/*
+	 * Keep track of registered VLANS to know what
+	 * filters have to be configured when VLAN_HWFILTER
+	 * capability is enabled.
+	 */
 	++vsi->num_vlans;
-	ixl_add_filter(vsi, hw->mac.addr, vtag);
+	bit_set(vsi->vlans_map, vtag);
+
+	if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0)
+		return;
+
+	if (vsi->num_vlans < IXL_MAX_VLAN_FILTERS)
+		ixl_add_filter(vsi, hw->mac.addr, vtag);
+	else if (vsi->num_vlans == IXL_MAX_VLAN_FILTERS) {
+		/*
+		 * There is not enough HW resources to add filters
+		 * for all registered VLANs. Re-configure filtering
+		 * to allow reception of all expected traffic.
+		 */
+		device_printf(vsi->dev,
+		    "Not enough HW filters for all VLANs. VLAN HW filtering disabled");
+		ixl_del_all_vlan_filters(vsi, hw->mac.addr);
+		ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
+	}
 }
 
 static void
@@ -1675,12 +1690,23 @@ ixl_if_vlan_unregister(if_ctx_t ctx, u16 vtag)
 	struct ixl_pf *pf = iflib_get_softc(ctx);
 	struct ixl_vsi *vsi = &pf->vsi;
 	struct i40e_hw	*hw = vsi->hw;
+	if_t ifp = iflib_get_ifp(ctx);
 
 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
 		return;
 
 	--vsi->num_vlans;
-	ixl_del_filter(vsi, hw->mac.addr, vtag);
+	bit_clear(vsi->vlans_map, vtag);
+
+	if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0)
+		return;
+
+	if (vsi->num_vlans < IXL_MAX_VLAN_FILTERS)
+		ixl_del_filter(vsi, hw->mac.addr, vtag);
+	else if (vsi->num_vlans == IXL_MAX_VLAN_FILTERS) {
+		ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
+		ixl_add_vlan_filters(vsi, hw->mac.addr);
+	}
 }
 
 static uint64_t
@@ -1798,15 +1824,6 @@ ixl_if_needs_restart(if_ctx_t ctx __unused, enum iflib_restart_event event)
 	}
 }
 
-static u_int
-ixl_mc_filter_apply(void *arg, struct sockaddr_dl *sdl, u_int count __unused)
-{
-	struct ixl_vsi *vsi = arg;
-
-	ixl_add_mc_filter(vsi, (u8*)LLADDR(sdl));
-	return (1);
-}
-
 /*
  * Sanity check and save off tunable values.
  */
diff --git a/sys/dev/ixl/ixl.h b/sys/dev/ixl/ixl.h
index 65e92c470a6c..3eb0fa4f6b5a 100644
--- a/sys/dev/ixl/ixl.h
+++ b/sys/dev/ixl/ixl.h
@@ -53,6 +53,7 @@
 #include <sys/eventhandler.h>
 #include <sys/syslog.h>
 #include <sys/priv.h>
+#include <sys/bitstring.h>
 
 #include <net/if.h>
 #include <net/if_var.h>
@@ -187,15 +188,15 @@
 #define IXL_BULK_LATENCY	2
 
 /* MacVlan Flags */
-#define IXL_FILTER_USED		(u16)(1 << 0)
-#define IXL_FILTER_VLAN		(u16)(1 << 1)
-#define IXL_FILTER_ADD		(u16)(1 << 2)
-#define IXL_FILTER_DEL		(u16)(1 << 3)
-#define IXL_FILTER_MC		(u16)(1 << 4)
+#define IXL_FILTER_VLAN		(u16)(1 << 0)
+#define IXL_FILTER_MC		(u16)(1 << 1)
 
 /* used in the vlan field of the filter when not a vlan */
 #define IXL_VLAN_ANY		-1
 
+/* Maximum number of MAC/VLAN filters supported by HW */
+#define IXL_MAX_VLAN_FILTERS	256
+
 #define CSUM_OFFLOAD_IPV4	(CSUM_IP|CSUM_TCP|CSUM_UDP|CSUM_SCTP)
 #define CSUM_OFFLOAD_IPV6	(CSUM_TCP_IPV6|CSUM_UDP_IPV6|CSUM_SCTP_IPV6)
 #define CSUM_OFFLOAD		(CSUM_OFFLOAD_IPV4|CSUM_OFFLOAD_IPV6|CSUM_TSO)
@@ -303,16 +304,18 @@
 /* For stats sysctl naming */
 #define IXL_QUEUE_NAME_LEN 32
 
+MALLOC_DECLARE(M_IXL);
+
 #define IXL_DEV_ERR(_dev, _format, ...) \
 	device_printf(_dev, "%s: " _format " (%s:%d)\n", __func__, ##__VA_ARGS__, __FILE__, __LINE__)
 
 /*
  *****************************************************************************
  * vendor_info_array
- * 
+ *
  * This array contains the list of Subvendor/Subdevice IDs on which the driver
  * should load.
- * 
+ *
  *****************************************************************************
  */
 typedef struct _ixl_vendor_info_t {
@@ -328,7 +331,7 @@ typedef struct _ixl_vendor_info_t {
 ** addresses, vlans, and mac filters all use it.
 */
 struct ixl_mac_filter {
-	SLIST_ENTRY(ixl_mac_filter) next;
+	LIST_ENTRY(ixl_mac_filter) ftle;
 	u8	macaddr[ETHER_ADDR_LEN];
 	s16	vlan;
 	u16	flags;
@@ -414,7 +417,7 @@ struct ixl_rx_queue {
 /*
 ** Virtual Station Interface
 */
-SLIST_HEAD(ixl_ftl_head, ixl_mac_filter);
+LIST_HEAD(ixl_ftl_head, ixl_mac_filter);
 struct ixl_vsi {
 	if_ctx_t		ctx;
 	if_softc_ctx_t		shared;
@@ -452,6 +455,8 @@ struct ixl_vsi {
 	/* Contains readylist & stat counter id */
 	struct i40e_aqc_vsi_properties_data info;
 
+#define IXL_VLANS_MAP_LEN EVL_VLID_MASK + 1
+	bitstr_t		bit_decl(vlans_map, IXL_VLANS_MAP_LEN);
 	u16			num_vlans;
 
 	/* Per-VSI stats from hardware */
@@ -478,32 +483,16 @@ struct ixl_vsi {
 	struct sysctl_ctx_list  sysctl_ctx;
 };
 
-/*
-** Creates new filter with given MAC address and VLAN ID
-*/
-static inline struct ixl_mac_filter *
-ixl_new_filter(struct ixl_vsi *vsi, const u8 *macaddr, s16 vlan)
-{
-	struct ixl_mac_filter  *f;
-
-	/* create a new empty filter */
-	f = malloc(sizeof(struct ixl_mac_filter),
-	    M_DEVBUF, M_NOWAIT | M_ZERO);
-	if (f) {
-		SLIST_INSERT_HEAD(&vsi->ftl, f, next);
-		bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
-		f->vlan = vlan;
-		f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
-	}
-
-	return (f);
-}
+struct ixl_add_maddr_arg {
+	struct ixl_ftl_head to_add;
+	struct ixl_vsi *vsi;
+};
 
 /*
 ** Compare two ethernet addresses
 */
 static inline bool
-cmp_etheraddr(const u8 *ea1, const u8 *ea2)
+ixl_ether_is_equal(const u8 *ea1, const u8 *ea2)
 {
 	return (bcmp(ea1, ea2, ETHER_ADDR_LEN) == 0);
 }
diff --git a/sys/dev/ixl/ixl_iw.c b/sys/dev/ixl/ixl_iw.c
index 6557e9dca4b3..5e2d7cfcb30b 100644
--- a/sys/dev/ixl/ixl_iw.c
+++ b/sys/dev/ixl/ixl_iw.c
@@ -238,7 +238,7 @@ ixl_iw_pf_attach(struct ixl_pf *pf)
 		}
 
 	pf_entry = malloc(sizeof(struct ixl_iw_pf_entry),
-			M_DEVBUF, M_NOWAIT | M_ZERO);
+			M_IXL, M_NOWAIT | M_ZERO);
 	if (pf_entry == NULL) {
 		device_printf(pf->dev,
 		    "%s: failed to allocate memory to attach new PF\n",
@@ -289,7 +289,7 @@ ixl_iw_pf_detach(struct ixl_pf *pf)
 		goto out;
 	}
 	LIST_REMOVE(pf_entry, node);
-	free(pf_entry, M_DEVBUF);
+	free(pf_entry, M_IXL);
 	ixl_iw_ref_cnt--;
 
 out:
@@ -414,7 +414,7 @@ ixl_iw_register(struct ixl_iw_ops *ops)
 	taskqueue_start_threads(&ixl_iw.tq, 1, PI_NET, "ixl iw");
 
 	ixl_iw.ops = malloc(sizeof(struct ixl_iw_ops),
-			M_DEVBUF, M_NOWAIT | M_ZERO);
+			M_IXL, M_NOWAIT | M_ZERO);
 	if (ixl_iw.ops == NULL) {
 		printf("%s: failed to allocate memory\n", __func__);
 		taskqueue_free(ixl_iw.tq);
@@ -481,7 +481,7 @@ ixl_iw_unregister(void)
 		taskqueue_drain(ixl_iw.tq, &pf_entry->iw_task);
 	taskqueue_free(ixl_iw.tq);
 	ixl_iw.tq = NULL;
-	free(ixl_iw.ops, M_DEVBUF);
+	free(ixl_iw.ops, M_IXL);
 	ixl_iw.ops = NULL;
 
 	return (0);
diff --git a/sys/dev/ixl/ixl_pf.h b/sys/dev/ixl/ixl_pf.h
index 0521ae5a4bc5..c3fbdc91d358 100644
--- a/sys/dev/ixl/ixl_pf.h
+++ b/sys/dev/ixl/ixl_pf.h
@@ -78,7 +78,7 @@ enum ixl_i2c_access_method_t {
 /* Used in struct ixl_pf's state field */
 enum ixl_pf_state {
 	IXL_PF_STATE_RECOVERY_MODE	= (1 << 0),
-	IXL_PF_STATE_ADAPTER_RESETTING	= (1 << 1),
+	IXL_PF_STATE_RESETTING		= (1 << 1),
 	IXL_PF_STATE_MDD_PENDING	= (1 << 2),
 	IXL_PF_STATE_PF_RESET_REQ	= (1 << 3),
 	IXL_PF_STATE_VF_RESET_REQ	= (1 << 4),
@@ -93,6 +93,8 @@ enum ixl_pf_state {
 #define IXL_PF_IN_RECOVERY_MODE(pf)	\
 	((atomic_load_acq_32(&pf->state) & IXL_PF_STATE_RECOVERY_MODE) != 0)
 
+#define IXL_PF_IS_RESETTING(pf)	\
+	((atomic_load_acq_32(&pf->state) & IXL_PF_STATE_RESETTING) != 0)
 
 struct ixl_vf {
 	struct ixl_vsi		vsi;
@@ -258,8 +260,6 @@ struct ixl_pf {
 "\t1 - Enable (VEB)\n"				\
 "Enabling this will allow VFs in separate VMs to communicate over the hardware bridge."
 
-MALLOC_DECLARE(M_IXL);
-
 /*** Functions / Macros ***/
 /* Adjust the level here to 10 or over to print stats messages */
 #define	I40E_VC_DEBUG(p, level, ...)				\
@@ -367,6 +367,8 @@ void	ixl_set_queue_tx_itr(struct ixl_tx_queue *);
 
 void	ixl_add_filter(struct ixl_vsi *, const u8 *, s16 vlan);
 void	ixl_del_filter(struct ixl_vsi *, const u8 *, s16 vlan);
+void	ixl_add_vlan_filters(struct ixl_vsi *, const u8 *);
+void	ixl_del_all_vlan_filters(struct ixl_vsi *, const u8 *);
 void	ixl_reconfigure_filters(struct ixl_vsi *vsi);
 
 int	ixl_disable_rings(struct ixl_pf *, struct ixl_vsi *, struct ixl_pf_qtag *);
@@ -391,16 +393,15 @@ void	ixl_enable_intr(struct ixl_vsi *);
 void	ixl_disable_rings_intr(struct ixl_vsi *);
 void	ixl_set_promisc(struct ixl_vsi *);
 void	ixl_add_multi(struct ixl_vsi *);
-int	ixl_del_multi(struct ixl_vsi *);
+void	ixl_del_multi(struct ixl_vsi *, bool);
 void	ixl_setup_vlan_filters(struct ixl_vsi *);
 void	ixl_init_filters(struct ixl_vsi *);
-void	ixl_add_hw_filters(struct ixl_vsi *, int, int);
-void	ixl_del_hw_filters(struct ixl_vsi *, int);
+void	ixl_free_filters(struct ixl_ftl_head *);
+void	ixl_add_hw_filters(struct ixl_vsi *, struct ixl_ftl_head *, int);
+void	ixl_del_hw_filters(struct ixl_vsi *, struct ixl_ftl_head *, int);
 void	ixl_del_default_hw_filters(struct ixl_vsi *);
 struct ixl_mac_filter *
-		ixl_find_filter(struct ixl_vsi *, const u8 *, s16);
-void	ixl_add_mc_filter(struct ixl_vsi *, u8 *);
-void	ixl_free_mac_filters(struct ixl_vsi *vsi);
+		ixl_find_filter(struct ixl_ftl_head *, const u8 *, s16);
 void	ixl_update_vsi_stats(struct ixl_vsi *);
 void	ixl_vsi_reset_stats(struct ixl_vsi *);
 
diff --git a/sys/dev/ixl/ixl_pf_iflib.c b/sys/dev/ixl/ixl_pf_iflib.c
index 4351f65ee5ab..2b3d035fbcfe 100644
--- a/sys/dev/ixl/ixl_pf_iflib.c
+++ b/sys/dev/ixl/ixl_pf_iflib.c
@@ -185,7 +185,7 @@ ixl_msix_adminq(void *arg)
 		}
 		device_printf(dev, "Reset Requested! (%s)\n", reset_type);
 		/* overload admin queue task to check reset progress */
-		atomic_set_int(&pf->state, IXL_PF_STATE_ADAPTER_RESETTING);
+		atomic_set_int(&pf->state, IXL_PF_STATE_RESETTING);
 		do_task = TRUE;
 	}
 
@@ -866,41 +866,6 @@ ixl_set_rss_hlut(struct ixl_pf *pf)
 	}
 }
 
-/*
-** This routine updates vlan filters, called by init
-** it scans the filter table and then updates the hw
-** after a soft reset.
-*/
-void
-ixl_setup_vlan_filters(struct ixl_vsi *vsi)
-{
-	struct ixl_mac_filter	*f;
-	int			cnt = 0, flags;
-
-	if (vsi->num_vlans == 0)
-		return;
-	/*
-	** Scan the filter list for vlan entries,
-	** mark them for addition and then call
-	** for the AQ update.
-	*/
-	SLIST_FOREACH(f, &vsi->ftl, next) {
-		if (f->flags & IXL_FILTER_VLAN) {
-			f->flags |=
-			    (IXL_FILTER_ADD |
-			    IXL_FILTER_USED);
-			cnt++;
-		}
-	}
-	if (cnt == 0) {
-		printf("setup vlan: no filters found!\n");
-		return;
-	}
-	flags = IXL_FILTER_VLAN;
-	flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
-	ixl_add_hw_filters(vsi, flags, cnt);
-}
-
 /* For PF VSI only */
 int
 ixl_enable_rings(struct ixl_vsi *vsi)
diff --git a/sys/dev/ixl/ixl_pf_iov.c b/sys/dev/ixl/ixl_pf_iov.c
index 92e434eab9fc..c3cf90d1c4b5 100644
--- a/sys/dev/ixl/ixl_pf_iov.c
+++ b/sys/dev/ixl/ixl_pf_iov.c
@@ -1025,7 +1025,7 @@ ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr)
 	 * is not its assigned MAC.
 	 */
 	if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) &&
-	    !(ETHER_IS_MULTICAST(addr) || cmp_etheraddr(addr, vf->mac)))
+	    !(ETHER_IS_MULTICAST(addr) || !ixl_ether_is_equal(addr, vf->mac)))
 		return (EPERM);
 
 	return (0);
@@ -1717,7 +1717,7 @@ ixl_if_iov_uninit(if_ctx_t ctx)
 		if (pf->vfs[i].vsi.seid != 0)
 			i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL);
 		ixl_pf_qmgr_release(&pf->qmgr, &pf->vfs[i].qtag);
-		ixl_free_mac_filters(&pf->vfs[i].vsi);
+		ixl_free_filters(&pf->vfs[i].vsi.ftl);
 		ixl_dbg_iov(pf, "VF %d: %d released\n",
 		    i, pf->vfs[i].qtag.num_allocated);
 		ixl_dbg_iov(pf, "Unallocated total: %d\n", ixl_pf_qmgr_get_num_free(&pf->qmgr));
diff --git a/sys/dev/ixl/ixl_pf_main.c b/sys/dev/ixl/ixl_pf_main.c
index eddd4dfaab0d..2714b1a0e6d8 100644
--- a/sys/dev/ixl/ixl_pf_main.c
+++ b/sys/dev/ixl/ixl_pf_main.c
@@ -326,7 +326,7 @@ ixl_get_hw_capabilities(struct ixl_pf *pf)
 	len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
 retry:
 	if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *)
-	    malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) {
+	    malloc(len, M_IXL, M_NOWAIT | M_ZERO))) {
 		device_printf(dev, "Unable to allocate cap memory\n");
                 return (ENOMEM);
 	}
@@ -334,7 +334,7 @@ retry:
 	/* This populates the hw struct */
         status = i40e_aq_discover_capabilities(hw, buf, len,
 	    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
-	free(buf, M_DEVBUF);
+	free(buf, M_IXL);
 	if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) &&
 	    (again == TRUE)) {
 		/* retry once with a larger buffer */
@@ -452,12 +452,67 @@ err_out:
 	return (status);
 }
 
+/*
+** Creates new filter with given MAC address and VLAN ID
+*/
+static struct ixl_mac_filter *
+ixl_new_filter(struct ixl_ftl_head *headp, const u8 *macaddr, s16 vlan)
+{
+	struct ixl_mac_filter  *f;
+
+	/* create a new empty filter */
+	f = malloc(sizeof(struct ixl_mac_filter),
+	    M_IXL, M_NOWAIT | M_ZERO);
+	if (f) {
+		LIST_INSERT_HEAD(headp, f, ftle);
+		bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
+		f->vlan = vlan;
+	}
+
+	return (f);
+}
+
+/**
+ * ixl_free_filters - Free all filters in given list
+ * headp - pointer to list head
+ *
+ * Frees memory used by each entry in the list.
+ * Does not remove filters from HW.
+ */
+void
+ixl_free_filters(struct ixl_ftl_head *headp)
+{
+	struct ixl_mac_filter *f, *nf;
+
+	f = LIST_FIRST(headp);
+	while (f != NULL) {
+		nf = LIST_NEXT(f, ftle);
+		free(f, M_IXL);
+		f = nf;
+	}
+
+	LIST_INIT(headp);
+}
+
 static u_int
 ixl_add_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
 {
-	struct ixl_vsi *vsi = arg;
+	struct ixl_add_maddr_arg *ama = arg;
+	struct ixl_vsi *vsi = ama->vsi;
+	const u8 *macaddr = (u8*)LLADDR(sdl);
+	struct ixl_mac_filter *f;
 
-	ixl_add_mc_filter(vsi, (u8*)LLADDR(sdl));
+	/* Does one already exist */
+	f = ixl_find_filter(&vsi->ftl, macaddr, IXL_VLAN_ANY);
+	if (f != NULL)
+		return (0);
+
+	f = ixl_new_filter(&ama->to_add, macaddr, IXL_VLAN_ANY);
+	if (f == NULL) {
+		device_printf(vsi->dev, "WARNING: no filter available!!\n");
+		return (0);
+	}
+	f->flags |= IXL_FILTER_MC;
 
 	return (1);
 }
@@ -473,28 +528,26 @@ ixl_add_multi(struct ixl_vsi *vsi)
 {
 	struct ifnet		*ifp = vsi->ifp;
 	struct i40e_hw		*hw = vsi->hw;
-	int			mcnt = 0, flags;
+	int			mcnt = 0;
+	struct ixl_add_maddr_arg cb_arg;
 
 	IOCTL_DEBUGOUT("ixl_add_multi: begin");
 
-	/*
-	** First just get a count, to decide if we
-	** we simply use multicast promiscuous.
-	*/
 	mcnt = if_llmaddr_count(ifp);
 	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
-		/* delete existing MC filters */
-		ixl_del_hw_filters(vsi, mcnt);
 		i40e_aq_set_vsi_multicast_promiscuous(hw,
 		    vsi->seid, TRUE, NULL);
+		/* delete all existing MC filters */
+		ixl_del_multi(vsi, true);
 		return;
 	}
 
-	mcnt = if_foreach_llmaddr(ifp, ixl_add_maddr, vsi);
-	if (mcnt > 0) {
-		flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
-		ixl_add_hw_filters(vsi, flags, mcnt);
-	}
+	cb_arg.vsi = vsi;
+	LIST_INIT(&cb_arg.to_add);
+
+	mcnt = if_foreach_llmaddr(ifp, ixl_add_maddr, &cb_arg);
+	if (mcnt > 0)
+		ixl_add_hw_filters(vsi, &cb_arg.to_add, mcnt);
 
 	IOCTL_DEBUGOUT("ixl_add_multi: end");
 }
@@ -504,34 +557,36 @@ ixl_match_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
 {
 	struct ixl_mac_filter *f = arg;
 
-	if (cmp_etheraddr(f->macaddr, (u8 *)LLADDR(sdl)))
+	if (ixl_ether_is_equal(f->macaddr, (u8 *)LLADDR(sdl)))
 		return (1);
 	else
 		return (0);
 }
 
-int
-ixl_del_multi(struct ixl_vsi *vsi)
+void
+ixl_del_multi(struct ixl_vsi *vsi, bool all)
 {
+	struct ixl_ftl_head	to_del;
 	struct ifnet		*ifp = vsi->ifp;
-	struct ixl_mac_filter	*f;
+	struct ixl_mac_filter	*f, *fn;
 	int			mcnt = 0;
 
 	IOCTL_DEBUGOUT("ixl_del_multi: begin");
 
+	LIST_INIT(&to_del);
 	/* Search for removed multicast addresses */
-	SLIST_FOREACH(f, &vsi->ftl, next)
-		if ((f->flags & IXL_FILTER_USED) &&
-		    (f->flags & IXL_FILTER_MC) &&
-		    (if_foreach_llmaddr(ifp, ixl_match_maddr, f) == 0)) {
-			f->flags |= IXL_FILTER_DEL;
-			mcnt++;
-		}
+	LIST_FOREACH_SAFE(f, &vsi->ftl, ftle, fn) {
+		if ((f->flags & IXL_FILTER_MC) == 0 ||
+		    (!all && (if_foreach_llmaddr(ifp, ixl_match_maddr, f) == 0)))
+			continue;
 
-	if (mcnt > 0)
-		ixl_del_hw_filters(vsi, mcnt);
+		LIST_REMOVE(f, ftle);
+		LIST_INSERT_HEAD(&to_del, f, ftle);
+		mcnt++;
+	}
 
-	return (mcnt);
+	if (mcnt > 0)
+		ixl_del_hw_filters(vsi, &to_del, mcnt);
 }
 
 void
@@ -738,20 +793,6 @@ ixl_switch_config(struct ixl_pf *pf)
 	return (ret);
 }
 
-void
-ixl_free_mac_filters(struct ixl_vsi *vsi)
-{
-	struct ixl_mac_filter *f;
-
-	while (!SLIST_EMPTY(&vsi->ftl)) {
-		f = SLIST_FIRST(&vsi->ftl);
-		SLIST_REMOVE_HEAD(&vsi->ftl, next);
-		free(f, M_DEVBUF);
-	}
-
-	vsi->num_hw_filters = 0;
-}
-
 void
 ixl_vsi_add_sysctls(struct ixl_vsi * vsi, const char * sysctl_name, bool queues_sysctls)
 {
@@ -1019,7 +1060,7 @@ ixl_init_filters(struct ixl_vsi *vsi)
 	ixl_dbg_filter(pf, "%s: start\n", __func__);
 
 	/* Initialize mac filter list for VSI */
-	SLIST_INIT(&vsi->ftl);
+	LIST_INIT(&vsi->ftl);
 	vsi->num_hw_filters = 0;
 
 	/* Receive broadcast Ethernet frames */
@@ -1045,30 +1086,35 @@ ixl_init_filters(struct ixl_vsi *vsi)
 #endif
 }
 
-/*
-** This routine adds mulicast filters
-*/
 void
-ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr)
+ixl_reconfigure_filters(struct ixl_vsi *vsi)
 {
-	struct ixl_mac_filter *f;
+	struct i40e_hw *hw = vsi->hw;
+	struct ixl_ftl_head tmp;
+	int cnt;
 
-	/* Does one already exist */
-	f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
-	if (f != NULL)
-		return;
+	/*
+	 * The ixl_add_hw_filters function adds filters configured
+	 * in HW to a list in VSI. Move all filters to a temporary
+	 * list to avoid corrupting it by concatenating to itself.
+	 */
+	LIST_INIT(&tmp);
+	LIST_CONCAT(&tmp, &vsi->ftl, ixl_mac_filter, ftle);
+	cnt = vsi->num_hw_filters;
+	vsi->num_hw_filters = 0;
 
-	f = ixl_new_filter(vsi, macaddr, IXL_VLAN_ANY);
-	if (f != NULL)
-		f->flags |= IXL_FILTER_MC;
-	else
-		printf("WARNING: no filter available!!\n");
-}
+	ixl_add_hw_filters(vsi, &tmp, cnt);
 
-void
-ixl_reconfigure_filters(struct ixl_vsi *vsi)
-{
-	ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs);
+	/* Filter could be removed if MAC address was changed */
+	ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
+
+	if ((if_getcapenable(vsi->ifp) & IFCAP_VLAN_HWFILTER) == 0)
+		return;
+	/*
+	 * VLAN HW filtering is enabled, make sure that filters
+	 * for all registered VLAN tags are configured
+	 */
+	ixl_add_vlan_filters(vsi, hw->mac.addr);
 }
 
 /*
@@ -1082,82 +1128,205 @@ ixl_add_filter(struct ixl_vsi *vsi, const u8 *macaddr, s16 vlan)
 	struct ixl_mac_filter	*f, *tmp;
 	struct ixl_pf		*pf;
 	device_t		dev;
+	struct ixl_ftl_head	to_add;
*** 553 LINES SKIPPED ***


More information about the dev-commits-src-all mailing list