Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Feb 2021 22:25:19 GMT
From:      Navdeep Parhar <np@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 7ac8040a9931 - main - cxgbe(4): Use firmware commands to get/set filter configuration.
Message-ID:  <202102192225.11JMPJhQ093491@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by np:

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

commit 7ac8040a99319456c3225cd5166390f5bd172fdf
Author:     Navdeep Parhar <np@FreeBSD.org>
AuthorDate: 2021-02-19 21:05:19 +0000
Commit:     Navdeep Parhar <np@FreeBSD.org>
CommitDate: 2021-02-19 22:23:58 +0000

    cxgbe(4): Use firmware commands to get/set filter configuration.
    
    1. Query the firmware for filter mode, mask, and related ingress config
       instead of trying to figure them out from hardware registers.  Read
       configuration from the registers only when the firmware does not
       support this query.
    
    2. Use the firmware to set the filter mode.  This is the correct way to
       do it and is more flexible as well.  The filter mode (and associated
       ingress config) can now be changed any time it is safe to do so.
    
       The user can specify a subset of a valid mode and the driver will
       enable enough bits to make sure that the mode is maxed out -- that
       is, it is not possible to set another bit without exceeding the
       total width for optional filter fields.  This is a hardware
       requirement that was not enforced by the driver previously.
    
    MFC after:      2 weeks
    Sponsored by:   Chelsio Communications
---
 sys/dev/cxgbe/common/common.h           |   9 +-
 sys/dev/cxgbe/common/t4_hw.c            | 190 +++++++++++++++++++++++++------
 sys/dev/cxgbe/firmware/t4fw_interface.h |   5 +
 sys/dev/cxgbe/t4_filter.c               | 196 +++++++++++++++++++-------------
 sys/dev/cxgbe/t4_ioctl.h                |  14 +--
 sys/dev/cxgbe/tom/t4_tom.c              |   2 +-
 6 files changed, 287 insertions(+), 129 deletions(-)

diff --git a/sys/dev/cxgbe/common/common.h b/sys/dev/cxgbe/common/common.h
index 9cc923eaf2f6..53be2fa2588a 100644
--- a/sys/dev/cxgbe/common/common.h
+++ b/sys/dev/cxgbe/common/common.h
@@ -256,11 +256,11 @@ struct tp_params {
 	unsigned int la_mask;        /* what events are recorded by TP LA */
 	unsigned short tx_modq[MAX_NCHAN];  /* channel to modulation queue map */
 
-	uint32_t vlan_pri_map;
-	uint32_t ingress_config;
+	uint16_t filter_mode;
+	uint16_t filter_mask;	/* Used by TOE and hashfilters */
+	int vnic_mode;
 	uint32_t max_rx_pdu;
 	uint32_t max_tx_pdu;
-	uint64_t hash_filter_mask;
 	bool rx_pkt_encap;
 
 	int8_t fcoe_shift;
@@ -753,8 +753,7 @@ int t4_set_sched_ipg(struct adapter *adap, int sched, unsigned int ipg);
 int t4_set_pace_tbl(struct adapter *adap, const unsigned int *pace_vals,
 		    unsigned int start, unsigned int n);
 void t4_get_chan_txrate(struct adapter *adap, u64 *nic_rate, u64 *ofld_rate);
-int t4_set_filter_mode(struct adapter *adap, unsigned int mode_map,
-    bool sleep_ok);
+int t4_set_filter_cfg(struct adapter *adap, int mode, int mask, int vnic_mode);
 void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid);
 
 void t4_wol_magic_enable(struct adapter *adap, unsigned int port, const u8 *addr);
diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c
index 36d8864de960..8b22f2e4f5ba 100644
--- a/sys/dev/cxgbe/common/t4_hw.c
+++ b/sys/dev/cxgbe/common/t4_hw.c
@@ -9633,19 +9633,74 @@ int t4_init_sge_params(struct adapter *adapter)
 	return 0;
 }
 
+/* Convert the LE's hardware hash mask to a shorter filter mask. */
+static inline uint16_t
+hashmask_to_filtermask(uint64_t hashmask, uint16_t filter_mode)
+{
+	static const uint8_t width[] = {1, 3, 17, 17, 8, 8, 16, 9, 3, 1};
+	int i;
+	uint16_t filter_mask;
+	uint64_t mask;		/* field mask */
+
+	filter_mask = 0;
+	for (i = S_FCOE; i <= S_FRAGMENTATION; i++) {
+		if ((filter_mode & (1 << i)) == 0)
+			continue;
+		mask = (1 << width[i]) - 1;
+		if ((hashmask & mask) == mask)
+			filter_mask |= 1 << i;
+		hashmask >>= width[i];
+	}
+
+	return (filter_mask);
+}
+
 /*
  * Read and cache the adapter's compressed filter mode and ingress config.
  */
-static void read_filter_mode_and_ingress_config(struct adapter *adap,
-    bool sleep_ok)
+static void
+read_filter_mode_and_ingress_config(struct adapter *adap)
 {
-	uint32_t v;
+	int rc;
+	uint32_t v, param[2], val[2];
 	struct tp_params *tpp = &adap->params.tp;
+	uint64_t hash_mask;
+
+	param[0] = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_FILTER) |
+	    V_FW_PARAMS_PARAM_Y(FW_PARAM_DEV_FILTER_MODE_MASK);
+	param[1] = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_FILTER) |
+	    V_FW_PARAMS_PARAM_Y(FW_PARAM_DEV_FILTER_VNIC_MODE);
+	rc = -t4_query_params(adap, adap->mbox, adap->pf, 0, 2, param, val);
+	if (rc == 0) {
+		tpp->filter_mode = G_FW_PARAMS_PARAM_FILTER_MODE(val[0]);
+		tpp->filter_mask = G_FW_PARAMS_PARAM_FILTER_MASK(val[0]);
+		tpp->vnic_mode = val[1];
+	} else {
+		/*
+		 * Old firmware.  Read filter mode/mask and ingress config
+		 * straight from the hardware.
+		 */
+		t4_tp_pio_read(adap, &v, 1, A_TP_VLAN_PRI_MAP, true);
+		tpp->filter_mode = v & 0xffff;
+
+		hash_mask = 0;
+		if (chip_id(adap) > CHELSIO_T4) {
+			v = t4_read_reg(adap, LE_HASH_MASK_GEN_IPV4T5(3));
+			hash_mask = v;
+			v = t4_read_reg(adap, LE_HASH_MASK_GEN_IPV4T5(4));
+			hash_mask |= (u64)v << 32;
+		}
+		tpp->filter_mask = hashmask_to_filtermask(hash_mask,
+		    tpp->filter_mode);
 
-	t4_tp_pio_read(adap, &tpp->vlan_pri_map, 1, A_TP_VLAN_PRI_MAP,
-	    sleep_ok);
-	t4_tp_pio_read(adap, &tpp->ingress_config, 1, A_TP_INGRESS_CONFIG,
-	    sleep_ok);
+		t4_tp_pio_read(adap, &v, 1, A_TP_INGRESS_CONFIG, true);
+		if (v & F_VNIC)
+			tpp->vnic_mode = FW_VNIC_MODE_PF_VF;
+		else
+			tpp->vnic_mode = FW_VNIC_MODE_OUTER_VLAN;
+	}
 
 	/*
 	 * Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field
@@ -9662,13 +9717,6 @@ static void read_filter_mode_and_ingress_config(struct adapter *adap,
 	tpp->macmatch_shift = t4_filter_field_shift(adap, F_MACMATCH);
 	tpp->matchtype_shift = t4_filter_field_shift(adap, F_MPSHITTYPE);
 	tpp->frag_shift = t4_filter_field_shift(adap, F_FRAGMENTATION);
-
-	if (chip_id(adap) > CHELSIO_T4) {
-		v = t4_read_reg(adap, LE_HASH_MASK_GEN_IPV4T5(3));
-		adap->params.tp.hash_filter_mask = v;
-		v = t4_read_reg(adap, LE_HASH_MASK_GEN_IPV4T5(4));
-		adap->params.tp.hash_filter_mask |= (u64)v << 32;
-	}
 }
 
 /**
@@ -9691,7 +9739,7 @@ int t4_init_tp_params(struct adapter *adap)
 	for (chan = 0; chan < MAX_NCHAN; chan++)
 		tpp->tx_modq[chan] = chan;
 
-	read_filter_mode_and_ingress_config(adap, true);
+	read_filter_mode_and_ingress_config(adap);
 
 	if (chip_id(adap) > CHELSIO_T5) {
 		v = t4_read_reg(adap, A_TP_OUT_CONFIG);
@@ -9728,7 +9776,7 @@ int t4_init_tp_params(struct adapter *adap)
  */
 int t4_filter_field_shift(const struct adapter *adap, int filter_sel)
 {
-	unsigned int filter_mode = adap->params.tp.vlan_pri_map;
+	const unsigned int filter_mode = adap->params.tp.filter_mode;
 	unsigned int sel;
 	int field_shift;
 
@@ -10798,30 +10846,98 @@ out:
 }
 
 /**
- *	t4_set_filter_mode - configure the optional components of filter tuples
+ *	t4_set_filter_cfg - set up filter mode/mask and ingress config.
  *	@adap: the adapter
- *	@mode_map: a bitmap selcting which optional filter components to enable
- * 	@sleep_ok: if true we may sleep while awaiting command completion
- *
- *	Sets the filter mode by selecting the optional components to enable
- *	in filter tuples.  Returns 0 on success and a negative error if the
- *	requested mode needs more bits than are available for optional
- *	components.
- */
-int t4_set_filter_mode(struct adapter *adap, unsigned int mode_map,
-		       bool sleep_ok)
-{
-	static u8 width[] = { 1, 3, 17, 17, 8, 8, 16, 9, 3, 1 };
+ *	@mode: a bitmap selecting which optional filter components to enable
+ *	@mask: a bitmap selecting which components to enable in filter mask
+ *	@vnic_mode: the ingress config/vnic mode setting
+ *
+ *	Sets the filter mode and mask by selecting the optional components to
+ *	enable in filter tuples.  Returns 0 on success and a negative error if
+ *	the requested mode needs more bits than are available for optional
+ *	components.  The filter mask must be a subset of the filter mode.
+ */
+int t4_set_filter_cfg(struct adapter *adap, int mode, int mask, int vnic_mode)
+{
+	static const uint8_t width[] = {1, 3, 17, 17, 8, 8, 16, 9, 3, 1};
+	int i, nbits, rc;
+	uint32_t param, val;
+	uint16_t fmode, fmask;
+	const int maxbits = FILTER_OPT_LEN;
+
+	if (mode != -1 || mask != -1) {
+		if (mode != -1) {
+			fmode = mode;
+			nbits = 0;
+			for (i = S_FCOE; i <= S_FRAGMENTATION; i++) {
+				if (fmode & (1 << i))
+					nbits += width[i];
+			}
+			if (nbits > maxbits) {
+				CH_ERR(adap, "optional fields in the filter "
+				    "mode (0x%x) add up to %d bits "
+				    "(must be <= %db).  Remove some fields and "
+				    "try again.\n", fmode, nbits, maxbits);
+				return -E2BIG;
+			}
 
-	int i, nbits = 0;
+			/*
+			 * Hardware wants the bits to be maxed out.  Keep
+			 * setting them until there's no room for more.
+			 */
+			for (i = S_FCOE; i <= S_FRAGMENTATION; i++) {
+				if (fmode & (1 << i))
+					continue;
+				if (nbits + width[i] <= maxbits) {
+					fmode |= 1 << i;
+					nbits += width[i];
+					if (nbits == maxbits)
+						break;
+				}
+			}
 
-	for (i = S_FCOE; i <= S_FRAGMENTATION; i++)
-		if (mode_map & (1 << i))
-			nbits += width[i];
-	if (nbits > FILTER_OPT_LEN)
-		return -EINVAL;
-	t4_tp_pio_write(adap, &mode_map, 1, A_TP_VLAN_PRI_MAP, sleep_ok);
-	read_filter_mode_and_ingress_config(adap, sleep_ok);
+			fmask = fmode & adap->params.tp.filter_mask;
+			if (fmask != adap->params.tp.filter_mask) {
+				CH_WARN(adap,
+				    "filter mask will be changed from 0x%x to "
+				    "0x%x to comply with the filter mode (0x%x).\n",
+				    adap->params.tp.filter_mask, fmask, fmode);
+			}
+		} else {
+			fmode = adap->params.tp.filter_mode;
+			fmask = mask;
+			if ((fmode | fmask) != fmode) {
+				CH_ERR(adap,
+				    "filter mask (0x%x) must be a subset of "
+				    "the filter mode (0x%x).\n", fmask, fmode);
+				return -EINVAL;
+			}
+		}
+
+		param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+		    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_FILTER) |
+		    V_FW_PARAMS_PARAM_Y(FW_PARAM_DEV_FILTER_MODE_MASK);
+		val = V_FW_PARAMS_PARAM_FILTER_MODE(fmode) |
+		    V_FW_PARAMS_PARAM_FILTER_MASK(fmask);
+		rc = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, &param,
+		    &val);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (vnic_mode != -1) {
+		param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+		    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_FILTER) |
+		    V_FW_PARAMS_PARAM_Y(FW_PARAM_DEV_FILTER_VNIC_MODE);
+		val = vnic_mode;
+		rc = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, &param,
+		    &val);
+		if (rc < 0)
+			return rc;
+	}
+
+	/* Refresh. */
+	read_filter_mode_and_ingress_config(adap);
 
 	return 0;
 }
diff --git a/sys/dev/cxgbe/firmware/t4fw_interface.h b/sys/dev/cxgbe/firmware/t4fw_interface.h
index dcec2cc122f2..30a2e1760052 100644
--- a/sys/dev/cxgbe/firmware/t4fw_interface.h
+++ b/sys/dev/cxgbe/firmware/t4fw_interface.h
@@ -4874,6 +4874,11 @@ enum fw_params_param_dev_diag {
 enum fw_params_param_dev_filter{
 	FW_PARAM_DEV_FILTER_VNIC_MODE	= 0x00,
 	FW_PARAM_DEV_FILTER_MODE_MASK	= 0x01,
+
+	/* VNIC modes */
+	FW_VNIC_MODE_PF_VF	= 0,
+	FW_VNIC_MODE_OUTER_VLAN	= 1,
+	FW_VNIC_MODE_ENCAP_EN	= 2,
 };
 
 enum fw_params_param_dev_ktls_hw {
diff --git a/sys/dev/cxgbe/t4_filter.c b/sys/dev/cxgbe/t4_filter.c
index 65a87f4c4163..1e0269fcd5c0 100644
--- a/sys/dev/cxgbe/t4_filter.c
+++ b/sys/dev/cxgbe/t4_filter.c
@@ -231,9 +231,8 @@ filter_eq(struct t4_filter_specification *fs1,
 		return (false);
 
 	/*
-	 * We know the masks are the same because all hashfilter masks have to
-	 * conform to the global tp->hash_filter_mask and the driver has
-	 * verified that already.
+	 * We know the masks are the same because all hashfilters conform to the
+	 * global tp->filter_mask and the driver has verified that already.
 	 */
 
 	if ((fs1->mask.pfvf_vld || fs1->mask.ovlan_vld) &&
@@ -325,7 +324,11 @@ remove_hftid(struct adapter *sc, struct filter_entry *f)
 	LIST_REMOVE(f, link_tid);
 }
 
-static uint32_t
+/*
+ * Input: driver's 32b filter mode.
+ * Returns: hardware filter mode (bits to set in vlan_pri_map) for the input.
+ */
+static uint16_t
 mode_to_fconf(uint32_t mode)
 {
 	uint32_t fconf = 0;
@@ -363,13 +366,22 @@ mode_to_fconf(uint32_t mode)
 	return (fconf);
 }
 
-static uint32_t
+/*
+ * Input: driver's 32b filter mode.
+ * Returns: hardware vnic mode (ingress config) matching the input.
+ */
+static int
 mode_to_iconf(uint32_t mode)
 {
+	if ((mode & T4_FILTER_VNIC) == 0)
+		return (-1);	/* ingress config doesn't matter. */
 
 	if (mode & T4_FILTER_IC_VNIC)
-		return (F_VNIC);
-	return (0);
+		return (FW_VNIC_MODE_PF_VF);
+	else if (mode & T4_FILTER_IC_ENCAP)
+		return (FW_VNIC_MODE_ENCAP_EN);
+	else
+		return (FW_VNIC_MODE_OUTER_VLAN);
 }
 
 static int
@@ -401,16 +413,24 @@ check_fspec_against_fconf_iconf(struct adapter *sc,
 		fconf |= F_VLAN;
 
 	if (fs->val.ovlan_vld || fs->mask.ovlan_vld) {
-		fconf |= F_VNIC_ID;
-		if (tpp->ingress_config & F_VNIC)
+		if (tpp->vnic_mode != FW_VNIC_MODE_OUTER_VLAN)
 			return (EINVAL);
+		fconf |= F_VNIC_ID;
 	}
 
 	if (fs->val.pfvf_vld || fs->mask.pfvf_vld) {
+		if (tpp->vnic_mode != FW_VNIC_MODE_PF_VF)
+			return (EINVAL);
 		fconf |= F_VNIC_ID;
-		if ((tpp->ingress_config & F_VNIC) == 0)
+	}
+
+#ifdef notyet
+	if (fs->val.encap_vld || fs->mask.encap_vld) {
+		if (tpp->vnic_mode != FW_VNIC_MODE_ENCAP_EN);
 			return (EINVAL);
+		fconf |= F_VNIC_ID;
 	}
+#endif
 
 	if (fs->val.iport || fs->mask.iport)
 		fconf |= F_PORT;
@@ -418,46 +438,70 @@ check_fspec_against_fconf_iconf(struct adapter *sc,
 	if (fs->val.fcoe || fs->mask.fcoe)
 		fconf |= F_FCOE;
 
-	if ((tpp->vlan_pri_map | fconf) != tpp->vlan_pri_map)
+	if ((tpp->filter_mode | fconf) != tpp->filter_mode)
 		return (E2BIG);
 
 	return (0);
 }
 
+/*
+ * Input: hardware filter configuration (filter mode/mask, ingress config).
+ * Input: driver's 32b filter mode matching the input.
+ */
+static uint32_t
+fconf_to_mode(uint16_t hwmode, int vnic_mode)
+{
+	uint32_t mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR |
+	    T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT;
+
+	if (hwmode & F_FRAGMENTATION)
+		mode |= T4_FILTER_IP_FRAGMENT;
+	if (hwmode & F_MPSHITTYPE)
+		mode |= T4_FILTER_MPS_HIT_TYPE;
+	if (hwmode & F_MACMATCH)
+		mode |= T4_FILTER_MAC_IDX;
+	if (hwmode & F_ETHERTYPE)
+		mode |= T4_FILTER_ETH_TYPE;
+	if (hwmode & F_PROTOCOL)
+		mode |= T4_FILTER_IP_PROTO;
+	if (hwmode & F_TOS)
+		mode |= T4_FILTER_IP_TOS;
+	if (hwmode & F_VLAN)
+		mode |= T4_FILTER_VLAN;
+	if (hwmode & F_VNIC_ID)
+		mode |= T4_FILTER_VNIC; /* real meaning depends on vnic_mode. */
+	if (hwmode & F_PORT)
+		mode |= T4_FILTER_PORT;
+	if (hwmode & F_FCOE)
+		mode |= T4_FILTER_FCoE;
+
+	switch (vnic_mode) {
+	case FW_VNIC_MODE_PF_VF:
+		mode |= T4_FILTER_IC_VNIC;
+		break;
+	case FW_VNIC_MODE_ENCAP_EN:
+		mode |= T4_FILTER_IC_ENCAP;
+		break;
+	case FW_VNIC_MODE_OUTER_VLAN:
+	default:
+		break;
+	}
+
+	return (mode);
+}
+
 int
 get_filter_mode(struct adapter *sc, uint32_t *mode)
 {
 	struct tp_params *tp = &sc->params.tp;
-	uint64_t mask;
+	uint16_t filter_mode;
 
-	/* Non-zero incoming value in mode means "hashfilter mode". */
-	mask = *mode ? tp->hash_filter_mask : UINT64_MAX;
+	/* Filter mask must comply with the global filter mode. */
+	MPASS((tp->filter_mode | tp->filter_mask) == tp->filter_mode);
 
-	/* Always */
-	*mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR |
-	    T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT;
-
-#define CHECK_FIELD(fconf_bit, field_shift, field_mask, mode_bit)  do { \
-	if (tp->vlan_pri_map & (fconf_bit)) { \
-		MPASS(tp->field_shift >= 0); \
-		if ((mask >> tp->field_shift & field_mask) == field_mask) \
-		*mode |= (mode_bit); \
-	} \
-} while (0)
-
-	CHECK_FIELD(F_FRAGMENTATION, frag_shift, M_FT_FRAGMENTATION, T4_FILTER_IP_FRAGMENT);
-	CHECK_FIELD(F_MPSHITTYPE, matchtype_shift, M_FT_MPSHITTYPE, T4_FILTER_MPS_HIT_TYPE);
-	CHECK_FIELD(F_MACMATCH, macmatch_shift, M_FT_MACMATCH, T4_FILTER_MAC_IDX);
-	CHECK_FIELD(F_ETHERTYPE, ethertype_shift, M_FT_ETHERTYPE, T4_FILTER_ETH_TYPE);
-	CHECK_FIELD(F_PROTOCOL, protocol_shift, M_FT_PROTOCOL, T4_FILTER_IP_PROTO);
-	CHECK_FIELD(F_TOS, tos_shift, M_FT_TOS, T4_FILTER_IP_TOS);
-	CHECK_FIELD(F_VLAN, vlan_shift, M_FT_VLAN, T4_FILTER_VLAN);
-	CHECK_FIELD(F_VNIC_ID, vnic_shift, M_FT_VNIC_ID , T4_FILTER_VNIC);
-	if (tp->ingress_config & F_VNIC)
-		*mode |= T4_FILTER_IC_VNIC;
-	CHECK_FIELD(F_PORT, port_shift, M_FT_PORT , T4_FILTER_PORT);
-	CHECK_FIELD(F_FCOE, fcoe_shift, M_FT_FCOE , T4_FILTER_FCoE);
-#undef CHECK_FIELD
+	/* Non-zero incoming value in mode means "hashfilter mode". */
+	filter_mode = *mode ? tp->filter_mask : tp->filter_mode;
+	*mode = fconf_to_mode(filter_mode, tp->vnic_mode);
 
 	return (0);
 }
@@ -465,33 +509,22 @@ get_filter_mode(struct adapter *sc, uint32_t *mode)
 int
 set_filter_mode(struct adapter *sc, uint32_t mode)
 {
-	struct tp_params *tpp = &sc->params.tp;
-	uint32_t fconf, iconf;
-	int rc;
+	struct tp_params *tp = &sc->params.tp;
+	int rc, iconf;
+	uint16_t fconf;
 
 	iconf = mode_to_iconf(mode);
-	if ((iconf ^ tpp->ingress_config) & F_VNIC) {
-		/*
-		 * For now we just complain if A_TP_INGRESS_CONFIG is not
-		 * already set to the correct value for the requested filter
-		 * mode.  It's not clear if it's safe to write to this register
-		 * on the fly.  (And we trust the cached value of the register).
-		 *
-		 * check_fspec_against_fconf_iconf and other code that looks at
-		 * tp->vlan_pri_map and tp->ingress_config needs to be reviewed
-		 * thorougly before allowing dynamic filter mode changes.
-		 */
-		return (EBUSY);
-	}
-
 	fconf = mode_to_fconf(mode);
+	if ((iconf == -1 || iconf == tp->vnic_mode) && fconf == tp->filter_mode)
+		return (0);	/* Nothing to do */
 
-	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
-	    "t4setfm");
+	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setfm");
 	if (rc)
 		return (rc);
 
-	if (sc->tids.ftids_in_use > 0 || sc->tids.hpftids_in_use > 0) {
+	if (sc->tids.ftids_in_use > 0 ||	/* TCAM filters active */
+	    sc->tids.hpftids_in_use > 0 ||	/* hi-pri TCAM filters active */
+	    sc->tids.tids_in_use > 0) {		/* TOE or hashfilters active */
 		rc = EBUSY;
 		goto done;
 	}
@@ -503,9 +536,10 @@ set_filter_mode(struct adapter *sc, uint32_t mode)
 	}
 #endif
 
-	rc = -t4_set_filter_mode(sc, fconf, true);
+	/* Note that filter mask will get clipped to the new filter mode. */
+	rc = -t4_set_filter_cfg(sc, fconf, -1, iconf);
 done:
-	end_synchronized_op(sc, LOCK_HELD);
+	end_synchronized_op(sc, 0);
 	return (rc);
 }
 
@@ -718,7 +752,7 @@ hashfilter_ntuple(struct adapter *sc, const struct t4_filter_specification *fs,
     uint64_t *ftuple)
 {
 	struct tp_params *tp = &sc->params.tp;
-	uint64_t fmask;
+	uint16_t fmask;
 
 	*ftuple = fmask = 0;
 
@@ -727,63 +761,67 @@ hashfilter_ntuple(struct adapter *sc, const struct t4_filter_specification *fs,
 	 * in the Compressed Filter Tuple.
 	 */
 	if (tp->vlan_shift >= 0 && fs->mask.vlan) {
-		*ftuple |= (F_FT_VLAN_VLD | fs->val.vlan) << tp->vlan_shift;
-		fmask |= M_FT_VLAN << tp->vlan_shift;
+		*ftuple |= (uint64_t)(F_FT_VLAN_VLD | fs->val.vlan) <<
+		    tp->vlan_shift;
+		fmask |= F_VLAN;
 	}
 
 	if (tp->port_shift >= 0 && fs->mask.iport) {
 		*ftuple |= (uint64_t)fs->val.iport << tp->port_shift;
-		fmask |= M_FT_PORT << tp->port_shift;
+		fmask |= F_PORT;
 	}
 
 	if (tp->protocol_shift >= 0 && fs->mask.proto) {
 		*ftuple |= (uint64_t)fs->val.proto << tp->protocol_shift;
-		fmask |= M_FT_PROTOCOL << tp->protocol_shift;
+		fmask |= F_PROTOCOL;
 	}
 
 	if (tp->tos_shift >= 0 && fs->mask.tos) {
 		*ftuple |= (uint64_t)(fs->val.tos) << tp->tos_shift;
-		fmask |= M_FT_TOS << tp->tos_shift;
+		fmask |= F_TOS;
 	}
 
 	if (tp->vnic_shift >= 0 && fs->mask.vnic) {
-		/* F_VNIC in ingress config was already validated. */
-		if (tp->ingress_config & F_VNIC)
+		/* vnic_mode was already validated. */
+		if (tp->vnic_mode == FW_VNIC_MODE_PF_VF)
 			MPASS(fs->mask.pfvf_vld);
-		else
+		else if (tp->vnic_mode == FW_VNIC_MODE_OUTER_VLAN)
 			MPASS(fs->mask.ovlan_vld);
-
+#ifdef notyet
+		else if (tp->vnic_mode == FW_VNIC_MODE_ENCAP_EN)
+			MPASS(fs->mask.encap_vld);
+#endif
 		*ftuple |= ((1ULL << 16) | fs->val.vnic) << tp->vnic_shift;
-		fmask |= M_FT_VNIC_ID << tp->vnic_shift;
+		fmask |= F_VNIC_ID;
 	}
 
 	if (tp->macmatch_shift >= 0 && fs->mask.macidx) {
 		*ftuple |= (uint64_t)(fs->val.macidx) << tp->macmatch_shift;
-		fmask |= M_FT_MACMATCH << tp->macmatch_shift;
+		fmask |= F_MACMATCH;
 	}
 
 	if (tp->ethertype_shift >= 0 && fs->mask.ethtype) {
 		*ftuple |= (uint64_t)(fs->val.ethtype) << tp->ethertype_shift;
-		fmask |= M_FT_ETHERTYPE << tp->ethertype_shift;
+		fmask |= F_ETHERTYPE;
 	}
 
 	if (tp->matchtype_shift >= 0 && fs->mask.matchtype) {
 		*ftuple |= (uint64_t)(fs->val.matchtype) << tp->matchtype_shift;
-		fmask |= M_FT_MPSHITTYPE << tp->matchtype_shift;
+		fmask |= F_MPSHITTYPE;
 	}
 
 	if (tp->frag_shift >= 0 && fs->mask.frag) {
 		*ftuple |= (uint64_t)(fs->val.frag) << tp->frag_shift;
-		fmask |= M_FT_FRAGMENTATION << tp->frag_shift;
+		fmask |= F_FRAGMENTATION;
 	}
 
 	if (tp->fcoe_shift >= 0 && fs->mask.fcoe) {
 		*ftuple |= (uint64_t)(fs->val.fcoe) << tp->fcoe_shift;
-		fmask |= M_FT_FCOE << tp->fcoe_shift;
+		fmask |= F_FCOE;
 	}
 
-	/* A hashfilter must conform to the filterMask. */
-	if (fmask != tp->hash_filter_mask)
+	/* A hashfilter must conform to the hardware filter mask. */
+	if (fmask != tp->filter_mask)
 		return (EINVAL);
 
 	return (0);
diff --git a/sys/dev/cxgbe/t4_ioctl.h b/sys/dev/cxgbe/t4_ioctl.h
index 1daa4f5dfa27..4f0a71683ef0 100644
--- a/sys/dev/cxgbe/t4_ioctl.h
+++ b/sys/dev/cxgbe/t4_ioctl.h
@@ -110,7 +110,7 @@ struct t4_i2c_data {
 #define T4_FILTER_IP_DPORT	0x20	/* Destination IP port */
 #define T4_FILTER_FCoE		0x40	/* Fibre Channel over Ethernet packet */
 #define T4_FILTER_PORT		0x80	/* Physical ingress port */
-#define T4_FILTER_VNIC		0x100	/* VNIC id or outer VLAN */
+#define T4_FILTER_VNIC		0x100	/* See the IC_* bits towards the end */
 #define T4_FILTER_VLAN		0x200	/* VLAN ID */
 #define T4_FILTER_IP_TOS	0x400	/* IPv4 TOS/IPv6 Traffic Class */
 #define T4_FILTER_IP_PROTO	0x800	/* IP protocol */
@@ -118,12 +118,12 @@ struct t4_i2c_data {
 #define T4_FILTER_MAC_IDX	0x2000	/* MPS MAC address match index */
 #define T4_FILTER_MPS_HIT_TYPE	0x4000	/* MPS match type */
 #define T4_FILTER_IP_FRAGMENT	0x8000	/* IP fragment */
-
-#define T4_FILTER_IC_VNIC	0x80000000	/* TP Ingress Config's F_VNIC
-						   bit.  It indicates whether
-						   T4_FILTER_VNIC bit means VNIC
-						   id (PF/VF) or outer VLAN.
-						   0 = oVLAN, 1 = VNIC */
+/*
+ * T4_FILTER_VNIC's real meaning depends on the ingress config.
+ */
+#define T4_FILTER_IC_OVLAN	0		/* outer VLAN */
+#define T4_FILTER_IC_VNIC	0x80000000	/* VNIC id (PF/VF) */
+#define T4_FILTER_IC_ENCAP	0x40000000
 
 /* Filter action */
 enum {
diff --git a/sys/dev/cxgbe/tom/t4_tom.c b/sys/dev/cxgbe/tom/t4_tom.c
index 0f0b4d7ee5b3..df837cc50454 100644
--- a/sys/dev/cxgbe/tom/t4_tom.c
+++ b/sys/dev/cxgbe/tom/t4_tom.c
@@ -1066,7 +1066,7 @@ select_ntuple(struct vi_info *vi, struct l2t_entry *e)
 	if (tp->protocol_shift >= 0)
 		ntuple |= (uint64_t)IPPROTO_TCP << tp->protocol_shift;
 
-	if (tp->vnic_shift >= 0 && tp->ingress_config & F_VNIC) {
+	if (tp->vnic_shift >= 0 && tp->vnic_mode == FW_VNIC_MODE_PF_VF) {
 		ntuple |= (uint64_t)(V_FT_VNID_ID_VF(vi->vin) |
 		    V_FT_VNID_ID_PF(sc->pf) | V_FT_VNID_ID_VLD(vi->vfvld)) <<
 		    tp->vnic_shift;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202102192225.11JMPJhQ093491>