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