109fe6320SNavdeep Parhar /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 409fe6320SNavdeep Parhar * Copyright (c) 2012 Chelsio Communications, Inc. 509fe6320SNavdeep Parhar * All rights reserved. 609fe6320SNavdeep Parhar * 709fe6320SNavdeep Parhar * Redistribution and use in source and binary forms, with or without 809fe6320SNavdeep Parhar * modification, are permitted provided that the following conditions 909fe6320SNavdeep Parhar * are met: 1009fe6320SNavdeep Parhar * 1. Redistributions of source code must retain the above copyright 1109fe6320SNavdeep Parhar * notice, this list of conditions and the following disclaimer. 1209fe6320SNavdeep Parhar * 2. Redistributions in binary form must reproduce the above copyright 1309fe6320SNavdeep Parhar * notice, this list of conditions and the following disclaimer in the 1409fe6320SNavdeep Parhar * documentation and/or other materials provided with the distribution. 1509fe6320SNavdeep Parhar * 1609fe6320SNavdeep Parhar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1709fe6320SNavdeep Parhar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1809fe6320SNavdeep Parhar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1909fe6320SNavdeep Parhar * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2009fe6320SNavdeep Parhar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2109fe6320SNavdeep Parhar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2209fe6320SNavdeep Parhar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2309fe6320SNavdeep Parhar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2409fe6320SNavdeep Parhar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2509fe6320SNavdeep Parhar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2609fe6320SNavdeep Parhar * SUCH DAMAGE. 2709fe6320SNavdeep Parhar */ 2809fe6320SNavdeep Parhar #include <sys/cdefs.h> 2909fe6320SNavdeep Parhar #include "opt_inet.h" 300a0a697cSNavdeep Parhar #include "opt_inet6.h" 3109fe6320SNavdeep Parhar 3209fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD 3309fe6320SNavdeep Parhar #include <sys/param.h> 3409fe6320SNavdeep Parhar #include <sys/systm.h> 3509fe6320SNavdeep Parhar #include <sys/kernel.h> 3609fe6320SNavdeep Parhar #include <sys/module.h> 3709fe6320SNavdeep Parhar #include <sys/bus.h> 380a0a697cSNavdeep Parhar #include <sys/fnv_hash.h> 3909fe6320SNavdeep Parhar #include <sys/lock.h> 4009fe6320SNavdeep Parhar #include <sys/mutex.h> 4109fe6320SNavdeep Parhar #include <sys/rwlock.h> 4209fe6320SNavdeep Parhar #include <sys/socket.h> 43b2c558c8SGleb Smirnoff #include <sys/socketvar.h> 4409fe6320SNavdeep Parhar #include <sys/sbuf.h> 4519abdd06SNavdeep Parhar #include <sys/taskqueue.h> 4609fe6320SNavdeep Parhar #include <net/if.h> 4709fe6320SNavdeep Parhar #include <net/if_types.h> 4809fe6320SNavdeep Parhar #include <net/ethernet.h> 4909fe6320SNavdeep Parhar #include <net/if_vlan_var.h> 5009fe6320SNavdeep Parhar #include <net/route.h> 5109fe6320SNavdeep Parhar #include <netinet/in.h> 52e68b3792SGleb Smirnoff #include <netinet/in_pcb.h> 53b2c558c8SGleb Smirnoff #include <netinet/tcp_var.h> 5409fe6320SNavdeep Parhar #include <netinet/toecore.h> 5509fe6320SNavdeep Parhar 5609fe6320SNavdeep Parhar #include "common/common.h" 5709fe6320SNavdeep Parhar #include "common/t4_msg.h" 5809fe6320SNavdeep Parhar #include "tom/t4_tom_l2t.h" 5909fe6320SNavdeep Parhar #include "tom/t4_tom.h" 6009fe6320SNavdeep Parhar 6109fe6320SNavdeep Parhar #define VLAN_NONE 0xfff 6209fe6320SNavdeep Parhar 6309fe6320SNavdeep Parhar static inline void 6409fe6320SNavdeep Parhar l2t_hold(struct l2t_data *d, struct l2t_entry *e) 6509fe6320SNavdeep Parhar { 660a0a697cSNavdeep Parhar 6709fe6320SNavdeep Parhar if (atomic_fetchadd_int(&e->refcnt, 1) == 0) /* 0 -> 1 transition */ 6809fe6320SNavdeep Parhar atomic_subtract_int(&d->nfree, 1); 6909fe6320SNavdeep Parhar } 7009fe6320SNavdeep Parhar 710a0a697cSNavdeep Parhar static inline u_int 720a0a697cSNavdeep Parhar l2_hash(struct l2t_data *d, const struct sockaddr *sa, int ifindex) 7309fe6320SNavdeep Parhar { 740a0a697cSNavdeep Parhar u_int hash, half = d->l2t_size / 2, start = 0; 750a0a697cSNavdeep Parhar const void *key; 760a0a697cSNavdeep Parhar size_t len; 770a0a697cSNavdeep Parhar 780a0a697cSNavdeep Parhar KASSERT(sa->sa_family == AF_INET || sa->sa_family == AF_INET6, 790a0a697cSNavdeep Parhar ("%s: sa %p has unexpected sa_family %d", __func__, sa, 800a0a697cSNavdeep Parhar sa->sa_family)); 810a0a697cSNavdeep Parhar 820a0a697cSNavdeep Parhar if (sa->sa_family == AF_INET) { 830a0a697cSNavdeep Parhar const struct sockaddr_in *sin = (const void *)sa; 840a0a697cSNavdeep Parhar 850a0a697cSNavdeep Parhar key = &sin->sin_addr; 860a0a697cSNavdeep Parhar len = sizeof(sin->sin_addr); 870a0a697cSNavdeep Parhar } else { 880a0a697cSNavdeep Parhar const struct sockaddr_in6 *sin6 = (const void *)sa; 890a0a697cSNavdeep Parhar 900a0a697cSNavdeep Parhar key = &sin6->sin6_addr; 910a0a697cSNavdeep Parhar len = sizeof(sin6->sin6_addr); 920a0a697cSNavdeep Parhar start = half; 930a0a697cSNavdeep Parhar } 940a0a697cSNavdeep Parhar 950a0a697cSNavdeep Parhar hash = fnv_32_buf(key, len, FNV1_32_INIT); 960a0a697cSNavdeep Parhar hash = fnv_32_buf(&ifindex, sizeof(ifindex), hash); 970a0a697cSNavdeep Parhar hash %= half; 980a0a697cSNavdeep Parhar 990a0a697cSNavdeep Parhar return (hash + start); 1000a0a697cSNavdeep Parhar } 1010a0a697cSNavdeep Parhar 1020a0a697cSNavdeep Parhar static inline int 1030a0a697cSNavdeep Parhar l2_cmp(const struct sockaddr *sa, struct l2t_entry *e) 1040a0a697cSNavdeep Parhar { 1050a0a697cSNavdeep Parhar 1060a0a697cSNavdeep Parhar KASSERT(sa->sa_family == AF_INET || sa->sa_family == AF_INET6, 1070a0a697cSNavdeep Parhar ("%s: sa %p has unexpected sa_family %d", __func__, sa, 1080a0a697cSNavdeep Parhar sa->sa_family)); 1090a0a697cSNavdeep Parhar 1100a0a697cSNavdeep Parhar if (sa->sa_family == AF_INET) { 1110a0a697cSNavdeep Parhar const struct sockaddr_in *sin = (const void *)sa; 1120a0a697cSNavdeep Parhar 1130a0a697cSNavdeep Parhar return (e->addr[0] != sin->sin_addr.s_addr); 1140a0a697cSNavdeep Parhar } else { 1150a0a697cSNavdeep Parhar const struct sockaddr_in6 *sin6 = (const void *)sa; 1160a0a697cSNavdeep Parhar 1170a0a697cSNavdeep Parhar return (memcmp(&e->addr[0], &sin6->sin6_addr, sizeof(e->addr))); 1180a0a697cSNavdeep Parhar } 1190a0a697cSNavdeep Parhar } 1200a0a697cSNavdeep Parhar 1210a0a697cSNavdeep Parhar static inline void 1220a0a697cSNavdeep Parhar l2_store(const struct sockaddr *sa, struct l2t_entry *e) 1230a0a697cSNavdeep Parhar { 1240a0a697cSNavdeep Parhar 1250a0a697cSNavdeep Parhar KASSERT(sa->sa_family == AF_INET || sa->sa_family == AF_INET6, 1260a0a697cSNavdeep Parhar ("%s: sa %p has unexpected sa_family %d", __func__, sa, 1270a0a697cSNavdeep Parhar sa->sa_family)); 1280a0a697cSNavdeep Parhar 1290a0a697cSNavdeep Parhar if (sa->sa_family == AF_INET) { 1300a0a697cSNavdeep Parhar const struct sockaddr_in *sin = (const void *)sa; 1310a0a697cSNavdeep Parhar 1320a0a697cSNavdeep Parhar e->addr[0] = sin->sin_addr.s_addr; 1330a0a697cSNavdeep Parhar e->ipv6 = 0; 1340a0a697cSNavdeep Parhar } else { 1350a0a697cSNavdeep Parhar const struct sockaddr_in6 *sin6 = (const void *)sa; 1360a0a697cSNavdeep Parhar 1370a0a697cSNavdeep Parhar memcpy(&e->addr[0], &sin6->sin6_addr, sizeof(e->addr)); 1380a0a697cSNavdeep Parhar e->ipv6 = 1; 1390a0a697cSNavdeep Parhar } 14009fe6320SNavdeep Parhar } 14109fe6320SNavdeep Parhar 14209fe6320SNavdeep Parhar /* 14309fe6320SNavdeep Parhar * Add a WR to an L2T entry's queue of work requests awaiting resolution. 14409fe6320SNavdeep Parhar * Must be called with the entry's lock held. 14509fe6320SNavdeep Parhar */ 14609fe6320SNavdeep Parhar static inline void 14709fe6320SNavdeep Parhar arpq_enqueue(struct l2t_entry *e, struct wrqe *wr) 14809fe6320SNavdeep Parhar { 14909fe6320SNavdeep Parhar mtx_assert(&e->lock, MA_OWNED); 15009fe6320SNavdeep Parhar 15109fe6320SNavdeep Parhar STAILQ_INSERT_TAIL(&e->wr_list, wr, link); 15209fe6320SNavdeep Parhar } 15309fe6320SNavdeep Parhar 15409fe6320SNavdeep Parhar static inline void 15509fe6320SNavdeep Parhar send_pending(struct adapter *sc, struct l2t_entry *e) 15609fe6320SNavdeep Parhar { 15709fe6320SNavdeep Parhar struct wrqe *wr; 15809fe6320SNavdeep Parhar 15909fe6320SNavdeep Parhar mtx_assert(&e->lock, MA_OWNED); 16009fe6320SNavdeep Parhar 16109fe6320SNavdeep Parhar while ((wr = STAILQ_FIRST(&e->wr_list)) != NULL) { 16209fe6320SNavdeep Parhar STAILQ_REMOVE_HEAD(&e->wr_list, link); 16309fe6320SNavdeep Parhar t4_wrq_tx(sc, wr); 16409fe6320SNavdeep Parhar } 16509fe6320SNavdeep Parhar } 16609fe6320SNavdeep Parhar 16709fe6320SNavdeep Parhar static void 16819abdd06SNavdeep Parhar resolution_failed(struct adapter *sc, struct l2t_entry *e) 16909fe6320SNavdeep Parhar { 17019abdd06SNavdeep Parhar struct tom_data *td = sc->tom_softc; 17109fe6320SNavdeep Parhar 17209fe6320SNavdeep Parhar mtx_assert(&e->lock, MA_OWNED); 17309fe6320SNavdeep Parhar 17419abdd06SNavdeep Parhar mtx_lock(&td->unsent_wr_lock); 17519abdd06SNavdeep Parhar STAILQ_CONCAT(&td->unsent_wr_list, &e->wr_list); 17619abdd06SNavdeep Parhar mtx_unlock(&td->unsent_wr_lock); 17719abdd06SNavdeep Parhar 17819abdd06SNavdeep Parhar taskqueue_enqueue(taskqueue_thread, &td->reclaim_wr_resources); 17909fe6320SNavdeep Parhar } 18009fe6320SNavdeep Parhar 18109fe6320SNavdeep Parhar static void 18209fe6320SNavdeep Parhar update_entry(struct adapter *sc, struct l2t_entry *e, uint8_t *lladdr, 18309fe6320SNavdeep Parhar uint16_t vtag) 18409fe6320SNavdeep Parhar { 18509fe6320SNavdeep Parhar 18609fe6320SNavdeep Parhar mtx_assert(&e->lock, MA_OWNED); 18709fe6320SNavdeep Parhar 18809fe6320SNavdeep Parhar /* 18909fe6320SNavdeep Parhar * The entry may be in active use (e->refcount > 0) or not. We update 19009fe6320SNavdeep Parhar * it even when it's not as this simplifies the case where we decide to 19109fe6320SNavdeep Parhar * reuse the entry later. 19209fe6320SNavdeep Parhar */ 19309fe6320SNavdeep Parhar 19409fe6320SNavdeep Parhar if (lladdr == NULL && 19509fe6320SNavdeep Parhar (e->state == L2T_STATE_RESOLVING || e->state == L2T_STATE_FAILED)) { 19609fe6320SNavdeep Parhar /* 19709fe6320SNavdeep Parhar * Never got a valid L2 address for this one. Just mark it as 19809fe6320SNavdeep Parhar * failed instead of removing it from the hash (for which we'd 19909fe6320SNavdeep Parhar * need to wlock the table). 20009fe6320SNavdeep Parhar */ 20109fe6320SNavdeep Parhar e->state = L2T_STATE_FAILED; 20219abdd06SNavdeep Parhar resolution_failed(sc, e); 20309fe6320SNavdeep Parhar return; 20409fe6320SNavdeep Parhar 20509fe6320SNavdeep Parhar } else if (lladdr == NULL) { 20609fe6320SNavdeep Parhar 20709fe6320SNavdeep Parhar /* Valid or already-stale entry was deleted (or expired) */ 20809fe6320SNavdeep Parhar 20909fe6320SNavdeep Parhar KASSERT(e->state == L2T_STATE_VALID || 21009fe6320SNavdeep Parhar e->state == L2T_STATE_STALE, 21109fe6320SNavdeep Parhar ("%s: lladdr NULL, state %d", __func__, e->state)); 21209fe6320SNavdeep Parhar 21309fe6320SNavdeep Parhar e->state = L2T_STATE_STALE; 21409fe6320SNavdeep Parhar 21507f47e88SNavdeep Parhar } else if (e->state == L2T_STATE_RESOLVING || 21609fe6320SNavdeep Parhar e->state == L2T_STATE_FAILED || 21709fe6320SNavdeep Parhar memcmp(e->dmac, lladdr, ETHER_ADDR_LEN)) { 21809fe6320SNavdeep Parhar 21909fe6320SNavdeep Parhar /* unresolved -> resolved; or dmac changed */ 22009fe6320SNavdeep Parhar 22109fe6320SNavdeep Parhar memcpy(e->dmac, lladdr, ETHER_ADDR_LEN); 22209fe6320SNavdeep Parhar e->vlan = vtag; 22307f47e88SNavdeep Parhar if (t4_write_l2e(e, 1) == 0) 22409fe6320SNavdeep Parhar e->state = L2T_STATE_VALID; 22507f47e88SNavdeep Parhar } else 22607f47e88SNavdeep Parhar e->state = L2T_STATE_VALID; 22709fe6320SNavdeep Parhar } 22809fe6320SNavdeep Parhar 22909fe6320SNavdeep Parhar static int 23009fe6320SNavdeep Parhar resolve_entry(struct adapter *sc, struct l2t_entry *e) 23109fe6320SNavdeep Parhar { 23209fe6320SNavdeep Parhar struct tom_data *td = sc->tom_softc; 23309fe6320SNavdeep Parhar struct toedev *tod = &td->tod; 23409fe6320SNavdeep Parhar struct sockaddr_in sin = {0}; 2350a0a697cSNavdeep Parhar struct sockaddr_in6 sin6 = {0}; 2360a0a697cSNavdeep Parhar struct sockaddr *sa; 2374fb3a820SAlexander V. Chernikov uint8_t dmac[ETHER_HDR_LEN]; 23872049e73SNavdeep Parhar uint16_t vtag; 23909fe6320SNavdeep Parhar int rc; 24009fe6320SNavdeep Parhar 2410a0a697cSNavdeep Parhar if (e->ipv6 == 0) { 24209fe6320SNavdeep Parhar sin.sin_family = AF_INET; 24309fe6320SNavdeep Parhar sin.sin_len = sizeof(struct sockaddr_in); 2440a0a697cSNavdeep Parhar sin.sin_addr.s_addr = e->addr[0]; 2450a0a697cSNavdeep Parhar sa = (void *)&sin; 2460a0a697cSNavdeep Parhar } else { 2470a0a697cSNavdeep Parhar sin6.sin6_family = AF_INET6; 2480a0a697cSNavdeep Parhar sin6.sin6_len = sizeof(struct sockaddr_in6); 2490a0a697cSNavdeep Parhar memcpy(&sin6.sin6_addr, &e->addr[0], sizeof(e->addr)); 2500a0a697cSNavdeep Parhar sa = (void *)&sin6; 2510a0a697cSNavdeep Parhar } 25209fe6320SNavdeep Parhar 25372049e73SNavdeep Parhar vtag = EVL_MAKETAG(VLAN_NONE, 0, 0); 2540a0a697cSNavdeep Parhar rc = toe_l2_resolve(tod, e->ifp, sa, dmac, &vtag); 25509fe6320SNavdeep Parhar if (rc == EWOULDBLOCK) 25609fe6320SNavdeep Parhar return (rc); 25709fe6320SNavdeep Parhar 25809fe6320SNavdeep Parhar mtx_lock(&e->lock); 25909fe6320SNavdeep Parhar update_entry(sc, e, rc == 0 ? dmac : NULL, vtag); 26009fe6320SNavdeep Parhar mtx_unlock(&e->lock); 26109fe6320SNavdeep Parhar 26209fe6320SNavdeep Parhar return (rc); 26309fe6320SNavdeep Parhar } 26409fe6320SNavdeep Parhar 26509fe6320SNavdeep Parhar int 26609fe6320SNavdeep Parhar t4_l2t_send_slow(struct adapter *sc, struct wrqe *wr, struct l2t_entry *e) 26709fe6320SNavdeep Parhar { 26809fe6320SNavdeep Parhar 26909fe6320SNavdeep Parhar again: 27009fe6320SNavdeep Parhar switch (e->state) { 27109fe6320SNavdeep Parhar case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ 27209fe6320SNavdeep Parhar 27353c17de2SNavdeep Parhar resolve_entry(sc, e); 27409fe6320SNavdeep Parhar 27509fe6320SNavdeep Parhar /* Fall through */ 27609fe6320SNavdeep Parhar 27709fe6320SNavdeep Parhar case L2T_STATE_VALID: /* fast-path, send the packet on */ 27809fe6320SNavdeep Parhar 27909fe6320SNavdeep Parhar t4_wrq_tx(sc, wr); 28009fe6320SNavdeep Parhar return (0); 28109fe6320SNavdeep Parhar 28209fe6320SNavdeep Parhar case L2T_STATE_RESOLVING: 28309fe6320SNavdeep Parhar case L2T_STATE_SYNC_WRITE: 28409fe6320SNavdeep Parhar 28509fe6320SNavdeep Parhar mtx_lock(&e->lock); 28609fe6320SNavdeep Parhar if (e->state != L2T_STATE_SYNC_WRITE && 28709fe6320SNavdeep Parhar e->state != L2T_STATE_RESOLVING) { 28809fe6320SNavdeep Parhar /* state changed by the time we got here */ 28909fe6320SNavdeep Parhar mtx_unlock(&e->lock); 29009fe6320SNavdeep Parhar goto again; 29109fe6320SNavdeep Parhar } 29207f47e88SNavdeep Parhar if (adapter_stopped(sc)) 29307f47e88SNavdeep Parhar free(wr, M_CXGBE); 29407f47e88SNavdeep Parhar else 29509fe6320SNavdeep Parhar arpq_enqueue(e, wr); 29609fe6320SNavdeep Parhar mtx_unlock(&e->lock); 29709fe6320SNavdeep Parhar 29809fe6320SNavdeep Parhar if (resolve_entry(sc, e) == EWOULDBLOCK) 29909fe6320SNavdeep Parhar break; 30009fe6320SNavdeep Parhar 30109fe6320SNavdeep Parhar mtx_lock(&e->lock); 30209fe6320SNavdeep Parhar if (e->state == L2T_STATE_VALID && !STAILQ_EMPTY(&e->wr_list)) 30309fe6320SNavdeep Parhar send_pending(sc, e); 30409fe6320SNavdeep Parhar if (e->state == L2T_STATE_FAILED) 30519abdd06SNavdeep Parhar resolution_failed(sc, e); 30609fe6320SNavdeep Parhar mtx_unlock(&e->lock); 30709fe6320SNavdeep Parhar break; 30809fe6320SNavdeep Parhar 30909fe6320SNavdeep Parhar case L2T_STATE_FAILED: 31009fe6320SNavdeep Parhar return (EHOSTUNREACH); 31109fe6320SNavdeep Parhar } 31209fe6320SNavdeep Parhar 31309fe6320SNavdeep Parhar return (0); 31409fe6320SNavdeep Parhar } 31509fe6320SNavdeep Parhar 316671bf2b8SNavdeep Parhar int 31709fe6320SNavdeep Parhar do_l2t_write_rpl2(struct sge_iq *iq, const struct rss_header *rss, 31809fe6320SNavdeep Parhar struct mbuf *m) 31909fe6320SNavdeep Parhar { 32009fe6320SNavdeep Parhar struct adapter *sc = iq->adapter; 32109fe6320SNavdeep Parhar const struct cpl_l2t_write_rpl *rpl = (const void *)(rss + 1); 322cfcfd3c7SNavdeep Parhar const u_int hwidx = GET_TID(rpl) & ~(F_SYNC_WR | V_TID_QID(M_TID_QID)); 323cfcfd3c7SNavdeep Parhar const bool sync = GET_TID(rpl) & F_SYNC_WR; 32409fe6320SNavdeep Parhar 325cfcfd3c7SNavdeep Parhar MPASS(iq->abs_id == G_TID_QID(GET_TID(rpl))); 326cfcfd3c7SNavdeep Parhar 327cfcfd3c7SNavdeep Parhar if (__predict_false(hwidx < sc->vres.l2t.start) || 328cfcfd3c7SNavdeep Parhar __predict_false(hwidx >= sc->vres.l2t.start + sc->vres.l2t.size) || 329cfcfd3c7SNavdeep Parhar __predict_false(rpl->status != CPL_ERR_NONE)) { 330cfcfd3c7SNavdeep Parhar CH_ERR(sc, "%s: hwidx %u, rpl %u, sync %u; L2T st %u, sz %u\n", 331cfcfd3c7SNavdeep Parhar __func__, hwidx, rpl->status, sync, sc->vres.l2t.start, 332cfcfd3c7SNavdeep Parhar sc->vres.l2t.size); 333671bf2b8SNavdeep Parhar return (EINVAL); 334671bf2b8SNavdeep Parhar } 33509fe6320SNavdeep Parhar 336cfcfd3c7SNavdeep Parhar if (sync) { 337cfcfd3c7SNavdeep Parhar const u_int idx = hwidx - sc->vres.l2t.start; 338cfcfd3c7SNavdeep Parhar struct l2t_entry *e = &sc->l2t->l2tab[idx]; 33909fe6320SNavdeep Parhar 34009fe6320SNavdeep Parhar mtx_lock(&e->lock); 34109fe6320SNavdeep Parhar if (e->state != L2T_STATE_SWITCHING) { 34209fe6320SNavdeep Parhar send_pending(sc, e); 34309fe6320SNavdeep Parhar e->state = L2T_STATE_VALID; 34409fe6320SNavdeep Parhar } 34509fe6320SNavdeep Parhar mtx_unlock(&e->lock); 34609fe6320SNavdeep Parhar } 34709fe6320SNavdeep Parhar 34809fe6320SNavdeep Parhar return (0); 34909fe6320SNavdeep Parhar } 35009fe6320SNavdeep Parhar 35109fe6320SNavdeep Parhar /* 35209fe6320SNavdeep Parhar * The TOE wants an L2 table entry that it can use to reach the next hop over 35309fe6320SNavdeep Parhar * the specified port. Produce such an entry - create one if needed. 35409fe6320SNavdeep Parhar * 35509fe6320SNavdeep Parhar * Note that the ifnet could be a pseudo-device like if_vlan, if_lagg, etc. on 35609fe6320SNavdeep Parhar * top of the real cxgbe interface. 35709fe6320SNavdeep Parhar */ 35809fe6320SNavdeep Parhar struct l2t_entry * 359954712e8SJustin Hibbits t4_l2t_get(struct port_info *pi, if_t ifp, struct sockaddr *sa) 36009fe6320SNavdeep Parhar { 36109fe6320SNavdeep Parhar struct l2t_entry *e; 362671bf2b8SNavdeep Parhar struct adapter *sc = pi->adapter; 363671bf2b8SNavdeep Parhar struct l2t_data *d = sc->l2t; 364*f79fba05SNavdeep Parhar u_int hash; 36572049e73SNavdeep Parhar uint16_t vid, pcp, vtag; 36609fe6320SNavdeep Parhar 3670a0a697cSNavdeep Parhar KASSERT(sa->sa_family == AF_INET || sa->sa_family == AF_INET6, 3680a0a697cSNavdeep Parhar ("%s: sa %p has unexpected sa_family %d", __func__, sa, 3690a0a697cSNavdeep Parhar sa->sa_family)); 37009fe6320SNavdeep Parhar 37172049e73SNavdeep Parhar vid = VLAN_NONE; 37272049e73SNavdeep Parhar pcp = 0; 373954712e8SJustin Hibbits if (if_gettype(ifp) == IFT_L2VLAN) { 37472049e73SNavdeep Parhar VLAN_TAG(ifp, &vid); 37572049e73SNavdeep Parhar VLAN_PCP(ifp, &pcp); 376954712e8SJustin Hibbits } else if ((pcp = if_getpcp(ifp)) != IFNET_PCP_NONE) 37772049e73SNavdeep Parhar vid = 0; 378954712e8SJustin Hibbits else 379954712e8SJustin Hibbits pcp = 0; 38072049e73SNavdeep Parhar vtag = EVL_MAKETAG(vid, pcp, 0); 38109fe6320SNavdeep Parhar 382954712e8SJustin Hibbits hash = l2_hash(d, sa, if_getindex(ifp)); 38309fe6320SNavdeep Parhar rw_wlock(&d->lock); 384cd93fdeeSNavdeep Parhar if (__predict_false(d->l2t_stopped)) { 385cd93fdeeSNavdeep Parhar e = NULL; 386cd93fdeeSNavdeep Parhar goto done; 387cd93fdeeSNavdeep Parhar } 38809fe6320SNavdeep Parhar for (e = d->l2tab[hash].first; e; e = e->next) { 389*f79fba05SNavdeep Parhar if (l2_cmp(sa, e) == 0 && e->ifp == ifp && e->vlan == vtag) { 39009fe6320SNavdeep Parhar l2t_hold(d, e); 39109fe6320SNavdeep Parhar goto done; 39209fe6320SNavdeep Parhar } 39309fe6320SNavdeep Parhar } 39409fe6320SNavdeep Parhar 39509fe6320SNavdeep Parhar /* Need to allocate a new entry */ 39609fe6320SNavdeep Parhar e = t4_alloc_l2e(d); 39709fe6320SNavdeep Parhar if (e) { 39809fe6320SNavdeep Parhar mtx_lock(&e->lock); /* avoid race with t4_l2t_free */ 39909fe6320SNavdeep Parhar e->next = d->l2tab[hash].first; 40009fe6320SNavdeep Parhar d->l2tab[hash].first = e; 40109fe6320SNavdeep Parhar 40209fe6320SNavdeep Parhar e->state = L2T_STATE_RESOLVING; 4030a0a697cSNavdeep Parhar l2_store(sa, e); 40409fe6320SNavdeep Parhar e->ifp = ifp; 40509fe6320SNavdeep Parhar e->hash = hash; 40609fe6320SNavdeep Parhar e->lport = pi->lport; 407671bf2b8SNavdeep Parhar e->wrq = &sc->sge.ctrlq[pi->port_id]; 408671bf2b8SNavdeep Parhar e->iqid = sc->sge.ofld_rxq[pi->vi[0].first_ofld_rxq].iq.abs_id; 40909fe6320SNavdeep Parhar atomic_store_rel_int(&e->refcnt, 1); 41072049e73SNavdeep Parhar e->vlan = vtag; 41109fe6320SNavdeep Parhar mtx_unlock(&e->lock); 41209fe6320SNavdeep Parhar } 41309fe6320SNavdeep Parhar done: 41409fe6320SNavdeep Parhar rw_wunlock(&d->lock); 41509fe6320SNavdeep Parhar return e; 41609fe6320SNavdeep Parhar } 41709fe6320SNavdeep Parhar 41809fe6320SNavdeep Parhar /* 41909fe6320SNavdeep Parhar * Called when the host's ARP layer makes a change to some entry that is loaded 42009fe6320SNavdeep Parhar * into the HW L2 table. 42109fe6320SNavdeep Parhar */ 42209fe6320SNavdeep Parhar void 423954712e8SJustin Hibbits t4_l2_update(struct toedev *tod, if_t ifp, struct sockaddr *sa, 42409fe6320SNavdeep Parhar uint8_t *lladdr, uint16_t vtag) 42509fe6320SNavdeep Parhar { 42609fe6320SNavdeep Parhar struct adapter *sc = tod->tod_softc; 42709fe6320SNavdeep Parhar struct l2t_entry *e; 42809fe6320SNavdeep Parhar struct l2t_data *d = sc->l2t; 4290a0a697cSNavdeep Parhar u_int hash; 43009fe6320SNavdeep Parhar 43109fe6320SNavdeep Parhar KASSERT(d != NULL, ("%s: no L2 table", __func__)); 43209fe6320SNavdeep Parhar 433954712e8SJustin Hibbits hash = l2_hash(d, sa, if_getindex(ifp)); 43409fe6320SNavdeep Parhar rw_rlock(&d->lock); 435cd93fdeeSNavdeep Parhar if (__predict_false(d->l2t_stopped)) 436cd93fdeeSNavdeep Parhar goto done; 43709fe6320SNavdeep Parhar for (e = d->l2tab[hash].first; e; e = e->next) { 4380a0a697cSNavdeep Parhar if (l2_cmp(sa, e) == 0 && e->ifp == ifp) { 43909fe6320SNavdeep Parhar mtx_lock(&e->lock); 44009fe6320SNavdeep Parhar if (atomic_load_acq_int(&e->refcnt)) 44109fe6320SNavdeep Parhar goto found; 4423883300aSNavdeep Parhar if (e->state == L2T_STATE_VALID) 44309fe6320SNavdeep Parhar e->state = L2T_STATE_STALE; 44409fe6320SNavdeep Parhar mtx_unlock(&e->lock); 44509fe6320SNavdeep Parhar break; 44609fe6320SNavdeep Parhar } 44709fe6320SNavdeep Parhar } 448cd93fdeeSNavdeep Parhar done: 44909fe6320SNavdeep Parhar rw_runlock(&d->lock); 45009fe6320SNavdeep Parhar 45109fe6320SNavdeep Parhar /* 45209fe6320SNavdeep Parhar * This is of no interest to us. We've never had an offloaded 45309fe6320SNavdeep Parhar * connection to this destination, and we aren't attempting one right 45409fe6320SNavdeep Parhar * now. 45509fe6320SNavdeep Parhar */ 45609fe6320SNavdeep Parhar return; 45709fe6320SNavdeep Parhar 45809fe6320SNavdeep Parhar found: 45909fe6320SNavdeep Parhar rw_runlock(&d->lock); 46009fe6320SNavdeep Parhar 46109fe6320SNavdeep Parhar KASSERT(e->state != L2T_STATE_UNUSED, 46209fe6320SNavdeep Parhar ("%s: unused entry in the hash.", __func__)); 46309fe6320SNavdeep Parhar 46409fe6320SNavdeep Parhar update_entry(sc, e, lladdr, vtag); 46509fe6320SNavdeep Parhar mtx_unlock(&e->lock); 46609fe6320SNavdeep Parhar } 46709fe6320SNavdeep Parhar #endif 468