svn commit: r333153 - in head/sys: conf dev/cxgbe modules/cxgbe/if_cxgbe

Navdeep Parhar np at FreeBSD.org
Tue May 1 20:17:24 UTC 2018


Author: np
Date: Tue May  1 20:17:22 2018
New Revision: 333153
URL: https://svnweb.freebsd.org/changeset/base/333153

Log:
  cxgbe(4): Move all TCAM filter code into a separate file.
  
  Sponsored by:	Chelsio Communications

Added:
  head/sys/dev/cxgbe/t4_filter.c   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/dev/cxgbe/adapter.h
  head/sys/dev/cxgbe/t4_main.c
  head/sys/modules/cxgbe/if_cxgbe/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Tue May  1 20:09:29 2018	(r333152)
+++ head/sys/conf/files	Tue May  1 20:17:22 2018	(r333153)
@@ -1394,6 +1394,8 @@ dev/cxgb/sys/uipc_mvec.c	optional cxgb pci \
 	compile-with "${NORMAL_C} -I$S/dev/cxgb"
 dev/cxgb/cxgb_t3fw.c		optional cxgb cxgb_t3fw \
 	compile-with "${NORMAL_C} -I$S/dev/cxgb"
+dev/cxgbe/t4_filter.c		optional cxgbe pci \
+	compile-with "${NORMAL_C} -I$S/dev/cxgbe"
 dev/cxgbe/t4_if.m		optional cxgbe pci
 dev/cxgbe/t4_iov.c		optional cxgbe pci \
 	compile-with "${NORMAL_C} -I$S/dev/cxgbe"

Modified: head/sys/dev/cxgbe/adapter.h
==============================================================================
--- head/sys/dev/cxgbe/adapter.h	Tue May  1 20:09:29 2018	(r333152)
+++ head/sys/dev/cxgbe/adapter.h	Tue May  1 20:17:22 2018	(r333153)
@@ -1158,7 +1158,6 @@ void t4_init_devnames(struct adapter *);
 void t4_add_adapter(struct adapter *);
 void t4_aes_getdeckey(void *, const void *, unsigned int);
 int t4_detach_common(device_t);
-int t4_filter_rpl(struct sge_iq *, const struct rss_header *, struct mbuf *);
 int t4_map_bars_0_and_4(struct adapter *);
 int t4_map_bar_2(struct adapter *);
 int t4_setup_intr_handlers(struct adapter *);
@@ -1237,6 +1236,14 @@ int t4_free_tx_sched(struct adapter *);
 void t4_update_tx_sched(struct adapter *);
 int t4_reserve_cl_rl_kbps(struct adapter *, int, u_int, int *);
 void t4_release_cl_rl_kbps(struct adapter *, int, int);
+
+/* t4_filter.c */
+int get_filter_mode(struct adapter *, uint32_t *);
+int set_filter_mode(struct adapter *, uint32_t);
+int get_filter(struct adapter *, struct t4_filter *);
+int set_filter(struct adapter *, struct t4_filter *);
+int del_filter(struct adapter *, struct t4_filter *);
+int t4_filter_rpl(struct sge_iq *, const struct rss_header *, struct mbuf *);
 
 static inline struct wrqe *
 alloc_wrqe(int wr_len, struct sge_wrq *wrq)

Added: head/sys/dev/cxgbe/t4_filter.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/cxgbe/t4_filter.c	Tue May  1 20:17:22 2018	(r333153)
@@ -0,0 +1,686 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Chelsio Communications, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/socket.h>
+#include <sys/sbuf.h>
+#include <netinet/in.h>
+
+#include "common/common.h"
+#include "common/t4_msg.h"
+#include "common/t4_regs.h"
+#include "t4_l2t.h"
+
+struct filter_entry {
+        uint32_t valid:1;	/* filter allocated and valid */
+        uint32_t locked:1;	/* filter is administratively locked */
+        uint32_t pending:1;	/* filter action is pending firmware reply */
+	uint32_t smtidx:8;	/* Source MAC Table index for smac */
+	struct l2t_entry *l2t;	/* Layer Two Table entry for dmac */
+
+        struct t4_filter_specification fs;
+};
+
+static uint32_t
+fconf_iconf_to_mode(uint32_t fconf, uint32_t iconf)
+{
+	uint32_t mode;
+
+	mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR |
+	    T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT;
+
+	if (fconf & F_FRAGMENTATION)
+		mode |= T4_FILTER_IP_FRAGMENT;
+
+	if (fconf & F_MPSHITTYPE)
+		mode |= T4_FILTER_MPS_HIT_TYPE;
+
+	if (fconf & F_MACMATCH)
+		mode |= T4_FILTER_MAC_IDX;
+
+	if (fconf & F_ETHERTYPE)
+		mode |= T4_FILTER_ETH_TYPE;
+
+	if (fconf & F_PROTOCOL)
+		mode |= T4_FILTER_IP_PROTO;
+
+	if (fconf & F_TOS)
+		mode |= T4_FILTER_IP_TOS;
+
+	if (fconf & F_VLAN)
+		mode |= T4_FILTER_VLAN;
+
+	if (fconf & F_VNIC_ID) {
+		mode |= T4_FILTER_VNIC;
+		if (iconf & F_VNIC)
+			mode |= T4_FILTER_IC_VNIC;
+	}
+
+	if (fconf & F_PORT)
+		mode |= T4_FILTER_PORT;
+
+	if (fconf & F_FCOE)
+		mode |= T4_FILTER_FCoE;
+
+	return (mode);
+}
+
+static uint32_t
+mode_to_fconf(uint32_t mode)
+{
+	uint32_t fconf = 0;
+
+	if (mode & T4_FILTER_IP_FRAGMENT)
+		fconf |= F_FRAGMENTATION;
+
+	if (mode & T4_FILTER_MPS_HIT_TYPE)
+		fconf |= F_MPSHITTYPE;
+
+	if (mode & T4_FILTER_MAC_IDX)
+		fconf |= F_MACMATCH;
+
+	if (mode & T4_FILTER_ETH_TYPE)
+		fconf |= F_ETHERTYPE;
+
+	if (mode & T4_FILTER_IP_PROTO)
+		fconf |= F_PROTOCOL;
+
+	if (mode & T4_FILTER_IP_TOS)
+		fconf |= F_TOS;
+
+	if (mode & T4_FILTER_VLAN)
+		fconf |= F_VLAN;
+
+	if (mode & T4_FILTER_VNIC)
+		fconf |= F_VNIC_ID;
+
+	if (mode & T4_FILTER_PORT)
+		fconf |= F_PORT;
+
+	if (mode & T4_FILTER_FCoE)
+		fconf |= F_FCOE;
+
+	return (fconf);
+}
+
+static uint32_t
+mode_to_iconf(uint32_t mode)
+{
+
+	if (mode & T4_FILTER_IC_VNIC)
+		return (F_VNIC);
+	return (0);
+}
+
+static int check_fspec_against_fconf_iconf(struct adapter *sc,
+    struct t4_filter_specification *fs)
+{
+	struct tp_params *tpp = &sc->params.tp;
+	uint32_t fconf = 0;
+
+	if (fs->val.frag || fs->mask.frag)
+		fconf |= F_FRAGMENTATION;
+
+	if (fs->val.matchtype || fs->mask.matchtype)
+		fconf |= F_MPSHITTYPE;
+
+	if (fs->val.macidx || fs->mask.macidx)
+		fconf |= F_MACMATCH;
+
+	if (fs->val.ethtype || fs->mask.ethtype)
+		fconf |= F_ETHERTYPE;
+
+	if (fs->val.proto || fs->mask.proto)
+		fconf |= F_PROTOCOL;
+
+	if (fs->val.tos || fs->mask.tos)
+		fconf |= F_TOS;
+
+	if (fs->val.vlan_vld || fs->mask.vlan_vld)
+		fconf |= F_VLAN;
+
+	if (fs->val.ovlan_vld || fs->mask.ovlan_vld) {
+		fconf |= F_VNIC_ID;
+		if (tpp->ingress_config & F_VNIC)
+			return (EINVAL);
+	}
+
+	if (fs->val.pfvf_vld || fs->mask.pfvf_vld) {
+		fconf |= F_VNIC_ID;
+		if ((tpp->ingress_config & F_VNIC) == 0)
+			return (EINVAL);
+	}
+
+	if (fs->val.iport || fs->mask.iport)
+		fconf |= F_PORT;
+
+	if (fs->val.fcoe || fs->mask.fcoe)
+		fconf |= F_FCOE;
+
+	if ((tpp->vlan_pri_map | fconf) != tpp->vlan_pri_map)
+		return (E2BIG);
+
+	return (0);
+}
+
+int
+get_filter_mode(struct adapter *sc, uint32_t *mode)
+{
+	struct tp_params *tpp = &sc->params.tp;
+
+	/*
+	 * We trust the cached values of the relevant TP registers.  This means
+	 * things work reliably only if writes to those registers are always via
+	 * t4_set_filter_mode_.
+	 */
+	*mode = fconf_iconf_to_mode(tpp->vlan_pri_map, tpp->ingress_config);
+
+	return (0);
+}
+
+int
+set_filter_mode(struct adapter *sc, uint32_t mode)
+{
+	struct tp_params *tpp = &sc->params.tp;
+	uint32_t fconf, iconf;
+	int rc;
+
+	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).
+		 */
+		return (EBUSY);
+	}
+
+	fconf = mode_to_fconf(mode);
+
+	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
+	    "t4setfm");
+	if (rc)
+		return (rc);
+
+	if (sc->tids.ftids_in_use > 0) {
+		rc = EBUSY;
+		goto done;
+	}
+
+#ifdef TCP_OFFLOAD
+	if (uld_active(sc, ULD_TOM)) {
+		rc = EBUSY;
+		goto done;
+	}
+#endif
+
+	rc = -t4_set_filter_mode(sc, fconf, true);
+done:
+	end_synchronized_op(sc, LOCK_HELD);
+	return (rc);
+}
+
+static inline uint64_t
+get_filter_hits(struct adapter *sc, uint32_t fid)
+{
+	uint32_t tcb_addr;
+
+	tcb_addr = t4_read_reg(sc, A_TP_CMM_TCB_BASE) +
+	    (fid + sc->tids.ftid_base) * TCB_SIZE;
+
+	if (is_t4(sc)) {
+		uint64_t hits;
+
+		read_via_memwin(sc, 0, tcb_addr + 16, (uint32_t *)&hits, 8);
+		return (be64toh(hits));
+	} else {
+		uint32_t hits;
+
+		read_via_memwin(sc, 0, tcb_addr + 24, &hits, 4);
+		return (be32toh(hits));
+	}
+}
+
+int
+get_filter(struct adapter *sc, struct t4_filter *t)
+{
+	int i, rc, nfilters = sc->tids.nftids;
+	struct filter_entry *f;
+
+	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
+	    "t4getf");
+	if (rc)
+		return (rc);
+
+	if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL ||
+	    t->idx >= nfilters) {
+		t->idx = 0xffffffff;
+		goto done;
+	}
+
+	f = &sc->tids.ftid_tab[t->idx];
+	for (i = t->idx; i < nfilters; i++, f++) {
+		if (f->valid) {
+			t->idx = i;
+			t->l2tidx = f->l2t ? f->l2t->idx : 0;
+			t->smtidx = f->smtidx;
+			if (f->fs.hitcnts)
+				t->hits = get_filter_hits(sc, t->idx);
+			else
+				t->hits = UINT64_MAX;
+			t->fs = f->fs;
+
+			goto done;
+		}
+	}
+
+	t->idx = 0xffffffff;
+done:
+	end_synchronized_op(sc, LOCK_HELD);
+	return (0);
+}
+
+static int
+set_filter_wr(struct adapter *sc, int fidx)
+{
+	struct filter_entry *f = &sc->tids.ftid_tab[fidx];
+	struct fw_filter_wr *fwr;
+	unsigned int ftid, vnic_vld, vnic_vld_mask;
+	struct wrq_cookie cookie;
+
+	ASSERT_SYNCHRONIZED_OP(sc);
+
+	if (f->fs.newdmac || f->fs.newvlan) {
+		/* This filter needs an L2T entry; allocate one. */
+		f->l2t = t4_l2t_alloc_switching(sc->l2t);
+		if (f->l2t == NULL)
+			return (EAGAIN);
+		if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport,
+		    f->fs.dmac)) {
+			t4_l2t_release(f->l2t);
+			f->l2t = NULL;
+			return (ENOMEM);
+		}
+	}
+
+	/* Already validated against fconf, iconf */
+	MPASS((f->fs.val.pfvf_vld & f->fs.val.ovlan_vld) == 0);
+	MPASS((f->fs.mask.pfvf_vld & f->fs.mask.ovlan_vld) == 0);
+	if (f->fs.val.pfvf_vld || f->fs.val.ovlan_vld)
+		vnic_vld = 1;
+	else
+		vnic_vld = 0;
+	if (f->fs.mask.pfvf_vld || f->fs.mask.ovlan_vld)
+		vnic_vld_mask = 1;
+	else
+		vnic_vld_mask = 0;
+
+	ftid = sc->tids.ftid_base + fidx;
+
+	fwr = start_wrq_wr(&sc->sge.mgmtq, howmany(sizeof(*fwr), 16), &cookie);
+	if (fwr == NULL)
+		return (ENOMEM);
+	bzero(fwr, sizeof(*fwr));
+
+	fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR));
+	fwr->len16_pkd = htobe32(FW_LEN16(*fwr));
+	fwr->tid_to_iq =
+	    htobe32(V_FW_FILTER_WR_TID(ftid) |
+		V_FW_FILTER_WR_RQTYPE(f->fs.type) |
+		V_FW_FILTER_WR_NOREPLY(0) |
+		V_FW_FILTER_WR_IQ(f->fs.iq));
+	fwr->del_filter_to_l2tix =
+	    htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) |
+		V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) |
+		V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) |
+		V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) |
+		V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) |
+		V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) |
+		V_FW_FILTER_WR_DMAC(f->fs.newdmac) |
+		V_FW_FILTER_WR_SMAC(f->fs.newsmac) |
+		V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT ||
+		    f->fs.newvlan == VLAN_REWRITE) |
+		V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE ||
+		    f->fs.newvlan == VLAN_REWRITE) |
+		V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) |
+		V_FW_FILTER_WR_TXCHAN(f->fs.eport) |
+		V_FW_FILTER_WR_PRIO(f->fs.prio) |
+		V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0));
+	fwr->ethtype = htobe16(f->fs.val.ethtype);
+	fwr->ethtypem = htobe16(f->fs.mask.ethtype);
+	fwr->frag_to_ovlan_vldm =
+	    (V_FW_FILTER_WR_FRAG(f->fs.val.frag) |
+		V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) |
+		V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) |
+		V_FW_FILTER_WR_OVLAN_VLD(vnic_vld) |
+		V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) |
+		V_FW_FILTER_WR_OVLAN_VLDM(vnic_vld_mask));
+	fwr->smac_sel = 0;
+	fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) |
+	    V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id));
+	fwr->maci_to_matchtypem =
+	    htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) |
+		V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) |
+		V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) |
+		V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) |
+		V_FW_FILTER_WR_PORT(f->fs.val.iport) |
+		V_FW_FILTER_WR_PORTM(f->fs.mask.iport) |
+		V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) |
+		V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype));
+	fwr->ptcl = f->fs.val.proto;
+	fwr->ptclm = f->fs.mask.proto;
+	fwr->ttyp = f->fs.val.tos;
+	fwr->ttypm = f->fs.mask.tos;
+	fwr->ivlan = htobe16(f->fs.val.vlan);
+	fwr->ivlanm = htobe16(f->fs.mask.vlan);
+	fwr->ovlan = htobe16(f->fs.val.vnic);
+	fwr->ovlanm = htobe16(f->fs.mask.vnic);
+	bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip));
+	bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm));
+	bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip));
+	bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm));
+	fwr->lp = htobe16(f->fs.val.dport);
+	fwr->lpm = htobe16(f->fs.mask.dport);
+	fwr->fp = htobe16(f->fs.val.sport);
+	fwr->fpm = htobe16(f->fs.mask.sport);
+	if (f->fs.newsmac)
+		bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma));
+
+	f->pending = 1;
+	sc->tids.ftids_in_use++;
+
+	commit_wrq_wr(&sc->sge.mgmtq, fwr, &cookie);
+	return (0);
+}
+
+int
+set_filter(struct adapter *sc, struct t4_filter *t)
+{
+	unsigned int nfilters, nports;
+	struct filter_entry *f;
+	int i, rc;
+
+	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setf");
+	if (rc)
+		return (rc);
+
+	nfilters = sc->tids.nftids;
+	nports = sc->params.nports;
+
+	if (nfilters == 0) {
+		rc = ENOTSUP;
+		goto done;
+	}
+
+	if (t->idx >= nfilters) {
+		rc = EINVAL;
+		goto done;
+	}
+
+	/* Validate against the global filter mode and ingress config */
+	rc = check_fspec_against_fconf_iconf(sc, &t->fs);
+	if (rc != 0)
+		goto done;
+
+	if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) {
+		rc = EINVAL;
+		goto done;
+	}
+
+	if (t->fs.val.iport >= nports) {
+		rc = EINVAL;
+		goto done;
+	}
+
+	/* Can't specify an iq if not steering to it */
+	if (!t->fs.dirsteer && t->fs.iq) {
+		rc = EINVAL;
+		goto done;
+	}
+
+	/* IPv6 filter idx must be 4 aligned */
+	if (t->fs.type == 1 &&
+	    ((t->idx & 0x3) || t->idx + 4 >= nfilters)) {
+		rc = EINVAL;
+		goto done;
+	}
+
+	if (!(sc->flags & FULL_INIT_DONE) &&
+	    ((rc = adapter_full_init(sc)) != 0))
+		goto done;
+
+	if (sc->tids.ftid_tab == NULL) {
+		KASSERT(sc->tids.ftids_in_use == 0,
+		    ("%s: no memory allocated but filters_in_use > 0",
+		    __func__));
+
+		sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) *
+		    nfilters, M_CXGBE, M_NOWAIT | M_ZERO);
+		if (sc->tids.ftid_tab == NULL) {
+			rc = ENOMEM;
+			goto done;
+		}
+		mtx_init(&sc->tids.ftid_lock, "T4 filters", 0, MTX_DEF);
+	}
+
+	for (i = 0; i < 4; i++) {
+		f = &sc->tids.ftid_tab[t->idx + i];
+
+		if (f->pending || f->valid) {
+			rc = EBUSY;
+			goto done;
+		}
+		if (f->locked) {
+			rc = EPERM;
+			goto done;
+		}
+
+		if (t->fs.type == 0)
+			break;
+	}
+
+	f = &sc->tids.ftid_tab[t->idx];
+	f->fs = t->fs;
+
+	rc = set_filter_wr(sc, t->idx);
+done:
+	end_synchronized_op(sc, 0);
+
+	if (rc == 0) {
+		mtx_lock(&sc->tids.ftid_lock);
+		for (;;) {
+			if (f->pending == 0) {
+				rc = f->valid ? 0 : EIO;
+				break;
+			}
+
+			if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock,
+			    PCATCH, "t4setfw", 0)) {
+				rc = EINPROGRESS;
+				break;
+			}
+		}
+		mtx_unlock(&sc->tids.ftid_lock);
+	}
+	return (rc);
+}
+
+static int
+del_filter_wr(struct adapter *sc, int fidx)
+{
+	struct filter_entry *f = &sc->tids.ftid_tab[fidx];
+	struct fw_filter_wr *fwr;
+	unsigned int ftid;
+	struct wrq_cookie cookie;
+
+	ftid = sc->tids.ftid_base + fidx;
+
+	fwr = start_wrq_wr(&sc->sge.mgmtq, howmany(sizeof(*fwr), 16), &cookie);
+	if (fwr == NULL)
+		return (ENOMEM);
+	bzero(fwr, sizeof (*fwr));
+
+	t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id);
+
+	f->pending = 1;
+	commit_wrq_wr(&sc->sge.mgmtq, fwr, &cookie);
+	return (0);
+}
+
+int
+del_filter(struct adapter *sc, struct t4_filter *t)
+{
+	unsigned int nfilters;
+	struct filter_entry *f;
+	int rc;
+
+	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4delf");
+	if (rc)
+		return (rc);
+
+	nfilters = sc->tids.nftids;
+
+	if (nfilters == 0) {
+		rc = ENOTSUP;
+		goto done;
+	}
+
+	if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 ||
+	    t->idx >= nfilters) {
+		rc = EINVAL;
+		goto done;
+	}
+
+	if (!(sc->flags & FULL_INIT_DONE)) {
+		rc = EAGAIN;
+		goto done;
+	}
+
+	f = &sc->tids.ftid_tab[t->idx];
+
+	if (f->pending) {
+		rc = EBUSY;
+		goto done;
+	}
+	if (f->locked) {
+		rc = EPERM;
+		goto done;
+	}
+
+	if (f->valid) {
+		t->fs = f->fs;	/* extra info for the caller */
+		rc = del_filter_wr(sc, t->idx);
+	}
+
+done:
+	end_synchronized_op(sc, 0);
+
+	if (rc == 0) {
+		mtx_lock(&sc->tids.ftid_lock);
+		for (;;) {
+			if (f->pending == 0) {
+				rc = f->valid ? EIO : 0;
+				break;
+			}
+
+			if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock,
+			    PCATCH, "t4delfw", 0)) {
+				rc = EINPROGRESS;
+				break;
+			}
+		}
+		mtx_unlock(&sc->tids.ftid_lock);
+	}
+
+	return (rc);
+}
+
+static void
+clear_filter(struct filter_entry *f)
+{
+	if (f->l2t)
+		t4_l2t_release(f->l2t);
+
+	bzero(f, sizeof (*f));
+}
+
+int
+t4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
+{
+	struct adapter *sc = iq->adapter;
+	const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1);
+	unsigned int idx = GET_TID(rpl);
+	unsigned int rc;
+	struct filter_entry *f;
+
+	KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__,
+	    rss->opcode));
+	MPASS(iq == &sc->sge.fwq);
+	MPASS(is_ftid(sc, idx));
+
+	idx -= sc->tids.ftid_base;
+	f = &sc->tids.ftid_tab[idx];
+	rc = G_COOKIE(rpl->cookie);
+
+	mtx_lock(&sc->tids.ftid_lock);
+	if (rc == FW_FILTER_WR_FLT_ADDED) {
+		KASSERT(f->pending, ("%s: filter[%u] isn't pending.",
+		    __func__, idx));
+		f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff;
+		f->pending = 0;  /* asynchronous setup completed */
+		f->valid = 1;
+	} else {
+		if (rc != FW_FILTER_WR_FLT_DELETED) {
+			/* Add or delete failed, display an error */
+			log(LOG_ERR,
+			    "filter %u setup failed with error %u\n",
+			    idx, rc);
+		}
+
+		clear_filter(f);
+		sc->tids.ftids_in_use--;
+	}
+	wakeup(&sc->tids.ftid_tab);
+	mtx_unlock(&sc->tids.ftid_lock);
+
+	return (0);
+}

Modified: head/sys/dev/cxgbe/t4_main.c
==============================================================================
--- head/sys/dev/cxgbe/t4_main.c	Tue May  1 20:09:29 2018	(r333152)
+++ head/sys/dev/cxgbe/t4_main.c	Tue May  1 20:17:22 2018	(r333153)
@@ -509,16 +509,6 @@ struct intrs_and_queues {
 	uint16_t nnmrxq_vi;	/* # of netmap rxq's */
 };
 
-struct filter_entry {
-        uint32_t valid:1;	/* filter allocated and valid */
-        uint32_t locked:1;	/* filter is administratively locked */
-        uint32_t pending:1;	/* filter action is pending firmware reply */
-	uint32_t smtidx:8;	/* Source MAC Table index for smac */
-	struct l2t_entry *l2t;	/* Layer Two Table entry for dmac */
-
-        struct t4_filter_specification fs;
-};
-
 static void setup_memwin(struct adapter *);
 static void position_memwin(struct adapter *, int, uint32_t);
 static int validate_mem_range(struct adapter *, uint32_t, int);
@@ -605,20 +595,6 @@ static int sysctl_tp_backoff(SYSCTL_HANDLER_ARGS);
 static int sysctl_holdoff_tmr_idx_ofld(SYSCTL_HANDLER_ARGS);
 static int sysctl_holdoff_pktc_idx_ofld(SYSCTL_HANDLER_ARGS);
 #endif
-static uint32_t fconf_iconf_to_mode(uint32_t, uint32_t);
-static uint32_t mode_to_fconf(uint32_t);
-static uint32_t mode_to_iconf(uint32_t);
-static int check_fspec_against_fconf_iconf(struct adapter *,
-    struct t4_filter_specification *);
-static int get_filter_mode(struct adapter *, uint32_t *);
-static int set_filter_mode(struct adapter *, uint32_t);
-static inline uint64_t get_filter_hits(struct adapter *, uint32_t);
-static int get_filter(struct adapter *, struct t4_filter *);
-static int set_filter(struct adapter *, struct t4_filter *);
-static int del_filter(struct adapter *, struct t4_filter *);
-static void clear_filter(struct filter_entry *);
-static int set_filter_wr(struct adapter *, int);
-static int del_filter_wr(struct adapter *, int);
 static int get_sge_context(struct adapter *, struct t4_sge_context *);
 static int load_fw(struct adapter *, struct t4_data *);
 static int load_cfg(struct adapter *, struct t4_data *);
@@ -8645,632 +8621,6 @@ sysctl_holdoff_pktc_idx_ofld(SYSCTL_HANDLER_ARGS)
 	return (rc);
 }
 #endif
-
-static uint32_t
-fconf_iconf_to_mode(uint32_t fconf, uint32_t iconf)
-{
-	uint32_t mode;
-
-	mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR |
-	    T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT;
-
-	if (fconf & F_FRAGMENTATION)
-		mode |= T4_FILTER_IP_FRAGMENT;
-
-	if (fconf & F_MPSHITTYPE)
-		mode |= T4_FILTER_MPS_HIT_TYPE;
-
-	if (fconf & F_MACMATCH)
-		mode |= T4_FILTER_MAC_IDX;
-
-	if (fconf & F_ETHERTYPE)
-		mode |= T4_FILTER_ETH_TYPE;
-
-	if (fconf & F_PROTOCOL)
-		mode |= T4_FILTER_IP_PROTO;
-
-	if (fconf & F_TOS)
-		mode |= T4_FILTER_IP_TOS;
-
-	if (fconf & F_VLAN)
-		mode |= T4_FILTER_VLAN;
-
-	if (fconf & F_VNIC_ID) {
-		mode |= T4_FILTER_VNIC;
-		if (iconf & F_VNIC)
-			mode |= T4_FILTER_IC_VNIC;
-	}
-
-	if (fconf & F_PORT)
-		mode |= T4_FILTER_PORT;
-
-	if (fconf & F_FCOE)
-		mode |= T4_FILTER_FCoE;
-
-	return (mode);
-}
-
-static uint32_t
-mode_to_fconf(uint32_t mode)
-{
-	uint32_t fconf = 0;
-
-	if (mode & T4_FILTER_IP_FRAGMENT)
-		fconf |= F_FRAGMENTATION;
-
-	if (mode & T4_FILTER_MPS_HIT_TYPE)
-		fconf |= F_MPSHITTYPE;
-
-	if (mode & T4_FILTER_MAC_IDX)
-		fconf |= F_MACMATCH;
-
-	if (mode & T4_FILTER_ETH_TYPE)
-		fconf |= F_ETHERTYPE;
-
-	if (mode & T4_FILTER_IP_PROTO)
-		fconf |= F_PROTOCOL;
-
-	if (mode & T4_FILTER_IP_TOS)
-		fconf |= F_TOS;
-
-	if (mode & T4_FILTER_VLAN)
-		fconf |= F_VLAN;
-
-	if (mode & T4_FILTER_VNIC)
-		fconf |= F_VNIC_ID;
-
-	if (mode & T4_FILTER_PORT)
-		fconf |= F_PORT;
-
-	if (mode & T4_FILTER_FCoE)
-		fconf |= F_FCOE;
-
-	return (fconf);
-}
-
-static uint32_t
-mode_to_iconf(uint32_t mode)
-{
-
-	if (mode & T4_FILTER_IC_VNIC)
-		return (F_VNIC);
-	return (0);
-}
-
-static int check_fspec_against_fconf_iconf(struct adapter *sc,
-    struct t4_filter_specification *fs)
-{
-	struct tp_params *tpp = &sc->params.tp;
-	uint32_t fconf = 0;
-
-	if (fs->val.frag || fs->mask.frag)
-		fconf |= F_FRAGMENTATION;
-
-	if (fs->val.matchtype || fs->mask.matchtype)
-		fconf |= F_MPSHITTYPE;
-
-	if (fs->val.macidx || fs->mask.macidx)
-		fconf |= F_MACMATCH;
-
-	if (fs->val.ethtype || fs->mask.ethtype)
-		fconf |= F_ETHERTYPE;
-
-	if (fs->val.proto || fs->mask.proto)
-		fconf |= F_PROTOCOL;
-
-	if (fs->val.tos || fs->mask.tos)
-		fconf |= F_TOS;
-
-	if (fs->val.vlan_vld || fs->mask.vlan_vld)
-		fconf |= F_VLAN;
-
-	if (fs->val.ovlan_vld || fs->mask.ovlan_vld) {
-		fconf |= F_VNIC_ID;
-		if (tpp->ingress_config & F_VNIC)
-			return (EINVAL);
-	}
-
-	if (fs->val.pfvf_vld || fs->mask.pfvf_vld) {
-		fconf |= F_VNIC_ID;
-		if ((tpp->ingress_config & F_VNIC) == 0)
-			return (EINVAL);
-	}
-
-	if (fs->val.iport || fs->mask.iport)
-		fconf |= F_PORT;
-
-	if (fs->val.fcoe || fs->mask.fcoe)
-		fconf |= F_FCOE;
-
-	if ((tpp->vlan_pri_map | fconf) != tpp->vlan_pri_map)
-		return (E2BIG);
-
-	return (0);
-}
-
-static int
-get_filter_mode(struct adapter *sc, uint32_t *mode)
-{
-	struct tp_params *tpp = &sc->params.tp;
-
-	/*
-	 * We trust the cached values of the relevant TP registers.  This means
-	 * things work reliably only if writes to those registers are always via
-	 * t4_set_filter_mode.
-	 */
-	*mode = fconf_iconf_to_mode(tpp->vlan_pri_map, tpp->ingress_config);
-
-	return (0);
-}
-
-static int
-set_filter_mode(struct adapter *sc, uint32_t mode)
-{
-	struct tp_params *tpp = &sc->params.tp;
-	uint32_t fconf, iconf;
-	int rc;
-
-	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).
-		 */
-		return (EBUSY);
-	}
-
-	fconf = mode_to_fconf(mode);
-
-	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
-	    "t4setfm");
-	if (rc)
-		return (rc);
-
-	if (sc->tids.ftids_in_use > 0) {
-		rc = EBUSY;
-		goto done;
-	}
-
-#ifdef TCP_OFFLOAD
-	if (uld_active(sc, ULD_TOM)) {
-		rc = EBUSY;
-		goto done;
-	}
-#endif
-
-	rc = -t4_set_filter_mode(sc, fconf, true);
-done:
-	end_synchronized_op(sc, LOCK_HELD);
-	return (rc);
-}
-
-static inline uint64_t
-get_filter_hits(struct adapter *sc, uint32_t fid)
-{
-	uint32_t tcb_addr;
-
-	tcb_addr = t4_read_reg(sc, A_TP_CMM_TCB_BASE) +
-	    (fid + sc->tids.ftid_base) * TCB_SIZE;
-
-	if (is_t4(sc)) {
-		uint64_t hits;
-
-		read_via_memwin(sc, 0, tcb_addr + 16, (uint32_t *)&hits, 8);
-		return (be64toh(hits));
-	} else {
-		uint32_t hits;
-
-		read_via_memwin(sc, 0, tcb_addr + 24, &hits, 4);
-		return (be32toh(hits));
-	}
-}
-
-static int
-get_filter(struct adapter *sc, struct t4_filter *t)
-{
-	int i, rc, nfilters = sc->tids.nftids;
-	struct filter_entry *f;
-
-	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
-	    "t4getf");
-	if (rc)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list