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 21509fe6320SNavdeep Parhar } else { 21609fe6320SNavdeep Parhar 21709fe6320SNavdeep Parhar if (e->state == L2T_STATE_RESOLVING || 21809fe6320SNavdeep Parhar e->state == L2T_STATE_FAILED || 21909fe6320SNavdeep Parhar memcmp(e->dmac, lladdr, ETHER_ADDR_LEN)) { 22009fe6320SNavdeep Parhar 22109fe6320SNavdeep Parhar /* unresolved -> resolved; or dmac changed */ 22209fe6320SNavdeep Parhar 22309fe6320SNavdeep Parhar memcpy(e->dmac, lladdr, ETHER_ADDR_LEN); 22409fe6320SNavdeep Parhar e->vlan = vtag; 225671bf2b8SNavdeep Parhar t4_write_l2e(e, 1); 22609fe6320SNavdeep Parhar } 22709fe6320SNavdeep Parhar e->state = L2T_STATE_VALID; 22809fe6320SNavdeep Parhar } 22909fe6320SNavdeep Parhar } 23009fe6320SNavdeep Parhar 23109fe6320SNavdeep Parhar static int 23209fe6320SNavdeep Parhar resolve_entry(struct adapter *sc, struct l2t_entry *e) 23309fe6320SNavdeep Parhar { 23409fe6320SNavdeep Parhar struct tom_data *td = sc->tom_softc; 23509fe6320SNavdeep Parhar struct toedev *tod = &td->tod; 23609fe6320SNavdeep Parhar struct sockaddr_in sin = {0}; 2370a0a697cSNavdeep Parhar struct sockaddr_in6 sin6 = {0}; 2380a0a697cSNavdeep Parhar struct sockaddr *sa; 2394fb3a820SAlexander V. Chernikov uint8_t dmac[ETHER_HDR_LEN]; 24072049e73SNavdeep Parhar uint16_t vtag; 24109fe6320SNavdeep Parhar int rc; 24209fe6320SNavdeep Parhar 2430a0a697cSNavdeep Parhar if (e->ipv6 == 0) { 24409fe6320SNavdeep Parhar sin.sin_family = AF_INET; 24509fe6320SNavdeep Parhar sin.sin_len = sizeof(struct sockaddr_in); 2460a0a697cSNavdeep Parhar sin.sin_addr.s_addr = e->addr[0]; 2470a0a697cSNavdeep Parhar sa = (void *)&sin; 2480a0a697cSNavdeep Parhar } else { 2490a0a697cSNavdeep Parhar sin6.sin6_family = AF_INET6; 2500a0a697cSNavdeep Parhar sin6.sin6_len = sizeof(struct sockaddr_in6); 2510a0a697cSNavdeep Parhar memcpy(&sin6.sin6_addr, &e->addr[0], sizeof(e->addr)); 2520a0a697cSNavdeep Parhar sa = (void *)&sin6; 2530a0a697cSNavdeep Parhar } 25409fe6320SNavdeep Parhar 25572049e73SNavdeep Parhar vtag = EVL_MAKETAG(VLAN_NONE, 0, 0); 2560a0a697cSNavdeep Parhar rc = toe_l2_resolve(tod, e->ifp, sa, dmac, &vtag); 25709fe6320SNavdeep Parhar if (rc == EWOULDBLOCK) 25809fe6320SNavdeep Parhar return (rc); 25909fe6320SNavdeep Parhar 26009fe6320SNavdeep Parhar mtx_lock(&e->lock); 26109fe6320SNavdeep Parhar update_entry(sc, e, rc == 0 ? dmac : NULL, vtag); 26209fe6320SNavdeep Parhar mtx_unlock(&e->lock); 26309fe6320SNavdeep Parhar 26409fe6320SNavdeep Parhar return (rc); 26509fe6320SNavdeep Parhar } 26609fe6320SNavdeep Parhar 26709fe6320SNavdeep Parhar int 26809fe6320SNavdeep Parhar t4_l2t_send_slow(struct adapter *sc, struct wrqe *wr, struct l2t_entry *e) 26909fe6320SNavdeep Parhar { 27009fe6320SNavdeep Parhar 27109fe6320SNavdeep Parhar again: 27209fe6320SNavdeep Parhar switch (e->state) { 27309fe6320SNavdeep Parhar case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ 27409fe6320SNavdeep Parhar 27553c17de2SNavdeep Parhar resolve_entry(sc, e); 27609fe6320SNavdeep Parhar 27709fe6320SNavdeep Parhar /* Fall through */ 27809fe6320SNavdeep Parhar 27909fe6320SNavdeep Parhar case L2T_STATE_VALID: /* fast-path, send the packet on */ 28009fe6320SNavdeep Parhar 28109fe6320SNavdeep Parhar t4_wrq_tx(sc, wr); 28209fe6320SNavdeep Parhar return (0); 28309fe6320SNavdeep Parhar 28409fe6320SNavdeep Parhar case L2T_STATE_RESOLVING: 28509fe6320SNavdeep Parhar case L2T_STATE_SYNC_WRITE: 28609fe6320SNavdeep Parhar 28709fe6320SNavdeep Parhar mtx_lock(&e->lock); 28809fe6320SNavdeep Parhar if (e->state != L2T_STATE_SYNC_WRITE && 28909fe6320SNavdeep Parhar e->state != L2T_STATE_RESOLVING) { 29009fe6320SNavdeep Parhar /* state changed by the time we got here */ 29109fe6320SNavdeep Parhar mtx_unlock(&e->lock); 29209fe6320SNavdeep Parhar goto again; 29309fe6320SNavdeep Parhar } 29409fe6320SNavdeep Parhar arpq_enqueue(e, wr); 29509fe6320SNavdeep Parhar mtx_unlock(&e->lock); 29609fe6320SNavdeep Parhar 29709fe6320SNavdeep Parhar if (resolve_entry(sc, e) == EWOULDBLOCK) 29809fe6320SNavdeep Parhar break; 29909fe6320SNavdeep Parhar 30009fe6320SNavdeep Parhar mtx_lock(&e->lock); 30109fe6320SNavdeep Parhar if (e->state == L2T_STATE_VALID && !STAILQ_EMPTY(&e->wr_list)) 30209fe6320SNavdeep Parhar send_pending(sc, e); 30309fe6320SNavdeep Parhar if (e->state == L2T_STATE_FAILED) 30419abdd06SNavdeep Parhar resolution_failed(sc, e); 30509fe6320SNavdeep Parhar mtx_unlock(&e->lock); 30609fe6320SNavdeep Parhar break; 30709fe6320SNavdeep Parhar 30809fe6320SNavdeep Parhar case L2T_STATE_FAILED: 30909fe6320SNavdeep Parhar return (EHOSTUNREACH); 31009fe6320SNavdeep Parhar } 31109fe6320SNavdeep Parhar 31209fe6320SNavdeep Parhar return (0); 31309fe6320SNavdeep Parhar } 31409fe6320SNavdeep Parhar 315671bf2b8SNavdeep Parhar int 31609fe6320SNavdeep Parhar do_l2t_write_rpl2(struct sge_iq *iq, const struct rss_header *rss, 31709fe6320SNavdeep Parhar struct mbuf *m) 31809fe6320SNavdeep Parhar { 31909fe6320SNavdeep Parhar struct adapter *sc = iq->adapter; 32009fe6320SNavdeep Parhar const struct cpl_l2t_write_rpl *rpl = (const void *)(rss + 1); 321cfcfd3c7SNavdeep Parhar const u_int hwidx = GET_TID(rpl) & ~(F_SYNC_WR | V_TID_QID(M_TID_QID)); 322cfcfd3c7SNavdeep Parhar const bool sync = GET_TID(rpl) & F_SYNC_WR; 32309fe6320SNavdeep Parhar 324cfcfd3c7SNavdeep Parhar MPASS(iq->abs_id == G_TID_QID(GET_TID(rpl))); 325cfcfd3c7SNavdeep Parhar 326cfcfd3c7SNavdeep Parhar if (__predict_false(hwidx < sc->vres.l2t.start) || 327cfcfd3c7SNavdeep Parhar __predict_false(hwidx >= sc->vres.l2t.start + sc->vres.l2t.size) || 328cfcfd3c7SNavdeep Parhar __predict_false(rpl->status != CPL_ERR_NONE)) { 329cfcfd3c7SNavdeep Parhar CH_ERR(sc, "%s: hwidx %u, rpl %u, sync %u; L2T st %u, sz %u\n", 330cfcfd3c7SNavdeep Parhar __func__, hwidx, rpl->status, sync, sc->vres.l2t.start, 331cfcfd3c7SNavdeep Parhar sc->vres.l2t.size); 332671bf2b8SNavdeep Parhar return (EINVAL); 333671bf2b8SNavdeep Parhar } 33409fe6320SNavdeep Parhar 335cfcfd3c7SNavdeep Parhar if (sync) { 336cfcfd3c7SNavdeep Parhar const u_int idx = hwidx - sc->vres.l2t.start; 337cfcfd3c7SNavdeep Parhar struct l2t_entry *e = &sc->l2t->l2tab[idx]; 33809fe6320SNavdeep Parhar 33909fe6320SNavdeep Parhar mtx_lock(&e->lock); 34009fe6320SNavdeep Parhar if (e->state != L2T_STATE_SWITCHING) { 34109fe6320SNavdeep Parhar send_pending(sc, e); 34209fe6320SNavdeep Parhar e->state = L2T_STATE_VALID; 34309fe6320SNavdeep Parhar } 34409fe6320SNavdeep Parhar mtx_unlock(&e->lock); 34509fe6320SNavdeep Parhar } 34609fe6320SNavdeep Parhar 34709fe6320SNavdeep Parhar return (0); 34809fe6320SNavdeep Parhar } 34909fe6320SNavdeep Parhar 35009fe6320SNavdeep Parhar /* 35109fe6320SNavdeep Parhar * The TOE wants an L2 table entry that it can use to reach the next hop over 35209fe6320SNavdeep Parhar * the specified port. Produce such an entry - create one if needed. 35309fe6320SNavdeep Parhar * 35409fe6320SNavdeep Parhar * Note that the ifnet could be a pseudo-device like if_vlan, if_lagg, etc. on 35509fe6320SNavdeep Parhar * top of the real cxgbe interface. 35609fe6320SNavdeep Parhar */ 35709fe6320SNavdeep Parhar struct l2t_entry * 358954712e8SJustin Hibbits t4_l2t_get(struct port_info *pi, if_t ifp, struct sockaddr *sa) 35909fe6320SNavdeep Parhar { 36009fe6320SNavdeep Parhar struct l2t_entry *e; 361671bf2b8SNavdeep Parhar struct adapter *sc = pi->adapter; 362671bf2b8SNavdeep Parhar struct l2t_data *d = sc->l2t; 3630a0a697cSNavdeep Parhar u_int hash, smt_idx = pi->port_id; 36472049e73SNavdeep Parhar uint16_t vid, pcp, vtag; 36509fe6320SNavdeep Parhar 3660a0a697cSNavdeep Parhar KASSERT(sa->sa_family == AF_INET || sa->sa_family == AF_INET6, 3670a0a697cSNavdeep Parhar ("%s: sa %p has unexpected sa_family %d", __func__, sa, 3680a0a697cSNavdeep Parhar sa->sa_family)); 36909fe6320SNavdeep Parhar 37072049e73SNavdeep Parhar vid = VLAN_NONE; 37172049e73SNavdeep Parhar pcp = 0; 372954712e8SJustin Hibbits if (if_gettype(ifp) == IFT_L2VLAN) { 37372049e73SNavdeep Parhar VLAN_TAG(ifp, &vid); 37472049e73SNavdeep Parhar VLAN_PCP(ifp, &pcp); 375954712e8SJustin Hibbits } else if ((pcp = if_getpcp(ifp)) != IFNET_PCP_NONE) 37672049e73SNavdeep Parhar vid = 0; 377954712e8SJustin Hibbits else 378954712e8SJustin Hibbits pcp = 0; 37972049e73SNavdeep Parhar vtag = EVL_MAKETAG(vid, pcp, 0); 38009fe6320SNavdeep Parhar 381954712e8SJustin Hibbits hash = l2_hash(d, sa, if_getindex(ifp)); 38209fe6320SNavdeep Parhar rw_wlock(&d->lock); 383*cd93fdeeSNavdeep Parhar if (__predict_false(d->l2t_stopped)) { 384*cd93fdeeSNavdeep Parhar e = NULL; 385*cd93fdeeSNavdeep Parhar goto done; 386*cd93fdeeSNavdeep Parhar } 38709fe6320SNavdeep Parhar for (e = d->l2tab[hash].first; e; e = e->next) { 38872049e73SNavdeep Parhar if (l2_cmp(sa, e) == 0 && e->ifp == ifp && e->vlan == vtag && 3890a0a697cSNavdeep Parhar e->smt_idx == smt_idx) { 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->smt_idx = smt_idx; 40609fe6320SNavdeep Parhar e->hash = hash; 40709fe6320SNavdeep Parhar e->lport = pi->lport; 408671bf2b8SNavdeep Parhar e->wrq = &sc->sge.ctrlq[pi->port_id]; 409671bf2b8SNavdeep Parhar e->iqid = sc->sge.ofld_rxq[pi->vi[0].first_ofld_rxq].iq.abs_id; 41009fe6320SNavdeep Parhar atomic_store_rel_int(&e->refcnt, 1); 41172049e73SNavdeep Parhar e->vlan = vtag; 41209fe6320SNavdeep Parhar mtx_unlock(&e->lock); 41309fe6320SNavdeep Parhar } 41409fe6320SNavdeep Parhar done: 41509fe6320SNavdeep Parhar rw_wunlock(&d->lock); 41609fe6320SNavdeep Parhar return e; 41709fe6320SNavdeep Parhar } 41809fe6320SNavdeep Parhar 41909fe6320SNavdeep Parhar /* 42009fe6320SNavdeep Parhar * Called when the host's ARP layer makes a change to some entry that is loaded 42109fe6320SNavdeep Parhar * into the HW L2 table. 42209fe6320SNavdeep Parhar */ 42309fe6320SNavdeep Parhar void 424954712e8SJustin Hibbits t4_l2_update(struct toedev *tod, if_t ifp, struct sockaddr *sa, 42509fe6320SNavdeep Parhar uint8_t *lladdr, uint16_t vtag) 42609fe6320SNavdeep Parhar { 42709fe6320SNavdeep Parhar struct adapter *sc = tod->tod_softc; 42809fe6320SNavdeep Parhar struct l2t_entry *e; 42909fe6320SNavdeep Parhar struct l2t_data *d = sc->l2t; 4300a0a697cSNavdeep Parhar u_int hash; 43109fe6320SNavdeep Parhar 43209fe6320SNavdeep Parhar KASSERT(d != NULL, ("%s: no L2 table", __func__)); 43309fe6320SNavdeep Parhar 434954712e8SJustin Hibbits hash = l2_hash(d, sa, if_getindex(ifp)); 43509fe6320SNavdeep Parhar rw_rlock(&d->lock); 436*cd93fdeeSNavdeep Parhar if (__predict_false(d->l2t_stopped)) 437*cd93fdeeSNavdeep Parhar goto done; 43809fe6320SNavdeep Parhar for (e = d->l2tab[hash].first; e; e = e->next) { 4390a0a697cSNavdeep Parhar if (l2_cmp(sa, e) == 0 && e->ifp == ifp) { 44009fe6320SNavdeep Parhar mtx_lock(&e->lock); 44109fe6320SNavdeep Parhar if (atomic_load_acq_int(&e->refcnt)) 44209fe6320SNavdeep Parhar goto found; 44309fe6320SNavdeep Parhar e->state = L2T_STATE_STALE; 44409fe6320SNavdeep Parhar mtx_unlock(&e->lock); 44509fe6320SNavdeep Parhar break; 44609fe6320SNavdeep Parhar } 44709fe6320SNavdeep Parhar } 448*cd93fdeeSNavdeep 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