1*56b2bdd1SGireesh Nagabhushana /* 2*56b2bdd1SGireesh Nagabhushana * This file and its contents are supplied under the terms of the 3*56b2bdd1SGireesh Nagabhushana * Common Development and Distribution License ("CDDL"), version 1.0. 4*56b2bdd1SGireesh Nagabhushana * You may only use this file in accordance with the terms of version 5*56b2bdd1SGireesh Nagabhushana * 1.0 of the CDDL. 6*56b2bdd1SGireesh Nagabhushana * 7*56b2bdd1SGireesh Nagabhushana * A full copy of the text of the CDDL should have accompanied this 8*56b2bdd1SGireesh Nagabhushana * source. A copy of the CDDL is also available via the Internet at 9*56b2bdd1SGireesh Nagabhushana * http://www.illumos.org/license/CDDL. 10*56b2bdd1SGireesh Nagabhushana */ 11*56b2bdd1SGireesh Nagabhushana 12*56b2bdd1SGireesh Nagabhushana /* 13*56b2bdd1SGireesh Nagabhushana * This file is part of the Chelsio T4 support code. 14*56b2bdd1SGireesh Nagabhushana * 15*56b2bdd1SGireesh Nagabhushana * Copyright (C) 2010-2013 Chelsio Communications. All rights reserved. 16*56b2bdd1SGireesh Nagabhushana * 17*56b2bdd1SGireesh Nagabhushana * This program is distributed in the hope that it will be useful, but WITHOUT 18*56b2bdd1SGireesh Nagabhushana * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19*56b2bdd1SGireesh Nagabhushana * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this 20*56b2bdd1SGireesh Nagabhushana * release for licensing terms and conditions. 21*56b2bdd1SGireesh Nagabhushana */ 22*56b2bdd1SGireesh Nagabhushana 23*56b2bdd1SGireesh Nagabhushana #include <sys/ddi.h> 24*56b2bdd1SGireesh Nagabhushana #include <sys/sunddi.h> 25*56b2bdd1SGireesh Nagabhushana #include <sys/sunndi.h> 26*56b2bdd1SGireesh Nagabhushana #include <sys/atomic.h> 27*56b2bdd1SGireesh Nagabhushana #include <sys/dlpi.h> 28*56b2bdd1SGireesh Nagabhushana #include <sys/pattr.h> 29*56b2bdd1SGireesh Nagabhushana #include <sys/strsubr.h> 30*56b2bdd1SGireesh Nagabhushana #include <sys/stream.h> 31*56b2bdd1SGireesh Nagabhushana #include <sys/strsun.h> 32*56b2bdd1SGireesh Nagabhushana #include <sys/ethernet.h> 33*56b2bdd1SGireesh Nagabhushana #include <inet/ip.h> 34*56b2bdd1SGireesh Nagabhushana #include <inet/ipclassifier.h> 35*56b2bdd1SGireesh Nagabhushana #include <inet/tcp.h> 36*56b2bdd1SGireesh Nagabhushana 37*56b2bdd1SGireesh Nagabhushana #include "common/common.h" 38*56b2bdd1SGireesh Nagabhushana #include "common/t4_msg.h" 39*56b2bdd1SGireesh Nagabhushana #include "common/t4_regs.h" 40*56b2bdd1SGireesh Nagabhushana #include "common/t4_regs_values.h" 41*56b2bdd1SGireesh Nagabhushana #include "t4_l2t.h" 42*56b2bdd1SGireesh Nagabhushana 43*56b2bdd1SGireesh Nagabhushana /* identifies sync vs async L2T_WRITE_REQs */ 44*56b2bdd1SGireesh Nagabhushana #define S_SYNC_WR 12 45*56b2bdd1SGireesh Nagabhushana #define V_SYNC_WR(x) ((x) << S_SYNC_WR) 46*56b2bdd1SGireesh Nagabhushana #define F_SYNC_WR V_SYNC_WR(1) 47*56b2bdd1SGireesh Nagabhushana #define VLAN_NONE 0xfff 48*56b2bdd1SGireesh Nagabhushana 49*56b2bdd1SGireesh Nagabhushana /* 50*56b2bdd1SGireesh Nagabhushana * jhash.h: Jenkins hash support. 51*56b2bdd1SGireesh Nagabhushana * 52*56b2bdd1SGireesh Nagabhushana * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) 53*56b2bdd1SGireesh Nagabhushana * 54*56b2bdd1SGireesh Nagabhushana * http://burtleburtle.net/bob/hash/ 55*56b2bdd1SGireesh Nagabhushana * 56*56b2bdd1SGireesh Nagabhushana * These are the credits from Bob's sources: 57*56b2bdd1SGireesh Nagabhushana * 58*56b2bdd1SGireesh Nagabhushana * lookup2.c, by Bob Jenkins, December 1996, Public Domain. 59*56b2bdd1SGireesh Nagabhushana * hash(), hash2(), hash3, and mix() are externally useful functions. 60*56b2bdd1SGireesh Nagabhushana * Routines to test the hash are included if SELF_TEST is defined. 61*56b2bdd1SGireesh Nagabhushana * You can use this free for any purpose. It has no warranty. 62*56b2bdd1SGireesh Nagabhushana */ 63*56b2bdd1SGireesh Nagabhushana 64*56b2bdd1SGireesh Nagabhushana /* NOTE: Arguments are modified. */ 65*56b2bdd1SGireesh Nagabhushana #define __jhash_mix(a, b, c) \ 66*56b2bdd1SGireesh Nagabhushana { \ 67*56b2bdd1SGireesh Nagabhushana a -= b; a -= c; a ^= (c>>13); \ 68*56b2bdd1SGireesh Nagabhushana b -= c; b -= a; b ^= (a<<8); \ 69*56b2bdd1SGireesh Nagabhushana c -= a; c -= b; c ^= (b>>13); \ 70*56b2bdd1SGireesh Nagabhushana a -= b; a -= c; a ^= (c>>12); \ 71*56b2bdd1SGireesh Nagabhushana b -= c; b -= a; b ^= (a<<16); \ 72*56b2bdd1SGireesh Nagabhushana c -= a; c -= b; c ^= (b>>5); \ 73*56b2bdd1SGireesh Nagabhushana a -= b; a -= c; a ^= (c>>3); \ 74*56b2bdd1SGireesh Nagabhushana b -= c; b -= a; b ^= (a<<10); \ 75*56b2bdd1SGireesh Nagabhushana c -= a; c -= b; c ^= (b>>15); \ 76*56b2bdd1SGireesh Nagabhushana } 77*56b2bdd1SGireesh Nagabhushana 78*56b2bdd1SGireesh Nagabhushana /* The golden ration: an arbitrary value */ 79*56b2bdd1SGireesh Nagabhushana #define JHASH_GOLDEN_RATIO 0x9e3779b9 80*56b2bdd1SGireesh Nagabhushana 81*56b2bdd1SGireesh Nagabhushana /* 82*56b2bdd1SGireesh Nagabhushana * A special ultra-optimized versions that knows they are hashing exactly 83*56b2bdd1SGireesh Nagabhushana * 3, 2 or 1 word(s). 84*56b2bdd1SGireesh Nagabhushana * 85*56b2bdd1SGireesh Nagabhushana * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally 86*56b2bdd1SGireesh Nagabhushana * done at the end is not done here. 87*56b2bdd1SGireesh Nagabhushana */ 88*56b2bdd1SGireesh Nagabhushana static inline u32 89*56b2bdd1SGireesh Nagabhushana jhash_3words(u32 a, u32 b, u32 c, u32 initval) 90*56b2bdd1SGireesh Nagabhushana { 91*56b2bdd1SGireesh Nagabhushana a += JHASH_GOLDEN_RATIO; 92*56b2bdd1SGireesh Nagabhushana b += JHASH_GOLDEN_RATIO; 93*56b2bdd1SGireesh Nagabhushana c += initval; 94*56b2bdd1SGireesh Nagabhushana 95*56b2bdd1SGireesh Nagabhushana __jhash_mix(a, b, c); 96*56b2bdd1SGireesh Nagabhushana 97*56b2bdd1SGireesh Nagabhushana return (c); 98*56b2bdd1SGireesh Nagabhushana } 99*56b2bdd1SGireesh Nagabhushana 100*56b2bdd1SGireesh Nagabhushana static inline u32 101*56b2bdd1SGireesh Nagabhushana jhash_2words(u32 a, u32 b, u32 initval) 102*56b2bdd1SGireesh Nagabhushana { 103*56b2bdd1SGireesh Nagabhushana return (jhash_3words(a, b, 0, initval)); 104*56b2bdd1SGireesh Nagabhushana } 105*56b2bdd1SGireesh Nagabhushana 106*56b2bdd1SGireesh Nagabhushana #ifndef container_of 107*56b2bdd1SGireesh Nagabhushana #define container_of(p, s, f) ((s *)(((uint8_t *)(p)) - offsetof(s, f))) 108*56b2bdd1SGireesh Nagabhushana #endif 109*56b2bdd1SGireesh Nagabhushana 110*56b2bdd1SGireesh Nagabhushana #if defined(__GNUC__) 111*56b2bdd1SGireesh Nagabhushana #define likely(x) __builtin_expect((x), 1) 112*56b2bdd1SGireesh Nagabhushana #define unlikely(x) __builtin_expect((x), 0) 113*56b2bdd1SGireesh Nagabhushana #else 114*56b2bdd1SGireesh Nagabhushana #define likely(x) (x) 115*56b2bdd1SGireesh Nagabhushana #define unlikely(x) (x) 116*56b2bdd1SGireesh Nagabhushana #endif /* defined(__GNUC__) */ 117*56b2bdd1SGireesh Nagabhushana 118*56b2bdd1SGireesh Nagabhushana enum { 119*56b2bdd1SGireesh Nagabhushana L2T_STATE_VALID, /* entry is up to date */ 120*56b2bdd1SGireesh Nagabhushana L2T_STATE_STALE, /* entry may be used but needs revalidation */ 121*56b2bdd1SGireesh Nagabhushana L2T_STATE_RESOLVING, /* entry needs address resolution */ 122*56b2bdd1SGireesh Nagabhushana L2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */ 123*56b2bdd1SGireesh Nagabhushana 124*56b2bdd1SGireesh Nagabhushana /* when state is one of the below the entry is not hashed */ 125*56b2bdd1SGireesh Nagabhushana L2T_STATE_SWITCHING, /* entry is being used by a switching filter */ 126*56b2bdd1SGireesh Nagabhushana L2T_STATE_UNUSED /* entry not in use */ 127*56b2bdd1SGireesh Nagabhushana }; 128*56b2bdd1SGireesh Nagabhushana 129*56b2bdd1SGireesh Nagabhushana struct l2t_data { 130*56b2bdd1SGireesh Nagabhushana krwlock_t lock; 131*56b2bdd1SGireesh Nagabhushana volatile uint_t nfree; /* number of free entries */ 132*56b2bdd1SGireesh Nagabhushana struct l2t_entry *rover; /* starting point for next allocation */ 133*56b2bdd1SGireesh Nagabhushana struct l2t_entry l2tab[L2T_SIZE]; 134*56b2bdd1SGireesh Nagabhushana }; 135*56b2bdd1SGireesh Nagabhushana 136*56b2bdd1SGireesh Nagabhushana #define VLAN_NONE 0xfff 137*56b2bdd1SGireesh Nagabhushana #define SA(x) ((struct sockaddr *)(x)) 138*56b2bdd1SGireesh Nagabhushana #define SIN(x) ((struct sockaddr_in *)(x)) 139*56b2bdd1SGireesh Nagabhushana #define SINADDR(x) (SIN(x)->sin_addr.s_addr) 140*56b2bdd1SGireesh Nagabhushana #define atomic_read(x) atomic_add_int_nv(x, 0) 141*56b2bdd1SGireesh Nagabhushana /* 142*56b2bdd1SGireesh Nagabhushana * Allocate a free L2T entry. 143*56b2bdd1SGireesh Nagabhushana * Must be called with l2t_data.lockatomic_load_acq_int held. 144*56b2bdd1SGireesh Nagabhushana */ 145*56b2bdd1SGireesh Nagabhushana static struct l2t_entry * 146*56b2bdd1SGireesh Nagabhushana alloc_l2e(struct l2t_data *d) 147*56b2bdd1SGireesh Nagabhushana { 148*56b2bdd1SGireesh Nagabhushana struct l2t_entry *end, *e, **p; 149*56b2bdd1SGireesh Nagabhushana 150*56b2bdd1SGireesh Nagabhushana ASSERT(rw_write_held(&d->lock)); 151*56b2bdd1SGireesh Nagabhushana 152*56b2bdd1SGireesh Nagabhushana if (!atomic_read(&d->nfree)) 153*56b2bdd1SGireesh Nagabhushana return (NULL); 154*56b2bdd1SGireesh Nagabhushana 155*56b2bdd1SGireesh Nagabhushana /* there's definitely a free entry */ 156*56b2bdd1SGireesh Nagabhushana for (e = d->rover, end = &d->l2tab[L2T_SIZE]; e != end; ++e) 157*56b2bdd1SGireesh Nagabhushana if (atomic_read(&e->refcnt) == 0) 158*56b2bdd1SGireesh Nagabhushana goto found; 159*56b2bdd1SGireesh Nagabhushana 160*56b2bdd1SGireesh Nagabhushana for (e = d->l2tab; atomic_read(&e->refcnt); ++e) 161*56b2bdd1SGireesh Nagabhushana /* */; 162*56b2bdd1SGireesh Nagabhushana found: 163*56b2bdd1SGireesh Nagabhushana d->rover = e + 1; 164*56b2bdd1SGireesh Nagabhushana atomic_dec_uint(&d->nfree); 165*56b2bdd1SGireesh Nagabhushana 166*56b2bdd1SGireesh Nagabhushana /* 167*56b2bdd1SGireesh Nagabhushana * The entry we found may be an inactive entry that is 168*56b2bdd1SGireesh Nagabhushana * presently in the hash table. We need to remove it. 169*56b2bdd1SGireesh Nagabhushana */ 170*56b2bdd1SGireesh Nagabhushana if (e->state < L2T_STATE_SWITCHING) { 171*56b2bdd1SGireesh Nagabhushana for (p = &d->l2tab[e->hash].first; *p; p = &(*p)->next) { 172*56b2bdd1SGireesh Nagabhushana if (*p == e) { 173*56b2bdd1SGireesh Nagabhushana *p = e->next; 174*56b2bdd1SGireesh Nagabhushana e->next = NULL; 175*56b2bdd1SGireesh Nagabhushana break; 176*56b2bdd1SGireesh Nagabhushana } 177*56b2bdd1SGireesh Nagabhushana } 178*56b2bdd1SGireesh Nagabhushana } 179*56b2bdd1SGireesh Nagabhushana 180*56b2bdd1SGireesh Nagabhushana e->state = L2T_STATE_UNUSED; 181*56b2bdd1SGireesh Nagabhushana return (e); 182*56b2bdd1SGireesh Nagabhushana } 183*56b2bdd1SGireesh Nagabhushana 184*56b2bdd1SGireesh Nagabhushana /* 185*56b2bdd1SGireesh Nagabhushana * Write an L2T entry. Must be called with the entry locked. 186*56b2bdd1SGireesh Nagabhushana * The write may be synchronous or asynchronous. 187*56b2bdd1SGireesh Nagabhushana */ 188*56b2bdd1SGireesh Nagabhushana static int 189*56b2bdd1SGireesh Nagabhushana write_l2e(adapter_t *sc, struct l2t_entry *e, int sync) 190*56b2bdd1SGireesh Nagabhushana { 191*56b2bdd1SGireesh Nagabhushana mblk_t *m; 192*56b2bdd1SGireesh Nagabhushana struct cpl_l2t_write_req *req; 193*56b2bdd1SGireesh Nagabhushana 194*56b2bdd1SGireesh Nagabhushana ASSERT(MUTEX_HELD(&e->lock)); 195*56b2bdd1SGireesh Nagabhushana 196*56b2bdd1SGireesh Nagabhushana if ((m = allocb(sizeof (*req), BPRI_HI)) == NULL) 197*56b2bdd1SGireesh Nagabhushana return (ENOMEM); 198*56b2bdd1SGireesh Nagabhushana 199*56b2bdd1SGireesh Nagabhushana /* LINTED: E_BAD_PTR_CAST_ALIGN */ 200*56b2bdd1SGireesh Nagabhushana req = (struct cpl_l2t_write_req *)m->b_wptr; 201*56b2bdd1SGireesh Nagabhushana 202*56b2bdd1SGireesh Nagabhushana /* LINTED: E_CONSTANT_CONDITION */ 203*56b2bdd1SGireesh Nagabhushana INIT_TP_WR(req, 0); 204*56b2bdd1SGireesh Nagabhushana OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx | 205*56b2bdd1SGireesh Nagabhushana V_SYNC_WR(sync) | V_TID_QID(sc->sge.fwq.abs_id))); 206*56b2bdd1SGireesh Nagabhushana req->params = htons(V_L2T_W_PORT(e->lport) | V_L2T_W_NOREPLY(!sync)); 207*56b2bdd1SGireesh Nagabhushana req->l2t_idx = htons(e->idx); 208*56b2bdd1SGireesh Nagabhushana req->vlan = htons(e->vlan); 209*56b2bdd1SGireesh Nagabhushana (void) memcpy(req->dst_mac, e->dmac, sizeof (req->dst_mac)); 210*56b2bdd1SGireesh Nagabhushana 211*56b2bdd1SGireesh Nagabhushana m->b_wptr += sizeof (*req); 212*56b2bdd1SGireesh Nagabhushana 213*56b2bdd1SGireesh Nagabhushana (void) t4_mgmt_tx(sc, m); 214*56b2bdd1SGireesh Nagabhushana 215*56b2bdd1SGireesh Nagabhushana if (sync && e->state != L2T_STATE_SWITCHING) 216*56b2bdd1SGireesh Nagabhushana e->state = L2T_STATE_SYNC_WRITE; 217*56b2bdd1SGireesh Nagabhushana 218*56b2bdd1SGireesh Nagabhushana return (0); 219*56b2bdd1SGireesh Nagabhushana } 220*56b2bdd1SGireesh Nagabhushana 221*56b2bdd1SGireesh Nagabhushana struct l2t_data * 222*56b2bdd1SGireesh Nagabhushana t4_init_l2t(struct adapter *sc) 223*56b2bdd1SGireesh Nagabhushana { 224*56b2bdd1SGireesh Nagabhushana int i; 225*56b2bdd1SGireesh Nagabhushana struct l2t_data *d; 226*56b2bdd1SGireesh Nagabhushana 227*56b2bdd1SGireesh Nagabhushana d = kmem_zalloc(sizeof (*d), KM_SLEEP); 228*56b2bdd1SGireesh Nagabhushana 229*56b2bdd1SGireesh Nagabhushana d->rover = d->l2tab; 230*56b2bdd1SGireesh Nagabhushana (void) atomic_swap_uint(&d->nfree, L2T_SIZE); 231*56b2bdd1SGireesh Nagabhushana rw_init(&d->lock, NULL, RW_DRIVER, NULL); 232*56b2bdd1SGireesh Nagabhushana 233*56b2bdd1SGireesh Nagabhushana for (i = 0; i < L2T_SIZE; i++) { 234*56b2bdd1SGireesh Nagabhushana /* LINTED: E_ASSIGN_NARROW_CONV */ 235*56b2bdd1SGireesh Nagabhushana d->l2tab[i].idx = i; 236*56b2bdd1SGireesh Nagabhushana d->l2tab[i].state = L2T_STATE_UNUSED; 237*56b2bdd1SGireesh Nagabhushana mutex_init(&d->l2tab[i].lock, NULL, MUTEX_DRIVER, NULL); 238*56b2bdd1SGireesh Nagabhushana (void) atomic_swap_uint(&d->l2tab[i].refcnt, 0); 239*56b2bdd1SGireesh Nagabhushana } 240*56b2bdd1SGireesh Nagabhushana 241*56b2bdd1SGireesh Nagabhushana (void) t4_register_cpl_handler(sc, CPL_L2T_WRITE_RPL, do_l2t_write_rpl); 242*56b2bdd1SGireesh Nagabhushana 243*56b2bdd1SGireesh Nagabhushana return (d); 244*56b2bdd1SGireesh Nagabhushana } 245*56b2bdd1SGireesh Nagabhushana 246*56b2bdd1SGireesh Nagabhushana int 247*56b2bdd1SGireesh Nagabhushana t4_free_l2t(struct l2t_data *d) 248*56b2bdd1SGireesh Nagabhushana { 249*56b2bdd1SGireesh Nagabhushana int i; 250*56b2bdd1SGireesh Nagabhushana 251*56b2bdd1SGireesh Nagabhushana for (i = 0; i < L2T_SIZE; i++) 252*56b2bdd1SGireesh Nagabhushana mutex_destroy(&d->l2tab[i].lock); 253*56b2bdd1SGireesh Nagabhushana rw_destroy(&d->lock); 254*56b2bdd1SGireesh Nagabhushana kmem_free(d, sizeof (*d)); 255*56b2bdd1SGireesh Nagabhushana 256*56b2bdd1SGireesh Nagabhushana return (0); 257*56b2bdd1SGireesh Nagabhushana } 258*56b2bdd1SGireesh Nagabhushana 259*56b2bdd1SGireesh Nagabhushana #ifndef TCP_OFFLOAD_DISABLE 260*56b2bdd1SGireesh Nagabhushana static inline void 261*56b2bdd1SGireesh Nagabhushana l2t_hold(struct l2t_data *d, struct l2t_entry *e) 262*56b2bdd1SGireesh Nagabhushana { 263*56b2bdd1SGireesh Nagabhushana if (atomic_inc_uint_nv(&e->refcnt) == 1) /* 0 -> 1 transition */ 264*56b2bdd1SGireesh Nagabhushana atomic_dec_uint(&d->nfree); 265*56b2bdd1SGireesh Nagabhushana } 266*56b2bdd1SGireesh Nagabhushana 267*56b2bdd1SGireesh Nagabhushana /* 268*56b2bdd1SGireesh Nagabhushana * To avoid having to check address families we do not allow v4 and v6 269*56b2bdd1SGireesh Nagabhushana * neighbors to be on the same hash chain. We keep v4 entries in the first 270*56b2bdd1SGireesh Nagabhushana * half of available hash buckets and v6 in the second. 271*56b2bdd1SGireesh Nagabhushana */ 272*56b2bdd1SGireesh Nagabhushana enum { 273*56b2bdd1SGireesh Nagabhushana L2T_SZ_HALF = L2T_SIZE / 2, 274*56b2bdd1SGireesh Nagabhushana L2T_HASH_MASK = L2T_SZ_HALF - 1 275*56b2bdd1SGireesh Nagabhushana }; 276*56b2bdd1SGireesh Nagabhushana 277*56b2bdd1SGireesh Nagabhushana static inline unsigned int 278*56b2bdd1SGireesh Nagabhushana arp_hash(const uint32_t *key, int ifindex) 279*56b2bdd1SGireesh Nagabhushana { 280*56b2bdd1SGireesh Nagabhushana return (jhash_2words(*key, ifindex, 0) & L2T_HASH_MASK); 281*56b2bdd1SGireesh Nagabhushana } 282*56b2bdd1SGireesh Nagabhushana 283*56b2bdd1SGireesh Nagabhushana static inline unsigned int 284*56b2bdd1SGireesh Nagabhushana ipv6_hash(const uint32_t *key, int ifindex) 285*56b2bdd1SGireesh Nagabhushana { 286*56b2bdd1SGireesh Nagabhushana uint32_t xor = key[0] ^ key[1] ^ key[2] ^ key[3]; 287*56b2bdd1SGireesh Nagabhushana 288*56b2bdd1SGireesh Nagabhushana return (L2T_SZ_HALF + (jhash_2words(xor, ifindex, 0) & L2T_HASH_MASK)); 289*56b2bdd1SGireesh Nagabhushana } 290*56b2bdd1SGireesh Nagabhushana 291*56b2bdd1SGireesh Nagabhushana static inline unsigned int 292*56b2bdd1SGireesh Nagabhushana addr_hash(const uint32_t *addr, int addr_len, int ifindex) 293*56b2bdd1SGireesh Nagabhushana { 294*56b2bdd1SGireesh Nagabhushana return (addr_len == 4 ? arp_hash(addr, ifindex) : 295*56b2bdd1SGireesh Nagabhushana ipv6_hash(addr, ifindex)); 296*56b2bdd1SGireesh Nagabhushana } 297*56b2bdd1SGireesh Nagabhushana 298*56b2bdd1SGireesh Nagabhushana /* 299*56b2bdd1SGireesh Nagabhushana * Checks if an L2T entry is for the given IP/IPv6 address. It does not check 300*56b2bdd1SGireesh Nagabhushana * whether the L2T entry and the address are of the same address family. 301*56b2bdd1SGireesh Nagabhushana * Callers ensure an address is only checked against L2T entries of the same 302*56b2bdd1SGireesh Nagabhushana * family, something made trivial by the separation of IP and IPv6 hash chains 303*56b2bdd1SGireesh Nagabhushana * mentioned above. Returns 0 if there's a match, 304*56b2bdd1SGireesh Nagabhushana */ 305*56b2bdd1SGireesh Nagabhushana static inline int 306*56b2bdd1SGireesh Nagabhushana addreq(const struct l2t_entry *e, const uint32_t *addr) 307*56b2bdd1SGireesh Nagabhushana { 308*56b2bdd1SGireesh Nagabhushana if (e->v6 != 0) 309*56b2bdd1SGireesh Nagabhushana return ((e->addr[0] ^ addr[0]) | (e->addr[1] ^ addr[1]) | 310*56b2bdd1SGireesh Nagabhushana (e->addr[2] ^ addr[2]) | (e->addr[3] ^ addr[3])); 311*56b2bdd1SGireesh Nagabhushana return (e->addr[0] ^ addr[0]); 312*56b2bdd1SGireesh Nagabhushana } 313*56b2bdd1SGireesh Nagabhushana 314*56b2bdd1SGireesh Nagabhushana /* 315*56b2bdd1SGireesh Nagabhushana * Add a packet to an L2T entry's queue of packets awaiting resolution. 316*56b2bdd1SGireesh Nagabhushana * Must be called with the entry's lock held. 317*56b2bdd1SGireesh Nagabhushana */ 318*56b2bdd1SGireesh Nagabhushana static inline void 319*56b2bdd1SGireesh Nagabhushana arpq_enqueue(struct l2t_entry *e, mblk_t *m) 320*56b2bdd1SGireesh Nagabhushana { 321*56b2bdd1SGireesh Nagabhushana ASSERT(MUTEX_HELD(&e->lock)); 322*56b2bdd1SGireesh Nagabhushana 323*56b2bdd1SGireesh Nagabhushana ASSERT(m->b_next == NULL); 324*56b2bdd1SGireesh Nagabhushana if (e->arpq_head != NULL) 325*56b2bdd1SGireesh Nagabhushana e->arpq_tail->b_next = m; 326*56b2bdd1SGireesh Nagabhushana else 327*56b2bdd1SGireesh Nagabhushana e->arpq_head = m; 328*56b2bdd1SGireesh Nagabhushana e->arpq_tail = m; 329*56b2bdd1SGireesh Nagabhushana } 330*56b2bdd1SGireesh Nagabhushana 331*56b2bdd1SGireesh Nagabhushana static inline void 332*56b2bdd1SGireesh Nagabhushana send_pending(struct adapter *sc, struct l2t_entry *e) 333*56b2bdd1SGireesh Nagabhushana { 334*56b2bdd1SGireesh Nagabhushana mblk_t *m, *next; 335*56b2bdd1SGireesh Nagabhushana 336*56b2bdd1SGireesh Nagabhushana ASSERT(MUTEX_HELD(&e->lock)); 337*56b2bdd1SGireesh Nagabhushana 338*56b2bdd1SGireesh Nagabhushana for (m = e->arpq_head; m; m = next) { 339*56b2bdd1SGireesh Nagabhushana next = m->b_next; 340*56b2bdd1SGireesh Nagabhushana m->b_next = NULL; 341*56b2bdd1SGireesh Nagabhushana (void) t4_wrq_tx(sc, MBUF_EQ(m), m); 342*56b2bdd1SGireesh Nagabhushana } 343*56b2bdd1SGireesh Nagabhushana e->arpq_head = e->arpq_tail = NULL; 344*56b2bdd1SGireesh Nagabhushana } 345*56b2bdd1SGireesh Nagabhushana 346*56b2bdd1SGireesh Nagabhushana int 347*56b2bdd1SGireesh Nagabhushana t4_l2t_send(struct adapter *sc, mblk_t *m, struct l2t_entry *e) 348*56b2bdd1SGireesh Nagabhushana { 349*56b2bdd1SGireesh Nagabhushana sin_t *sin; 350*56b2bdd1SGireesh Nagabhushana ip2mac_t ip2m; 351*56b2bdd1SGireesh Nagabhushana 352*56b2bdd1SGireesh Nagabhushana if (e->v6 != 0) 353*56b2bdd1SGireesh Nagabhushana ASSERT(0); 354*56b2bdd1SGireesh Nagabhushana again: 355*56b2bdd1SGireesh Nagabhushana switch (e->state) { 356*56b2bdd1SGireesh Nagabhushana case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ 357*56b2bdd1SGireesh Nagabhushana 358*56b2bdd1SGireesh Nagabhushana /* Fall through */ 359*56b2bdd1SGireesh Nagabhushana case L2T_STATE_VALID: /* fast-path, send the packet on */ 360*56b2bdd1SGireesh Nagabhushana (void) t4_wrq_tx(sc, MBUF_EQ(m), m); 361*56b2bdd1SGireesh Nagabhushana return (0); 362*56b2bdd1SGireesh Nagabhushana 363*56b2bdd1SGireesh Nagabhushana case L2T_STATE_RESOLVING: 364*56b2bdd1SGireesh Nagabhushana case L2T_STATE_SYNC_WRITE: 365*56b2bdd1SGireesh Nagabhushana mutex_enter(&e->lock); 366*56b2bdd1SGireesh Nagabhushana if (e->state != L2T_STATE_SYNC_WRITE && 367*56b2bdd1SGireesh Nagabhushana e->state != L2T_STATE_RESOLVING) { 368*56b2bdd1SGireesh Nagabhushana /* state changed by the time we got here */ 369*56b2bdd1SGireesh Nagabhushana mutex_exit(&e->lock); 370*56b2bdd1SGireesh Nagabhushana goto again; 371*56b2bdd1SGireesh Nagabhushana } 372*56b2bdd1SGireesh Nagabhushana arpq_enqueue(e, m); 373*56b2bdd1SGireesh Nagabhushana mutex_exit(&e->lock); 374*56b2bdd1SGireesh Nagabhushana 375*56b2bdd1SGireesh Nagabhushana bzero(&ip2m, sizeof (ip2m)); 376*56b2bdd1SGireesh Nagabhushana sin = (sin_t *)&ip2m.ip2mac_pa; 377*56b2bdd1SGireesh Nagabhushana sin->sin_family = AF_INET; 378*56b2bdd1SGireesh Nagabhushana sin->sin_addr.s_addr = e->in_addr; 379*56b2bdd1SGireesh Nagabhushana ip2m.ip2mac_ifindex = e->ifindex; 380*56b2bdd1SGireesh Nagabhushana 381*56b2bdd1SGireesh Nagabhushana if (e->state == L2T_STATE_RESOLVING) { 382*56b2bdd1SGireesh Nagabhushana (void) ip2mac(IP2MAC_RESOLVE, &ip2m, t4_l2t_update, e, 383*56b2bdd1SGireesh Nagabhushana 0); 384*56b2bdd1SGireesh Nagabhushana if (ip2m.ip2mac_err == EINPROGRESS) 385*56b2bdd1SGireesh Nagabhushana ASSERT(0); 386*56b2bdd1SGireesh Nagabhushana else if (ip2m.ip2mac_err == 0) 387*56b2bdd1SGireesh Nagabhushana t4_l2t_update(&ip2m, e); 388*56b2bdd1SGireesh Nagabhushana else 389*56b2bdd1SGireesh Nagabhushana ASSERT(0); 390*56b2bdd1SGireesh Nagabhushana } 391*56b2bdd1SGireesh Nagabhushana } 392*56b2bdd1SGireesh Nagabhushana 393*56b2bdd1SGireesh Nagabhushana return (0); 394*56b2bdd1SGireesh Nagabhushana } 395*56b2bdd1SGireesh Nagabhushana 396*56b2bdd1SGireesh Nagabhushana /* 397*56b2bdd1SGireesh Nagabhushana * Called when an L2T entry has no more users. The entry is left in the hash 398*56b2bdd1SGireesh Nagabhushana * table since it is likely to be reused but we also bump nfree to indicate 399*56b2bdd1SGireesh Nagabhushana * that the entry can be reallocated for a different neighbor. We also drop 400*56b2bdd1SGireesh Nagabhushana * the existing neighbor reference in case the neighbor is going away and is 401*56b2bdd1SGireesh Nagabhushana * waiting on our reference. 402*56b2bdd1SGireesh Nagabhushana * 403*56b2bdd1SGireesh Nagabhushana * Because entries can be reallocated to other neighbors once their ref count 404*56b2bdd1SGireesh Nagabhushana * drops to 0 we need to take the entry's lock to avoid races with a new 405*56b2bdd1SGireesh Nagabhushana * incarnation. 406*56b2bdd1SGireesh Nagabhushana */ 407*56b2bdd1SGireesh Nagabhushana static void 408*56b2bdd1SGireesh Nagabhushana t4_l2e_free(struct l2t_entry *e) 409*56b2bdd1SGireesh Nagabhushana { 410*56b2bdd1SGireesh Nagabhushana struct l2t_data *d; 411*56b2bdd1SGireesh Nagabhushana 412*56b2bdd1SGireesh Nagabhushana mutex_enter(&e->lock); 413*56b2bdd1SGireesh Nagabhushana /* LINTED: E_NOP_IF_STMT */ 414*56b2bdd1SGireesh Nagabhushana if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ 415*56b2bdd1SGireesh Nagabhushana /* 416*56b2bdd1SGireesh Nagabhushana * Don't need to worry about the arpq, an L2T entry can't be 417*56b2bdd1SGireesh Nagabhushana * released if any packets are waiting for resolution as we 418*56b2bdd1SGireesh Nagabhushana * need to be able to communicate with the device to close a 419*56b2bdd1SGireesh Nagabhushana * connection. 420*56b2bdd1SGireesh Nagabhushana */ 421*56b2bdd1SGireesh Nagabhushana } 422*56b2bdd1SGireesh Nagabhushana mutex_exit(&e->lock); 423*56b2bdd1SGireesh Nagabhushana 424*56b2bdd1SGireesh Nagabhushana d = container_of(e, struct l2t_data, l2tab[e->idx]); 425*56b2bdd1SGireesh Nagabhushana atomic_add_int(&d->nfree, 1); 426*56b2bdd1SGireesh Nagabhushana 427*56b2bdd1SGireesh Nagabhushana } 428*56b2bdd1SGireesh Nagabhushana 429*56b2bdd1SGireesh Nagabhushana void 430*56b2bdd1SGireesh Nagabhushana t4_l2t_release(struct l2t_entry *e) 431*56b2bdd1SGireesh Nagabhushana { 432*56b2bdd1SGireesh Nagabhushana if (atomic_dec_uint_nv(&e->refcnt) == 0) 433*56b2bdd1SGireesh Nagabhushana t4_l2e_free(e); 434*56b2bdd1SGireesh Nagabhushana } 435*56b2bdd1SGireesh Nagabhushana 436*56b2bdd1SGireesh Nagabhushana /* ARGSUSED */ 437*56b2bdd1SGireesh Nagabhushana int 438*56b2bdd1SGireesh Nagabhushana do_l2t_write_rpl(struct sge_iq *iq, const struct rss_header *rss, mblk_t *m) 439*56b2bdd1SGireesh Nagabhushana { 440*56b2bdd1SGireesh Nagabhushana struct adapter *sc = iq->adapter; 441*56b2bdd1SGireesh Nagabhushana const struct cpl_l2t_write_rpl *rpl = (const void *)(rss + 1); 442*56b2bdd1SGireesh Nagabhushana unsigned int tid = GET_TID(rpl); 443*56b2bdd1SGireesh Nagabhushana unsigned int idx = tid & (L2T_SIZE - 1); 444*56b2bdd1SGireesh Nagabhushana 445*56b2bdd1SGireesh Nagabhushana if (likely(rpl->status != CPL_ERR_NONE)) { 446*56b2bdd1SGireesh Nagabhushana cxgb_printf(sc->dip, CE_WARN, 447*56b2bdd1SGireesh Nagabhushana "Unexpected L2T_WRITE_RPL status %u for entry %u", 448*56b2bdd1SGireesh Nagabhushana rpl->status, idx); 449*56b2bdd1SGireesh Nagabhushana return (-EINVAL); 450*56b2bdd1SGireesh Nagabhushana } 451*56b2bdd1SGireesh Nagabhushana 452*56b2bdd1SGireesh Nagabhushana if (tid & F_SYNC_WR) { 453*56b2bdd1SGireesh Nagabhushana struct l2t_entry *e = &sc->l2t->l2tab[idx]; 454*56b2bdd1SGireesh Nagabhushana 455*56b2bdd1SGireesh Nagabhushana mutex_enter(&e->lock); 456*56b2bdd1SGireesh Nagabhushana if (e->state != L2T_STATE_SWITCHING) { 457*56b2bdd1SGireesh Nagabhushana send_pending(sc, e); 458*56b2bdd1SGireesh Nagabhushana e->state = L2T_STATE_VALID; 459*56b2bdd1SGireesh Nagabhushana } 460*56b2bdd1SGireesh Nagabhushana mutex_exit(&e->lock); 461*56b2bdd1SGireesh Nagabhushana } 462*56b2bdd1SGireesh Nagabhushana 463*56b2bdd1SGireesh Nagabhushana return (0); 464*56b2bdd1SGireesh Nagabhushana } 465*56b2bdd1SGireesh Nagabhushana 466*56b2bdd1SGireesh Nagabhushana /* 467*56b2bdd1SGireesh Nagabhushana * The TOE wants an L2 table entry that it can use to reach the next hop over 468*56b2bdd1SGireesh Nagabhushana * the specified port. Produce such an entry - create one if needed. 469*56b2bdd1SGireesh Nagabhushana * 470*56b2bdd1SGireesh Nagabhushana * Note that the ifnet could be a pseudo-device like if_vlan, if_lagg, etc. on 471*56b2bdd1SGireesh Nagabhushana * top of the real cxgbe interface. 472*56b2bdd1SGireesh Nagabhushana */ 473*56b2bdd1SGireesh Nagabhushana struct l2t_entry * 474*56b2bdd1SGireesh Nagabhushana t4_l2t_get(struct port_info *pi, conn_t *connp) 475*56b2bdd1SGireesh Nagabhushana { 476*56b2bdd1SGireesh Nagabhushana struct l2t_entry *e; 477*56b2bdd1SGireesh Nagabhushana struct l2t_data *d = pi->adapter->l2t; 478*56b2bdd1SGireesh Nagabhushana int addr_len; 479*56b2bdd1SGireesh Nagabhushana uint32_t *addr; 480*56b2bdd1SGireesh Nagabhushana int hash; 481*56b2bdd1SGireesh Nagabhushana int index = \ 482*56b2bdd1SGireesh Nagabhushana connp->conn_ixa->ixa_ire->ire_ill->ill_phyint->phyint_ifindex; 483*56b2bdd1SGireesh Nagabhushana unsigned int smt_idx = pi->port_id; 484*56b2bdd1SGireesh Nagabhushana addr = (uint32_t *)&connp->conn_faddr_v4; 485*56b2bdd1SGireesh Nagabhushana addr_len = sizeof (connp->conn_faddr_v4); 486*56b2bdd1SGireesh Nagabhushana 487*56b2bdd1SGireesh Nagabhushana hash = addr_hash(addr, addr_len, index); 488*56b2bdd1SGireesh Nagabhushana 489*56b2bdd1SGireesh Nagabhushana rw_enter(&d->lock, RW_WRITER); 490*56b2bdd1SGireesh Nagabhushana for (e = d->l2tab[hash].first; e; e = e->next) { 491*56b2bdd1SGireesh Nagabhushana if (!addreq(e, addr) && e->smt_idx == smt_idx) { 492*56b2bdd1SGireesh Nagabhushana l2t_hold(d, e); 493*56b2bdd1SGireesh Nagabhushana goto done; 494*56b2bdd1SGireesh Nagabhushana } 495*56b2bdd1SGireesh Nagabhushana } 496*56b2bdd1SGireesh Nagabhushana 497*56b2bdd1SGireesh Nagabhushana /* Need to allocate a new entry */ 498*56b2bdd1SGireesh Nagabhushana e = alloc_l2e(d); 499*56b2bdd1SGireesh Nagabhushana if (e != NULL) { 500*56b2bdd1SGireesh Nagabhushana mutex_enter(&e->lock); /* avoid race with t4_l2t_free */ 501*56b2bdd1SGireesh Nagabhushana e->state = L2T_STATE_RESOLVING; 502*56b2bdd1SGireesh Nagabhushana (void) memcpy(e->addr, addr, addr_len); 503*56b2bdd1SGireesh Nagabhushana e->in_addr = connp->conn_faddr_v4; 504*56b2bdd1SGireesh Nagabhushana e->ifindex = index; 505*56b2bdd1SGireesh Nagabhushana /* LINTED: E_ASSIGN_NARROW_CONV */ 506*56b2bdd1SGireesh Nagabhushana e->smt_idx = smt_idx; 507*56b2bdd1SGireesh Nagabhushana /* LINTED: E_ASSIGN_NARROW_CONV */ 508*56b2bdd1SGireesh Nagabhushana e->hash = hash; 509*56b2bdd1SGireesh Nagabhushana e->lport = pi->lport; 510*56b2bdd1SGireesh Nagabhushana e->arpq_head = e->arpq_tail = NULL; 511*56b2bdd1SGireesh Nagabhushana e->v6 = (addr_len == 16); 512*56b2bdd1SGireesh Nagabhushana e->sc = pi->adapter; 513*56b2bdd1SGireesh Nagabhushana (void) atomic_swap_uint(&e->refcnt, 1); 514*56b2bdd1SGireesh Nagabhushana e->vlan = VLAN_NONE; 515*56b2bdd1SGireesh Nagabhushana e->next = d->l2tab[hash].first; 516*56b2bdd1SGireesh Nagabhushana d->l2tab[hash].first = e; 517*56b2bdd1SGireesh Nagabhushana mutex_exit(&e->lock); 518*56b2bdd1SGireesh Nagabhushana } else { 519*56b2bdd1SGireesh Nagabhushana ASSERT(0); 520*56b2bdd1SGireesh Nagabhushana } 521*56b2bdd1SGireesh Nagabhushana 522*56b2bdd1SGireesh Nagabhushana done: 523*56b2bdd1SGireesh Nagabhushana rw_exit(&d->lock); 524*56b2bdd1SGireesh Nagabhushana return (e); 525*56b2bdd1SGireesh Nagabhushana } 526*56b2bdd1SGireesh Nagabhushana 527*56b2bdd1SGireesh Nagabhushana /* 528*56b2bdd1SGireesh Nagabhushana * Called when the host's neighbor layer makes a change to some entry that is 529*56b2bdd1SGireesh Nagabhushana * loaded into the HW L2 table. 530*56b2bdd1SGireesh Nagabhushana */ 531*56b2bdd1SGireesh Nagabhushana void 532*56b2bdd1SGireesh Nagabhushana t4_l2t_update(ip2mac_t *ip2macp, void *arg) 533*56b2bdd1SGireesh Nagabhushana { 534*56b2bdd1SGireesh Nagabhushana struct l2t_entry *e = (struct l2t_entry *)arg; 535*56b2bdd1SGireesh Nagabhushana struct adapter *sc = e->sc; 536*56b2bdd1SGireesh Nagabhushana uchar_t *cp; 537*56b2bdd1SGireesh Nagabhushana 538*56b2bdd1SGireesh Nagabhushana if (ip2macp->ip2mac_err != 0) { 539*56b2bdd1SGireesh Nagabhushana ASSERT(0); /* Don't know what to do. Needs to be investigated */ 540*56b2bdd1SGireesh Nagabhushana } 541*56b2bdd1SGireesh Nagabhushana 542*56b2bdd1SGireesh Nagabhushana mutex_enter(&e->lock); 543*56b2bdd1SGireesh Nagabhushana if (atomic_read(&e->refcnt) != 0) 544*56b2bdd1SGireesh Nagabhushana goto found; 545*56b2bdd1SGireesh Nagabhushana e->state = L2T_STATE_STALE; 546*56b2bdd1SGireesh Nagabhushana mutex_exit(&e->lock); 547*56b2bdd1SGireesh Nagabhushana 548*56b2bdd1SGireesh Nagabhushana /* The TOE has no interest in this LLE */ 549*56b2bdd1SGireesh Nagabhushana return; 550*56b2bdd1SGireesh Nagabhushana 551*56b2bdd1SGireesh Nagabhushana found: 552*56b2bdd1SGireesh Nagabhushana if (atomic_read(&e->refcnt) != 0) { 553*56b2bdd1SGireesh Nagabhushana 554*56b2bdd1SGireesh Nagabhushana /* Entry is referenced by at least 1 offloaded connection. */ 555*56b2bdd1SGireesh Nagabhushana 556*56b2bdd1SGireesh Nagabhushana cp = (uchar_t *)LLADDR(&ip2macp->ip2mac_ha); 557*56b2bdd1SGireesh Nagabhushana bcopy(cp, e->dmac, 6); 558*56b2bdd1SGireesh Nagabhushana (void) write_l2e(sc, e, 1); 559*56b2bdd1SGireesh Nagabhushana e->state = L2T_STATE_VALID; 560*56b2bdd1SGireesh Nagabhushana 561*56b2bdd1SGireesh Nagabhushana } 562*56b2bdd1SGireesh Nagabhushana mutex_exit(&e->lock); 563*56b2bdd1SGireesh Nagabhushana } 564*56b2bdd1SGireesh Nagabhushana #endif 565