svn commit: r338874 - head/sys/dev/cxgbe

Navdeep Parhar np at FreeBSD.org
Sat Sep 22 01:24:31 UTC 2018


Author: np
Date: Sat Sep 22 01:24:30 2018
New Revision: 338874
URL: https://svnweb.freebsd.org/changeset/base/338874

Log:
  cxgbe(4): Reuse existing "switching" L2T entries when possible.
  
  Approved by:	re@ (rgrimes@)
  Sponsored by:	Chelsio Communications

Modified:
  head/sys/dev/cxgbe/t4_filter.c
  head/sys/dev/cxgbe/t4_l2t.c
  head/sys/dev/cxgbe/t4_l2t.h

Modified: head/sys/dev/cxgbe/t4_filter.c
==============================================================================
--- head/sys/dev/cxgbe/t4_filter.c	Fri Sep 21 23:54:01 2018	(r338873)
+++ head/sys/dev/cxgbe/t4_filter.c	Sat Sep 22 01:24:30 2018	(r338874)
@@ -593,13 +593,8 @@ set_tcamfilter(struct adapter *sc, struct t4_filter *t
 		}
 	}
 	mtx_unlock(&sc->tids.ftid_lock);
-	if (rc != 0) {
-		if (l2te)
-			t4_l2t_release(l2te);
-		if (smt)
-			t4_smt_release(smt);
+	if (rc != 0)
 		return (rc);
-	}
 
 	/*
 	 * Can't fail now.  A set-filter WR will definitely be sent.
@@ -817,8 +812,8 @@ int
 set_filter(struct adapter *sc, struct t4_filter *t)
 {
 	struct tid_info *ti = &sc->tids;
-	struct l2t_entry *l2te;
-	struct smt_entry *smt;
+	struct l2t_entry *l2te = NULL;
+	struct smt_entry *smt = NULL;
 	uint64_t ftuple;
 	int rc;
 
@@ -942,43 +937,41 @@ done:
 	 * Allocate L2T entry, SMT entry, etc.
 	 */
 
-	l2te = NULL;
 	if (t->fs.newdmac || t->fs.newvlan) {
 		/* This filter needs an L2T entry; allocate one. */
-		l2te = t4_l2t_alloc_switching(sc->l2t);
-		if (__predict_false(l2te == NULL))
-			return (EAGAIN);
-		rc = t4_l2t_set_switching(sc, l2te, t->fs.vlan, t->fs.eport,
+		l2te = t4_l2t_alloc_switching(sc, t->fs.vlan, t->fs.eport,
 		    t->fs.dmac);
-		if (rc) {
-			t4_l2t_release(l2te);
-			return (ENOMEM);
+		if (__predict_false(l2te == NULL)) {
+			rc = EAGAIN;
+			goto error;
 		}
 	}
 
-	smt = NULL;
 	if (t->fs.newsmac) {
 		/* This filter needs an SMT entry; allocate one. */
 		smt = t4_smt_alloc_switching(sc->smt, t->fs.smac);
 		if (__predict_false(smt == NULL)) {
-			if (l2te != NULL)
-				t4_l2t_release(l2te);
-			return (EAGAIN);
+			rc = EAGAIN;
+			goto error;
 		}
 		rc = t4_smt_set_switching(sc, smt, 0x0, t->fs.smac);
-		if (rc) {
-			t4_smt_release(smt);
-			if (l2te != NULL)
-				t4_l2t_release(l2te);
-			return (rc);
-		}
+		if (rc)
+			goto error;
 	}
 
 	if (t->fs.hash)
-		return (set_hashfilter(sc, t, ftuple, l2te, smt));
+		rc = set_hashfilter(sc, t, ftuple, l2te, smt);
 	else
-		return (set_tcamfilter(sc, t, l2te, smt));
+		rc = set_tcamfilter(sc, t, l2te, smt);
 
+	if (rc != 0 && rc != EINPROGRESS) {
+error:
+		if (l2te)
+			t4_l2t_release(l2te);
+		if (smt)
+			t4_smt_release(smt);
+	}
+	return (rc);
 }
 
 static int
@@ -1552,10 +1545,6 @@ set_hashfilter(struct adapter *sc, struct t4_filter *t
 
 	f = malloc(sizeof(*f), M_CXGBE, M_ZERO | M_NOWAIT);
 	if (__predict_false(f == NULL)) {
-		if (l2te)
-			t4_l2t_release(l2te);
-		if (smt)
-			t4_smt_release(smt);
 		rc = ENOMEM;
 		goto done;
 	}
@@ -1565,10 +1554,6 @@ set_hashfilter(struct adapter *sc, struct t4_filter *t
 
 	atid = alloc_atid(sc, f);
 	if (__predict_false(atid) == -1) {
-		if (l2te)
-			t4_l2t_release(l2te);
-		if (smt)
-			t4_smt_release(smt);
 		free(f, M_CXGBE);
 		rc = EAGAIN;
 		goto done;
@@ -1579,10 +1564,6 @@ set_hashfilter(struct adapter *sc, struct t4_filter *t
 	    &cookie);
 	if (wr == NULL) {
 		free_atid(sc, atid);
-		if (l2te)
-			t4_l2t_release(l2te);
-		if (smt)
-			t4_smt_release(smt);
 		free(f, M_CXGBE);
 		rc = ENOMEM;
 		goto done;

Modified: head/sys/dev/cxgbe/t4_l2t.c
==============================================================================
--- head/sys/dev/cxgbe/t4_l2t.c	Fri Sep 21 23:54:01 2018	(r338873)
+++ head/sys/dev/cxgbe/t4_l2t.c	Sat Sep 22 01:24:30 2018	(r338874)
@@ -108,6 +108,44 @@ found:
 	return (e);
 }
 
+static struct l2t_entry *
+find_or_alloc_l2e(struct l2t_data *d, uint16_t vlan, uint8_t port, uint8_t *dmac)
+{
+	struct l2t_entry *end, *e, **p;
+	struct l2t_entry *first_free = NULL;
+
+	for (e = &d->l2tab[0], end = &d->l2tab[d->l2t_size]; e != end; ++e) {
+		if (atomic_load_acq_int(&e->refcnt) == 0) {
+			if (!first_free)
+				first_free = e;
+		} else if (e->state == L2T_STATE_SWITCHING &&
+		    memcmp(e->dmac, dmac, ETHER_ADDR_LEN) == 0 &&
+		    e->vlan == vlan && e->lport == port)
+			return (e);	/* Found existing entry that matches. */
+	}
+
+	if (first_free == NULL)
+		return (NULL);	/* No match and no room for a new entry. */
+
+	/*
+	 * The entry we found may be an inactive entry that is
+	 * presently in the hash table.  We need to remove it.
+	 */
+	e = first_free;
+	if (e->state < L2T_STATE_SWITCHING) {
+		for (p = &d->l2tab[e->hash].first; *p; p = &(*p)->next) {
+			if (*p == e) {
+				*p = e->next;
+				e->next = NULL;
+				break;
+			}
+		}
+	}
+	e->state = L2T_STATE_UNUSED;
+	return (e);
+}
+
+
 /*
  * Write an L2T entry.  Must be called with the entry locked.
  * The write may be synchronous or asynchronous.
@@ -154,41 +192,38 @@ t4_write_l2e(struct l2t_entry *e, int sync)
  * address resolution updates do not see them.
  */
 struct l2t_entry *
-t4_l2t_alloc_switching(struct l2t_data *d)
+t4_l2t_alloc_switching(struct adapter *sc, uint16_t vlan, uint8_t port,
+    uint8_t *eth_addr)
 {
+	struct l2t_data *d = sc->l2t;
 	struct l2t_entry *e;
+	int rc;
 
 	rw_wlock(&d->lock);
-	e = t4_alloc_l2e(d);
+	e = find_or_alloc_l2e(d, vlan, port, eth_addr);
 	if (e) {
-		mtx_lock(&e->lock);          /* avoid race with t4_l2t_free */
-		e->state = L2T_STATE_SWITCHING;
-		atomic_store_rel_int(&e->refcnt, 1);
-		mtx_unlock(&e->lock);
+		if (atomic_load_acq_int(&e->refcnt) == 0) {
+			mtx_lock(&e->lock);    /* avoid race with t4_l2t_free */
+			e->wrq = &sc->sge.ctrlq[0];
+			e->iqid = sc->sge.fwq.abs_id;
+			e->state = L2T_STATE_SWITCHING;
+			e->vlan = vlan;
+			e->lport = port;
+			memcpy(e->dmac, eth_addr, ETHER_ADDR_LEN);
+			atomic_store_rel_int(&e->refcnt, 1);
+			atomic_subtract_int(&d->nfree, 1);
+			rc = t4_write_l2e(e, 0);
+			mtx_unlock(&e->lock);
+			if (rc != 0)
+				e = NULL;
+		} else {
+			MPASS(e->vlan == vlan);
+			MPASS(e->lport == port);
+			atomic_add_int(&e->refcnt, 1);
+		}
 	}
 	rw_wunlock(&d->lock);
-	return e;
-}
-
-/*
- * Sets/updates the contents of a switching L2T entry that has been allocated
- * with an earlier call to @t4_l2t_alloc_switching.
- */
-int
-t4_l2t_set_switching(struct adapter *sc, struct l2t_entry *e, uint16_t vlan,
-    uint8_t port, uint8_t *eth_addr)
-{
-	int rc;
-
-	e->vlan = vlan;
-	e->lport = port;
-	e->wrq = &sc->sge.ctrlq[0];
-	e->iqid = sc->sge.fwq.abs_id;
-	memcpy(e->dmac, eth_addr, ETHER_ADDR_LEN);
-	mtx_lock(&e->lock);
-	rc = t4_write_l2e(e, 0);
-	mtx_unlock(&e->lock);
-	return (rc);
+	return (e);
 }
 
 int

Modified: head/sys/dev/cxgbe/t4_l2t.h
==============================================================================
--- head/sys/dev/cxgbe/t4_l2t.h	Fri Sep 21 23:54:01 2018	(r338873)
+++ head/sys/dev/cxgbe/t4_l2t.h	Sat Sep 22 01:24:30 2018	(r338874)
@@ -91,7 +91,8 @@ struct l2t_data {
 int t4_init_l2t(struct adapter *, int);
 int t4_free_l2t(struct l2t_data *);
 struct l2t_entry *t4_alloc_l2e(struct l2t_data *);
-struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *);
+struct l2t_entry *t4_l2t_alloc_switching(struct adapter *, uint16_t, uint8_t,
+    uint8_t *);
 int t4_l2t_set_switching(struct adapter *, struct l2t_entry *, uint16_t,
     uint8_t, uint8_t *);
 int t4_write_l2e(struct l2t_entry *, int);


More information about the svn-src-all mailing list