xref: /freebsd/sys/dev/mana/mana_en.c (revision 47f4137e44b8079c7784604d220a298db07a19a1)
1ce110ea1SWei Hu /*-
2ce110ea1SWei Hu  * SPDX-License-Identifier: BSD-2-Clause
3ce110ea1SWei Hu  *
4ce110ea1SWei Hu  * Copyright (c) 2021 Microsoft Corp.
5ce110ea1SWei Hu  * All rights reserved.
6ce110ea1SWei Hu  *
7ce110ea1SWei Hu  * Redistribution and use in source and binary forms, with or without
8ce110ea1SWei Hu  * modification, are permitted provided that the following conditions
9ce110ea1SWei Hu  * are met:
10ce110ea1SWei Hu  *
11ce110ea1SWei Hu  * 1. Redistributions of source code must retain the above copyright
12ce110ea1SWei Hu  *    notice, this list of conditions and the following disclaimer.
13ce110ea1SWei Hu  *
14ce110ea1SWei Hu  * 2. Redistributions in binary form must reproduce the above copyright
15ce110ea1SWei Hu  *    notice, this list of conditions and the following disclaimer in the
16ce110ea1SWei Hu  *    documentation and/or other materials provided with the distribution.
17ce110ea1SWei Hu  *
18ce110ea1SWei Hu  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19ce110ea1SWei Hu  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20ce110ea1SWei Hu  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21ce110ea1SWei Hu  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22ce110ea1SWei Hu  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23ce110ea1SWei Hu  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24ce110ea1SWei Hu  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25ce110ea1SWei Hu  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26ce110ea1SWei Hu  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27ce110ea1SWei Hu  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28ce110ea1SWei Hu  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29ce110ea1SWei Hu  */
30fdafd315SWarner Losh 
31ce110ea1SWei Hu #include <sys/param.h>
32ce110ea1SWei Hu #include <sys/systm.h>
33ce110ea1SWei Hu #include <sys/bus.h>
34ce110ea1SWei Hu #include <sys/kernel.h>
35ce110ea1SWei Hu #include <sys/kthread.h>
36ce110ea1SWei Hu #include <sys/malloc.h>
37ce110ea1SWei Hu #include <sys/mbuf.h>
38ce110ea1SWei Hu #include <sys/smp.h>
39ce110ea1SWei Hu #include <sys/socket.h>
40ce110ea1SWei Hu #include <sys/sockio.h>
41ce110ea1SWei Hu #include <sys/time.h>
42ce110ea1SWei Hu #include <sys/eventhandler.h>
43ce110ea1SWei Hu 
44ce110ea1SWei Hu #include <machine/bus.h>
45ce110ea1SWei Hu #include <machine/resource.h>
46ce110ea1SWei Hu #include <machine/in_cksum.h>
47ce110ea1SWei Hu 
48ce110ea1SWei Hu #include <net/if.h>
49ce110ea1SWei Hu #include <net/if_var.h>
50ce110ea1SWei Hu #include <net/if_types.h>
51ce110ea1SWei Hu #include <net/if_vlan_var.h>
52ce110ea1SWei Hu #ifdef RSS
53ce110ea1SWei Hu #include <net/rss_config.h>
54ce110ea1SWei Hu #endif
55ce110ea1SWei Hu 
56ce110ea1SWei Hu #include <netinet/in_systm.h>
57ce110ea1SWei Hu #include <netinet/in.h>
58ce110ea1SWei Hu #include <netinet/if_ether.h>
59ce110ea1SWei Hu #include <netinet/ip.h>
60ce110ea1SWei Hu #include <netinet/ip6.h>
61ce110ea1SWei Hu #include <netinet/tcp.h>
62ce110ea1SWei Hu #include <netinet/udp.h>
63ce110ea1SWei Hu 
64ce110ea1SWei Hu #include "mana.h"
65ce110ea1SWei Hu #include "mana_sysctl.h"
66ce110ea1SWei Hu 
67ce110ea1SWei Hu static int mana_up(struct mana_port_context *apc);
68ce110ea1SWei Hu static int mana_down(struct mana_port_context *apc);
69ce110ea1SWei Hu 
70a18e9994SWei Hu extern unsigned int mana_tx_req_size;
71a18e9994SWei Hu extern unsigned int mana_rx_req_size;
72*9b8701b8SWei Hu extern unsigned int mana_rx_refill_threshold;
73a18e9994SWei Hu 
74ce110ea1SWei Hu static void
mana_rss_key_fill(void * k,size_t size)75ce110ea1SWei Hu mana_rss_key_fill(void *k, size_t size)
76ce110ea1SWei Hu {
77ce110ea1SWei Hu 	static bool rss_key_generated = false;
78ce110ea1SWei Hu 	static uint8_t rss_key[MANA_HASH_KEY_SIZE];
79ce110ea1SWei Hu 
80ce110ea1SWei Hu 	KASSERT(size <= MANA_HASH_KEY_SIZE,
81ce110ea1SWei Hu 	    ("Request more buytes than MANA RSS key can hold"));
82ce110ea1SWei Hu 
83ce110ea1SWei Hu 	if (!rss_key_generated) {
84ce110ea1SWei Hu 		arc4random_buf(rss_key, MANA_HASH_KEY_SIZE);
85ce110ea1SWei Hu 		rss_key_generated = true;
86ce110ea1SWei Hu 	}
87ce110ea1SWei Hu 	memcpy(k, rss_key, size);
88ce110ea1SWei Hu }
89ce110ea1SWei Hu 
90ce110ea1SWei Hu static int
mana_ifmedia_change(if_t ifp __unused)9137d22ce0SJustin Hibbits mana_ifmedia_change(if_t ifp __unused)
92ce110ea1SWei Hu {
93ce110ea1SWei Hu 	return EOPNOTSUPP;
94ce110ea1SWei Hu }
95ce110ea1SWei Hu 
96ce110ea1SWei Hu static void
mana_ifmedia_status(if_t ifp,struct ifmediareq * ifmr)9737d22ce0SJustin Hibbits mana_ifmedia_status(if_t ifp, struct ifmediareq *ifmr)
98ce110ea1SWei Hu {
99ce110ea1SWei Hu 	struct mana_port_context *apc = if_getsoftc(ifp);
100ce110ea1SWei Hu 
101ce110ea1SWei Hu 	if (!apc) {
102ce110ea1SWei Hu 		if_printf(ifp, "Port not available\n");
103ce110ea1SWei Hu 		return;
104ce110ea1SWei Hu 	}
105ce110ea1SWei Hu 
106ce110ea1SWei Hu 	MANA_APC_LOCK_LOCK(apc);
107ce110ea1SWei Hu 
108ce110ea1SWei Hu 	ifmr->ifm_status = IFM_AVALID;
109ce110ea1SWei Hu 	ifmr->ifm_active = IFM_ETHER;
110ce110ea1SWei Hu 
111ce110ea1SWei Hu 	if (!apc->port_is_up) {
112ce110ea1SWei Hu 		MANA_APC_LOCK_UNLOCK(apc);
1131833cf13SWei Hu 		mana_dbg(NULL, "Port %u link is down\n", apc->port_idx);
114ce110ea1SWei Hu 		return;
115ce110ea1SWei Hu 	}
116ce110ea1SWei Hu 
117ce110ea1SWei Hu 	ifmr->ifm_status |= IFM_ACTIVE;
118ce110ea1SWei Hu 	ifmr->ifm_active |= IFM_100G_DR | IFM_FDX;
119ce110ea1SWei Hu 
120ce110ea1SWei Hu 	MANA_APC_LOCK_UNLOCK(apc);
121ce110ea1SWei Hu }
122ce110ea1SWei Hu 
123ce110ea1SWei Hu static uint64_t
mana_get_counter(if_t ifp,ift_counter cnt)12437d22ce0SJustin Hibbits mana_get_counter(if_t ifp, ift_counter cnt)
125ce110ea1SWei Hu {
126ce110ea1SWei Hu 	struct mana_port_context *apc = if_getsoftc(ifp);
127ce110ea1SWei Hu 	struct mana_port_stats *stats = &apc->port_stats;
128ce110ea1SWei Hu 
129ce110ea1SWei Hu 	switch (cnt) {
130ce110ea1SWei Hu 	case IFCOUNTER_IPACKETS:
131ce110ea1SWei Hu 		return (counter_u64_fetch(stats->rx_packets));
132ce110ea1SWei Hu 	case IFCOUNTER_OPACKETS:
133ce110ea1SWei Hu 		return (counter_u64_fetch(stats->tx_packets));
134ce110ea1SWei Hu 	case IFCOUNTER_IBYTES:
135ce110ea1SWei Hu 		return (counter_u64_fetch(stats->rx_bytes));
136ce110ea1SWei Hu 	case IFCOUNTER_OBYTES:
137ce110ea1SWei Hu 		return (counter_u64_fetch(stats->tx_bytes));
138ce110ea1SWei Hu 	case IFCOUNTER_IQDROPS:
139ce110ea1SWei Hu 		return (counter_u64_fetch(stats->rx_drops));
140ce110ea1SWei Hu 	case IFCOUNTER_OQDROPS:
141ce110ea1SWei Hu 		return (counter_u64_fetch(stats->tx_drops));
142ce110ea1SWei Hu 	default:
143ce110ea1SWei Hu 		return (if_get_counter_default(ifp, cnt));
144ce110ea1SWei Hu 	}
145ce110ea1SWei Hu }
146ce110ea1SWei Hu 
147ce110ea1SWei Hu static void
mana_qflush(if_t ifp)14837d22ce0SJustin Hibbits mana_qflush(if_t ifp)
149ce110ea1SWei Hu {
150ce110ea1SWei Hu 	if_qflush(ifp);
151ce110ea1SWei Hu }
152ce110ea1SWei Hu 
153ce110ea1SWei Hu int
mana_restart(struct mana_port_context * apc)154ce110ea1SWei Hu mana_restart(struct mana_port_context *apc)
155ce110ea1SWei Hu {
156ce110ea1SWei Hu 	int rc = 0;
157ce110ea1SWei Hu 
158ce110ea1SWei Hu 	MANA_APC_LOCK_LOCK(apc);
159ce110ea1SWei Hu 	if (apc->port_is_up)
160ce110ea1SWei Hu 		 mana_down(apc);
161ce110ea1SWei Hu 
162ce110ea1SWei Hu 	rc = mana_up(apc);
163ce110ea1SWei Hu 	MANA_APC_LOCK_UNLOCK(apc);
164ce110ea1SWei Hu 
165ce110ea1SWei Hu 	return (rc);
166ce110ea1SWei Hu }
167ce110ea1SWei Hu 
168ce110ea1SWei Hu static int
mana_ioctl(if_t ifp,u_long command,caddr_t data)16937d22ce0SJustin Hibbits mana_ioctl(if_t ifp, u_long command, caddr_t data)
170ce110ea1SWei Hu {
171ce110ea1SWei Hu 	struct mana_port_context *apc = if_getsoftc(ifp);
172ce110ea1SWei Hu 	struct ifrsskey *ifrk;
173ce110ea1SWei Hu 	struct ifrsshash *ifrh;
174ce110ea1SWei Hu 	struct ifreq *ifr;
175ce110ea1SWei Hu 	uint16_t new_mtu;
176ab7dc1ceSWei Hu 	int rc = 0, mask;
177ce110ea1SWei Hu 
178ce110ea1SWei Hu 	switch (command) {
179ce110ea1SWei Hu 	case SIOCSIFMTU:
180ce110ea1SWei Hu 		ifr = (struct ifreq *)data;
181ce110ea1SWei Hu 		new_mtu = ifr->ifr_mtu;
18237d22ce0SJustin Hibbits 		if (if_getmtu(ifp) == new_mtu)
183ce110ea1SWei Hu 			break;
184ce110ea1SWei Hu 		if ((new_mtu + 18 > MAX_FRAME_SIZE) ||
185ce110ea1SWei Hu 		    (new_mtu + 18 < MIN_FRAME_SIZE)) {
186ce110ea1SWei Hu 			if_printf(ifp, "Invalid MTU. new_mtu: %d, "
187ce110ea1SWei Hu 			    "max allowed: %d, min allowed: %d\n",
188ce110ea1SWei Hu 			    new_mtu, MAX_FRAME_SIZE - 18, MIN_FRAME_SIZE - 18);
189ce110ea1SWei Hu 			return EINVAL;
190ce110ea1SWei Hu 		}
191ce110ea1SWei Hu 		MANA_APC_LOCK_LOCK(apc);
192ce110ea1SWei Hu 		if (apc->port_is_up)
193ce110ea1SWei Hu 			mana_down(apc);
194ce110ea1SWei Hu 
195ce110ea1SWei Hu 		apc->frame_size = new_mtu + 18;
196ce110ea1SWei Hu 		if_setmtu(ifp, new_mtu);
197ce110ea1SWei Hu 		mana_dbg(NULL, "Set MTU to %d\n", new_mtu);
198ce110ea1SWei Hu 
199ce110ea1SWei Hu 		rc = mana_up(apc);
200ce110ea1SWei Hu 		MANA_APC_LOCK_UNLOCK(apc);
201ce110ea1SWei Hu 		break;
202ce110ea1SWei Hu 
203ce110ea1SWei Hu 	case SIOCSIFFLAGS:
20437d22ce0SJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
20537d22ce0SJustin Hibbits 			if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) {
206ce110ea1SWei Hu 				MANA_APC_LOCK_LOCK(apc);
207ce110ea1SWei Hu 				if (!apc->port_is_up)
208ce110ea1SWei Hu 					rc = mana_up(apc);
209ce110ea1SWei Hu 				MANA_APC_LOCK_UNLOCK(apc);
210ce110ea1SWei Hu 			}
211ce110ea1SWei Hu 		} else {
21237d22ce0SJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
213ce110ea1SWei Hu 				MANA_APC_LOCK_LOCK(apc);
214ce110ea1SWei Hu 				if (apc->port_is_up)
215ce110ea1SWei Hu 					mana_down(apc);
216ce110ea1SWei Hu 				MANA_APC_LOCK_UNLOCK(apc);
217ce110ea1SWei Hu 			}
218ce110ea1SWei Hu 		}
219ce110ea1SWei Hu 		break;
220ce110ea1SWei Hu 
221ab7dc1ceSWei Hu 	case SIOCSIFCAP:
222ab7dc1ceSWei Hu 		MANA_APC_LOCK_LOCK(apc);
223ab7dc1ceSWei Hu 		ifr = (struct ifreq *)data;
224ab7dc1ceSWei Hu 		/*
225ab7dc1ceSWei Hu 		 * Fix up requested capabilities w/ supported capabilities,
226ab7dc1ceSWei Hu 		 * since the supported capabilities could have been changed.
227ab7dc1ceSWei Hu 		 */
228ab7dc1ceSWei Hu 		mask = (ifr->ifr_reqcap & if_getcapabilities(ifp)) ^
229ab7dc1ceSWei Hu 		    if_getcapenable(ifp);
230ab7dc1ceSWei Hu 
231ab7dc1ceSWei Hu 		if (mask & IFCAP_TXCSUM) {
232ab7dc1ceSWei Hu 			if_togglecapenable(ifp, IFCAP_TXCSUM);
233ab7dc1ceSWei Hu 			if_togglehwassist(ifp, (CSUM_TCP | CSUM_UDP | CSUM_IP));
234ab7dc1ceSWei Hu 
235ab7dc1ceSWei Hu 			if ((IFCAP_TSO4 & if_getcapenable(ifp)) &&
236ab7dc1ceSWei Hu 			    !(IFCAP_TXCSUM & if_getcapenable(ifp))) {
237ab7dc1ceSWei Hu 				mask &= ~IFCAP_TSO4;
238ab7dc1ceSWei Hu 				if_setcapenablebit(ifp, 0, IFCAP_TSO4);
239ab7dc1ceSWei Hu 				if_sethwassistbits(ifp, 0, CSUM_IP_TSO);
240ab7dc1ceSWei Hu 				mana_warn(NULL,
241ab7dc1ceSWei Hu 				    "Also disabled tso4 due to -txcsum.\n");
242ab7dc1ceSWei Hu 			}
243ab7dc1ceSWei Hu 		}
244ab7dc1ceSWei Hu 
245ab7dc1ceSWei Hu 		if (mask & IFCAP_TXCSUM_IPV6) {
246ab7dc1ceSWei Hu 			if_togglecapenable(ifp, IFCAP_TXCSUM_IPV6);
247ab7dc1ceSWei Hu 			if_togglehwassist(ifp, (CSUM_UDP_IPV6 | CSUM_TCP_IPV6));
248ab7dc1ceSWei Hu 
249ab7dc1ceSWei Hu 			if ((IFCAP_TSO6 & if_getcapenable(ifp)) &&
250ab7dc1ceSWei Hu 			    !(IFCAP_TXCSUM_IPV6 & if_getcapenable(ifp))) {
251ab7dc1ceSWei Hu 				mask &= ~IFCAP_TSO6;
252ab7dc1ceSWei Hu 				if_setcapenablebit(ifp, 0, IFCAP_TSO6);
253ab7dc1ceSWei Hu 				if_sethwassistbits(ifp, 0, CSUM_IP6_TSO);
254ab7dc1ceSWei Hu 				mana_warn(ifp,
255ab7dc1ceSWei Hu 				    "Also disabled tso6 due to -txcsum6.\n");
256ab7dc1ceSWei Hu 			}
257ab7dc1ceSWei Hu 		}
258ab7dc1ceSWei Hu 
259ab7dc1ceSWei Hu 		if (mask & IFCAP_RXCSUM)
260ab7dc1ceSWei Hu 			if_togglecapenable(ifp, IFCAP_RXCSUM);
261ab7dc1ceSWei Hu 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
262ab7dc1ceSWei Hu 		if (mask & IFCAP_RXCSUM_IPV6)
263ab7dc1ceSWei Hu 			if_togglecapenable(ifp, IFCAP_RXCSUM_IPV6);
264ab7dc1ceSWei Hu 
265ab7dc1ceSWei Hu 		if (mask & IFCAP_LRO)
266ab7dc1ceSWei Hu 			if_togglecapenable(ifp, IFCAP_LRO);
267ab7dc1ceSWei Hu 
268ab7dc1ceSWei Hu 		if (mask & IFCAP_TSO4) {
269ab7dc1ceSWei Hu 			if (!(IFCAP_TSO4 & if_getcapenable(ifp)) &&
270ab7dc1ceSWei Hu 			    !(IFCAP_TXCSUM & if_getcapenable(ifp))) {
271ab7dc1ceSWei Hu 				MANA_APC_LOCK_UNLOCK(apc);
272ab7dc1ceSWei Hu 				if_printf(ifp, "Enable txcsum first.\n");
273ab7dc1ceSWei Hu 				rc = EAGAIN;
274ab7dc1ceSWei Hu 				goto out;
275ab7dc1ceSWei Hu 			}
276ab7dc1ceSWei Hu 			if_togglecapenable(ifp, IFCAP_TSO4);
277ab7dc1ceSWei Hu 			if_togglehwassist(ifp, CSUM_IP_TSO);
278ab7dc1ceSWei Hu 		}
279ab7dc1ceSWei Hu 
280ab7dc1ceSWei Hu 		if (mask & IFCAP_TSO6) {
281ab7dc1ceSWei Hu 			if (!(IFCAP_TSO6 & if_getcapenable(ifp)) &&
282ab7dc1ceSWei Hu 			    !(IFCAP_TXCSUM_IPV6 & if_getcapenable(ifp))) {
283ab7dc1ceSWei Hu 				MANA_APC_LOCK_UNLOCK(apc);
284ab7dc1ceSWei Hu 				if_printf(ifp, "Enable txcsum6 first.\n");
285ab7dc1ceSWei Hu 				rc = EAGAIN;
286ab7dc1ceSWei Hu 				goto out;
287ab7dc1ceSWei Hu 			}
288ab7dc1ceSWei Hu 			if_togglecapenable(ifp, IFCAP_TSO6);
289ab7dc1ceSWei Hu 			if_togglehwassist(ifp, CSUM_IP6_TSO);
290ab7dc1ceSWei Hu 		}
291ab7dc1ceSWei Hu 
292ab7dc1ceSWei Hu 		MANA_APC_LOCK_UNLOCK(apc);
293ab7dc1ceSWei Hu out:
294ab7dc1ceSWei Hu 		break;
295ab7dc1ceSWei Hu 
296ce110ea1SWei Hu 	case SIOCSIFMEDIA:
297ce110ea1SWei Hu 	case SIOCGIFMEDIA:
298ce110ea1SWei Hu 	case SIOCGIFXMEDIA:
299ce110ea1SWei Hu 		ifr = (struct ifreq *)data;
300ce110ea1SWei Hu 		rc = ifmedia_ioctl(ifp, ifr, &apc->media, command);
301ce110ea1SWei Hu 		break;
302ce110ea1SWei Hu 
303ce110ea1SWei Hu 	case SIOCGIFRSSKEY:
304ce110ea1SWei Hu 		ifrk = (struct ifrsskey *)data;
305ce110ea1SWei Hu 		ifrk->ifrk_func = RSS_FUNC_TOEPLITZ;
306ce110ea1SWei Hu 		ifrk->ifrk_keylen = MANA_HASH_KEY_SIZE;
307ce110ea1SWei Hu 		memcpy(ifrk->ifrk_key, apc->hashkey, MANA_HASH_KEY_SIZE);
308ce110ea1SWei Hu 		break;
309ce110ea1SWei Hu 
310ce110ea1SWei Hu 	case SIOCGIFRSSHASH:
311ce110ea1SWei Hu 		ifrh = (struct ifrsshash *)data;
312ce110ea1SWei Hu 		ifrh->ifrh_func = RSS_FUNC_TOEPLITZ;
313ce110ea1SWei Hu 		ifrh->ifrh_types =
314ce110ea1SWei Hu 		    RSS_TYPE_TCP_IPV4 |
315ce110ea1SWei Hu 		    RSS_TYPE_UDP_IPV4 |
316ce110ea1SWei Hu 		    RSS_TYPE_TCP_IPV6 |
317ce110ea1SWei Hu 		    RSS_TYPE_UDP_IPV6;
318ce110ea1SWei Hu 		break;
319ce110ea1SWei Hu 
320ce110ea1SWei Hu 	default:
321ce110ea1SWei Hu 		rc = ether_ioctl(ifp, command, data);
322ce110ea1SWei Hu 		break;
323ce110ea1SWei Hu 	}
324ce110ea1SWei Hu 
325ce110ea1SWei Hu 	return (rc);
326ce110ea1SWei Hu }
327ce110ea1SWei Hu 
328ce110ea1SWei Hu static inline void
mana_alloc_counters(counter_u64_t * begin,int size)329ce110ea1SWei Hu mana_alloc_counters(counter_u64_t *begin, int size)
330ce110ea1SWei Hu {
331ce110ea1SWei Hu 	counter_u64_t *end = (counter_u64_t *)((char *)begin + size);
332ce110ea1SWei Hu 
333ce110ea1SWei Hu 	for (; begin < end; ++begin)
334ce110ea1SWei Hu 		*begin = counter_u64_alloc(M_WAITOK);
335ce110ea1SWei Hu }
336ce110ea1SWei Hu 
337ce110ea1SWei Hu static inline void
mana_free_counters(counter_u64_t * begin,int size)338ce110ea1SWei Hu mana_free_counters(counter_u64_t *begin, int size)
339ce110ea1SWei Hu {
340ce110ea1SWei Hu 	counter_u64_t *end = (counter_u64_t *)((char *)begin + size);
341ce110ea1SWei Hu 
342ce110ea1SWei Hu 	for (; begin < end; ++begin)
343ce110ea1SWei Hu 		counter_u64_free(*begin);
344ce110ea1SWei Hu }
345ce110ea1SWei Hu 
346ce110ea1SWei Hu static bool
mana_can_tx(struct gdma_queue * wq)347ce110ea1SWei Hu mana_can_tx(struct gdma_queue *wq)
348ce110ea1SWei Hu {
349ce110ea1SWei Hu 	return mana_gd_wq_avail_space(wq) >= MAX_TX_WQE_SIZE;
350ce110ea1SWei Hu }
351ce110ea1SWei Hu 
352ce110ea1SWei Hu static inline int
mana_tx_map_mbuf(struct mana_port_context * apc,struct mana_send_buf_info * tx_info,struct mbuf ** m_head,struct mana_tx_package * tp,struct mana_stats * tx_stats)353ce110ea1SWei Hu mana_tx_map_mbuf(struct mana_port_context *apc,
354ce110ea1SWei Hu     struct mana_send_buf_info *tx_info,
355ce110ea1SWei Hu     struct mbuf **m_head, struct mana_tx_package *tp,
356ce110ea1SWei Hu     struct mana_stats *tx_stats)
357ce110ea1SWei Hu {
358ce110ea1SWei Hu 	struct gdma_dev *gd = apc->ac->gdma_dev;
359ce110ea1SWei Hu 	bus_dma_segment_t segs[MAX_MBUF_FRAGS];
360ce110ea1SWei Hu 	struct mbuf *m = *m_head;
361ce110ea1SWei Hu 	int err, nsegs, i;
362ce110ea1SWei Hu 
363ce110ea1SWei Hu 	err = bus_dmamap_load_mbuf_sg(apc->tx_buf_tag, tx_info->dma_map,
364ce110ea1SWei Hu 	    m, segs, &nsegs, BUS_DMA_NOWAIT);
365ce110ea1SWei Hu 	if (err == EFBIG) {
366ce110ea1SWei Hu 		struct mbuf *m_new;
367ce110ea1SWei Hu 
368ce110ea1SWei Hu 		counter_u64_add(tx_stats->collapse, 1);
369ce110ea1SWei Hu 		m_new = m_collapse(m, M_NOWAIT, MAX_MBUF_FRAGS);
370ce110ea1SWei Hu 		if (unlikely(m_new == NULL)) {
371ce110ea1SWei Hu 			counter_u64_add(tx_stats->collapse_err, 1);
372ce110ea1SWei Hu 			return ENOBUFS;
373ce110ea1SWei Hu 		} else {
374ce110ea1SWei Hu 			*m_head = m = m_new;
375ce110ea1SWei Hu 		}
376ce110ea1SWei Hu 
377ce110ea1SWei Hu 		mana_warn(NULL,
378ce110ea1SWei Hu 		    "Too many segs in orig mbuf, m_collapse called\n");
379ce110ea1SWei Hu 
380ce110ea1SWei Hu 		err = bus_dmamap_load_mbuf_sg(apc->tx_buf_tag,
381ce110ea1SWei Hu 		    tx_info->dma_map, m, segs, &nsegs, BUS_DMA_NOWAIT);
382ce110ea1SWei Hu 	}
383ce110ea1SWei Hu 	if (!err) {
384ce110ea1SWei Hu 		for (i = 0; i < nsegs; i++) {
385ce110ea1SWei Hu 			tp->wqe_req.sgl[i].address = segs[i].ds_addr;
386ce110ea1SWei Hu 			tp->wqe_req.sgl[i].mem_key = gd->gpa_mkey;
387ce110ea1SWei Hu 			tp->wqe_req.sgl[i].size = segs[i].ds_len;
388ce110ea1SWei Hu 		}
389ce110ea1SWei Hu 		tp->wqe_req.num_sge = nsegs;
390ce110ea1SWei Hu 
391ce110ea1SWei Hu 		tx_info->mbuf = *m_head;
392ce110ea1SWei Hu 
393ce110ea1SWei Hu 		bus_dmamap_sync(apc->tx_buf_tag, tx_info->dma_map,
394ce110ea1SWei Hu 		    BUS_DMASYNC_PREWRITE);
395ce110ea1SWei Hu 	}
396ce110ea1SWei Hu 
397ce110ea1SWei Hu 	return err;
398ce110ea1SWei Hu }
399ce110ea1SWei Hu 
400ce110ea1SWei Hu static inline void
mana_tx_unmap_mbuf(struct mana_port_context * apc,struct mana_send_buf_info * tx_info)401ce110ea1SWei Hu mana_tx_unmap_mbuf(struct mana_port_context *apc,
402ce110ea1SWei Hu     struct mana_send_buf_info *tx_info)
403ce110ea1SWei Hu {
404ce110ea1SWei Hu 	bus_dmamap_sync(apc->tx_buf_tag, tx_info->dma_map,
405ce110ea1SWei Hu 	    BUS_DMASYNC_POSTWRITE);
406ce110ea1SWei Hu 	bus_dmamap_unload(apc->tx_buf_tag, tx_info->dma_map);
407ce110ea1SWei Hu 	if (tx_info->mbuf) {
408ce110ea1SWei Hu 		m_freem(tx_info->mbuf);
409ce110ea1SWei Hu 		tx_info->mbuf = NULL;
410ce110ea1SWei Hu 	}
411ce110ea1SWei Hu }
412ce110ea1SWei Hu 
413ce110ea1SWei Hu static inline int
mana_load_rx_mbuf(struct mana_port_context * apc,struct mana_rxq * rxq,struct mana_recv_buf_oob * rx_oob,bool alloc_mbuf)414ce110ea1SWei Hu mana_load_rx_mbuf(struct mana_port_context *apc, struct mana_rxq *rxq,
415ce110ea1SWei Hu     struct mana_recv_buf_oob *rx_oob, bool alloc_mbuf)
416ce110ea1SWei Hu {
417ce110ea1SWei Hu 	bus_dma_segment_t segs[1];
418ce110ea1SWei Hu 	struct mbuf *mbuf;
419ce110ea1SWei Hu 	int nsegs, err;
420ce110ea1SWei Hu 	uint32_t mlen;
421ce110ea1SWei Hu 
422ce110ea1SWei Hu 	if (alloc_mbuf) {
423ce110ea1SWei Hu 		mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, rxq->datasize);
424ce110ea1SWei Hu 		if (unlikely(mbuf == NULL)) {
425ce110ea1SWei Hu 			mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
426ce110ea1SWei Hu 			if (unlikely(mbuf == NULL)) {
427ce110ea1SWei Hu 				return ENOMEM;
428ce110ea1SWei Hu 			}
429ce110ea1SWei Hu 			mlen = MCLBYTES;
430ce110ea1SWei Hu 		} else {
431ce110ea1SWei Hu 			mlen = rxq->datasize;
432ce110ea1SWei Hu 		}
433ce110ea1SWei Hu 
434ce110ea1SWei Hu 		mbuf->m_pkthdr.len = mbuf->m_len = mlen;
435ce110ea1SWei Hu 	} else {
436ce110ea1SWei Hu 		if (rx_oob->mbuf) {
437ce110ea1SWei Hu 			mbuf = rx_oob->mbuf;
438ce110ea1SWei Hu 			mlen = rx_oob->mbuf->m_pkthdr.len;
439ce110ea1SWei Hu 		} else {
440ce110ea1SWei Hu 			return ENOMEM;
441ce110ea1SWei Hu 		}
442ce110ea1SWei Hu 	}
443ce110ea1SWei Hu 
444ce110ea1SWei Hu 	err = bus_dmamap_load_mbuf_sg(apc->rx_buf_tag, rx_oob->dma_map,
445ce110ea1SWei Hu 	    mbuf, segs, &nsegs, BUS_DMA_NOWAIT);
446ce110ea1SWei Hu 
447ce110ea1SWei Hu 	if (unlikely((err != 0) || (nsegs != 1))) {
448ce110ea1SWei Hu 		mana_warn(NULL, "Failed to map mbuf, error: %d, "
449ce110ea1SWei Hu 		    "nsegs: %d\n", err, nsegs);
450ce110ea1SWei Hu 		counter_u64_add(rxq->stats.dma_mapping_err, 1);
451ce110ea1SWei Hu 		goto error;
452ce110ea1SWei Hu 	}
453ce110ea1SWei Hu 
454ce110ea1SWei Hu 	bus_dmamap_sync(apc->rx_buf_tag, rx_oob->dma_map,
455ce110ea1SWei Hu 	    BUS_DMASYNC_PREREAD);
456ce110ea1SWei Hu 
457ce110ea1SWei Hu 	rx_oob->mbuf = mbuf;
458ce110ea1SWei Hu 	rx_oob->num_sge = 1;
459ce110ea1SWei Hu 	rx_oob->sgl[0].address = segs[0].ds_addr;
460ce110ea1SWei Hu 	rx_oob->sgl[0].size = mlen;
461ce110ea1SWei Hu 	rx_oob->sgl[0].mem_key = apc->ac->gdma_dev->gpa_mkey;
462ce110ea1SWei Hu 
463ce110ea1SWei Hu 	return 0;
464ce110ea1SWei Hu 
465ce110ea1SWei Hu error:
466ce110ea1SWei Hu 	m_freem(mbuf);
467ce110ea1SWei Hu 	return EFAULT;
468ce110ea1SWei Hu }
469ce110ea1SWei Hu 
470ce110ea1SWei Hu static inline void
mana_unload_rx_mbuf(struct mana_port_context * apc,struct mana_rxq * rxq,struct mana_recv_buf_oob * rx_oob,bool free_mbuf)471ce110ea1SWei Hu mana_unload_rx_mbuf(struct mana_port_context *apc, struct mana_rxq *rxq,
472ce110ea1SWei Hu     struct mana_recv_buf_oob *rx_oob, bool free_mbuf)
473ce110ea1SWei Hu {
474ce110ea1SWei Hu 	bus_dmamap_sync(apc->rx_buf_tag, rx_oob->dma_map,
475ce110ea1SWei Hu 	    BUS_DMASYNC_POSTREAD);
476ce110ea1SWei Hu 	bus_dmamap_unload(apc->rx_buf_tag, rx_oob->dma_map);
477ce110ea1SWei Hu 
478ce110ea1SWei Hu 	if (free_mbuf && rx_oob->mbuf) {
479ce110ea1SWei Hu 		m_freem(rx_oob->mbuf);
480ce110ea1SWei Hu 		rx_oob->mbuf = NULL;
481ce110ea1SWei Hu 	}
482ce110ea1SWei Hu }
483ce110ea1SWei Hu 
484ce110ea1SWei Hu 
485ce110ea1SWei Hu /* Use couple mbuf PH_loc spaces for l3 and l4 protocal type */
486ce110ea1SWei Hu #define MANA_L3_PROTO(_mbuf)	((_mbuf)->m_pkthdr.PH_loc.sixteen[0])
487ce110ea1SWei Hu #define MANA_L4_PROTO(_mbuf)	((_mbuf)->m_pkthdr.PH_loc.sixteen[1])
488ce110ea1SWei Hu 
489ce110ea1SWei Hu #define MANA_TXQ_FULL	(IFF_DRV_RUNNING | IFF_DRV_OACTIVE)
490ce110ea1SWei Hu 
491ce110ea1SWei Hu static void
mana_xmit(struct mana_txq * txq)492ce110ea1SWei Hu mana_xmit(struct mana_txq *txq)
493ce110ea1SWei Hu {
494ce110ea1SWei Hu 	enum mana_tx_pkt_format pkt_fmt = MANA_SHORT_PKT_FMT;
495ce110ea1SWei Hu 	struct mana_send_buf_info *tx_info;
49637d22ce0SJustin Hibbits 	if_t ndev = txq->ndev;
497ce110ea1SWei Hu 	struct mbuf *mbuf;
498ce110ea1SWei Hu 	struct mana_port_context *apc = if_getsoftc(ndev);
499a18e9994SWei Hu 	unsigned int tx_queue_size = apc->tx_queue_size;
500ce110ea1SWei Hu 	struct mana_port_stats *port_stats = &apc->port_stats;
501ce110ea1SWei Hu 	struct gdma_dev *gd = apc->ac->gdma_dev;
502ce110ea1SWei Hu 	uint64_t packets, bytes;
503ce110ea1SWei Hu 	uint16_t next_to_use;
504ce110ea1SWei Hu 	struct mana_tx_package pkg = {};
505ce110ea1SWei Hu 	struct mana_stats *tx_stats;
506ce110ea1SWei Hu 	struct gdma_queue *gdma_sq;
507ce110ea1SWei Hu 	struct mana_cq *cq;
508ce110ea1SWei Hu 	int err, len;
509b167e449SWei Hu 	bool is_tso;
510ce110ea1SWei Hu 
511ce110ea1SWei Hu 	gdma_sq = txq->gdma_sq;
512ce110ea1SWei Hu 	cq = &apc->tx_qp[txq->idx].tx_cq;
513ce110ea1SWei Hu 	tx_stats = &txq->stats;
514ce110ea1SWei Hu 
515ce110ea1SWei Hu 	packets = 0;
516ce110ea1SWei Hu 	bytes = 0;
517ce110ea1SWei Hu 	next_to_use = txq->next_to_use;
518ce110ea1SWei Hu 
519ce110ea1SWei Hu 	while ((mbuf = drbr_peek(ndev, txq->txq_br)) != NULL) {
520ce110ea1SWei Hu 		if (!apc->port_is_up ||
521ce110ea1SWei Hu 		    (if_getdrvflags(ndev) & MANA_TXQ_FULL) != IFF_DRV_RUNNING) {
522ce110ea1SWei Hu 			drbr_putback(ndev, txq->txq_br, mbuf);
523ce110ea1SWei Hu 			break;
524ce110ea1SWei Hu 		}
525ce110ea1SWei Hu 
526ce110ea1SWei Hu 		if (!mana_can_tx(gdma_sq)) {
527ce110ea1SWei Hu 			/* SQ is full. Set the IFF_DRV_OACTIVE flag */
528ce110ea1SWei Hu 			if_setdrvflagbits(apc->ndev, IFF_DRV_OACTIVE, 0);
529ce110ea1SWei Hu 			counter_u64_add(tx_stats->stop, 1);
530ce110ea1SWei Hu 			uint64_t stops = counter_u64_fetch(tx_stats->stop);
531ce110ea1SWei Hu 			uint64_t wakeups = counter_u64_fetch(tx_stats->wakeup);
532ce110ea1SWei Hu #define MANA_TXQ_STOP_THRESHOLD		50
533ce110ea1SWei Hu 			if (stops > MANA_TXQ_STOP_THRESHOLD && wakeups > 0 &&
534ce110ea1SWei Hu 			    stops > wakeups && txq->alt_txq_idx == txq->idx) {
535ce110ea1SWei Hu 				txq->alt_txq_idx =
536ce110ea1SWei Hu 				    (txq->idx + (stops / wakeups))
537ce110ea1SWei Hu 				    % apc->num_queues;
538ce110ea1SWei Hu 				counter_u64_add(tx_stats->alt_chg, 1);
539ce110ea1SWei Hu 			}
540ce110ea1SWei Hu 
541ce110ea1SWei Hu 			drbr_putback(ndev, txq->txq_br, mbuf);
542ce110ea1SWei Hu 
5431833cf13SWei Hu 			taskqueue_enqueue(cq->cleanup_tq, &cq->cleanup_task);
544ce110ea1SWei Hu 			break;
545ce110ea1SWei Hu 		}
546ce110ea1SWei Hu 
547ce110ea1SWei Hu 		tx_info = &txq->tx_buf_info[next_to_use];
548ce110ea1SWei Hu 
549ce110ea1SWei Hu 		memset(&pkg, 0, sizeof(struct mana_tx_package));
550ce110ea1SWei Hu 		pkg.wqe_req.sgl = pkg.sgl_array;
551ce110ea1SWei Hu 
552ce110ea1SWei Hu 		err = mana_tx_map_mbuf(apc, tx_info, &mbuf, &pkg, tx_stats);
553ce110ea1SWei Hu 		if (unlikely(err)) {
554ce110ea1SWei Hu 			mana_dbg(NULL,
555ce110ea1SWei Hu 			    "Failed to map tx mbuf, err %d\n", err);
556ce110ea1SWei Hu 
557ce110ea1SWei Hu 			counter_u64_add(tx_stats->dma_mapping_err, 1);
558ce110ea1SWei Hu 
559ce110ea1SWei Hu 			/* The mbuf is still there. Free it */
560ce110ea1SWei Hu 			m_freem(mbuf);
561ce110ea1SWei Hu 			/* Advance the drbr queue */
562ce110ea1SWei Hu 			drbr_advance(ndev, txq->txq_br);
563ce110ea1SWei Hu 			continue;
564ce110ea1SWei Hu 		}
565ce110ea1SWei Hu 
566ce110ea1SWei Hu 		pkg.tx_oob.s_oob.vcq_num = cq->gdma_id;
567ce110ea1SWei Hu 		pkg.tx_oob.s_oob.vsq_frame = txq->vsq_frame;
568ce110ea1SWei Hu 
569ce110ea1SWei Hu 		if (txq->vp_offset > MANA_SHORT_VPORT_OFFSET_MAX) {
570ce110ea1SWei Hu 			pkg.tx_oob.l_oob.long_vp_offset = txq->vp_offset;
571ce110ea1SWei Hu 			pkt_fmt = MANA_LONG_PKT_FMT;
572ce110ea1SWei Hu 		} else {
573ce110ea1SWei Hu 			pkg.tx_oob.s_oob.short_vp_offset = txq->vp_offset;
574ce110ea1SWei Hu 		}
575ce110ea1SWei Hu 
576ce110ea1SWei Hu 		pkg.tx_oob.s_oob.pkt_fmt = pkt_fmt;
577ce110ea1SWei Hu 
578ce110ea1SWei Hu 		if (pkt_fmt == MANA_SHORT_PKT_FMT)
579ce110ea1SWei Hu 			pkg.wqe_req.inline_oob_size = sizeof(struct mana_tx_short_oob);
580ce110ea1SWei Hu 		else
581ce110ea1SWei Hu 			pkg.wqe_req.inline_oob_size = sizeof(struct mana_tx_oob);
582ce110ea1SWei Hu 
583ce110ea1SWei Hu 		pkg.wqe_req.inline_oob_data = &pkg.tx_oob;
584ce110ea1SWei Hu 		pkg.wqe_req.flags = 0;
585ce110ea1SWei Hu 		pkg.wqe_req.client_data_unit = 0;
586ce110ea1SWei Hu 
587b167e449SWei Hu 		is_tso = false;
588ce110ea1SWei Hu 		if (mbuf->m_pkthdr.csum_flags & CSUM_TSO) {
589b167e449SWei Hu 			is_tso =  true;
590b167e449SWei Hu 
591ce110ea1SWei Hu 			if (MANA_L3_PROTO(mbuf) == ETHERTYPE_IP)
592ce110ea1SWei Hu 				pkg.tx_oob.s_oob.is_outer_ipv4 = 1;
593ce110ea1SWei Hu 			else
594ce110ea1SWei Hu 				pkg.tx_oob.s_oob.is_outer_ipv6 = 1;
595ce110ea1SWei Hu 
596ce110ea1SWei Hu 			pkg.tx_oob.s_oob.comp_iphdr_csum = 1;
597ce110ea1SWei Hu 			pkg.tx_oob.s_oob.comp_tcp_csum = 1;
598ce110ea1SWei Hu 			pkg.tx_oob.s_oob.trans_off = mbuf->m_pkthdr.l3hlen;
599ce110ea1SWei Hu 
600ce110ea1SWei Hu 			pkg.wqe_req.client_data_unit = mbuf->m_pkthdr.tso_segsz;
601ce110ea1SWei Hu 			pkg.wqe_req.flags = GDMA_WR_OOB_IN_SGL | GDMA_WR_PAD_BY_SGE0;
602ce110ea1SWei Hu 		} else if (mbuf->m_pkthdr.csum_flags &
603ce110ea1SWei Hu 		    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
604ce110ea1SWei Hu 			if (MANA_L3_PROTO(mbuf) == ETHERTYPE_IP) {
605ce110ea1SWei Hu 				pkg.tx_oob.s_oob.is_outer_ipv4 = 1;
606ce110ea1SWei Hu 				pkg.tx_oob.s_oob.comp_iphdr_csum = 1;
607ce110ea1SWei Hu 			} else {
608ce110ea1SWei Hu 				pkg.tx_oob.s_oob.is_outer_ipv6 = 1;
609ce110ea1SWei Hu 			}
610ce110ea1SWei Hu 
611ce110ea1SWei Hu 			if (MANA_L4_PROTO(mbuf) == IPPROTO_TCP) {
612ce110ea1SWei Hu 				pkg.tx_oob.s_oob.comp_tcp_csum = 1;
613ce110ea1SWei Hu 				pkg.tx_oob.s_oob.trans_off =
614ce110ea1SWei Hu 				    mbuf->m_pkthdr.l3hlen;
615ce110ea1SWei Hu 			} else {
616ce110ea1SWei Hu 				pkg.tx_oob.s_oob.comp_udp_csum = 1;
617ce110ea1SWei Hu 			}
618ce110ea1SWei Hu 		} else if (mbuf->m_pkthdr.csum_flags & CSUM_IP) {
619ce110ea1SWei Hu 			pkg.tx_oob.s_oob.is_outer_ipv4 = 1;
620ce110ea1SWei Hu 			pkg.tx_oob.s_oob.comp_iphdr_csum = 1;
621ce110ea1SWei Hu 		} else {
622ce110ea1SWei Hu 			if (MANA_L3_PROTO(mbuf) == ETHERTYPE_IP)
623ce110ea1SWei Hu 				pkg.tx_oob.s_oob.is_outer_ipv4 = 1;
624ce110ea1SWei Hu 			else if (MANA_L3_PROTO(mbuf) == ETHERTYPE_IPV6)
625ce110ea1SWei Hu 				pkg.tx_oob.s_oob.is_outer_ipv6 = 1;
626ce110ea1SWei Hu 		}
627ce110ea1SWei Hu 
628ce110ea1SWei Hu 		len = mbuf->m_pkthdr.len;
629ce110ea1SWei Hu 
630ce110ea1SWei Hu 		err = mana_gd_post_work_request(gdma_sq, &pkg.wqe_req,
631ce110ea1SWei Hu 		    (struct gdma_posted_wqe_info *)&tx_info->wqe_inf);
632ce110ea1SWei Hu 		if (unlikely(err)) {
633ce110ea1SWei Hu 			/* Should not happen */
634ce110ea1SWei Hu 			if_printf(ndev, "Failed to post TX OOB: %d\n", err);
635ce110ea1SWei Hu 
636ce110ea1SWei Hu 			mana_tx_unmap_mbuf(apc, tx_info);
637ce110ea1SWei Hu 
638ce110ea1SWei Hu 			drbr_advance(ndev, txq->txq_br);
639ce110ea1SWei Hu 			continue;
640ce110ea1SWei Hu 		}
641ce110ea1SWei Hu 
642*9b8701b8SWei Hu 		next_to_use = MANA_IDX_NEXT(next_to_use, tx_queue_size);
643ce110ea1SWei Hu 
6440def501dSJohn Baldwin 		(void)atomic_inc_return(&txq->pending_sends);
645ce110ea1SWei Hu 
646ce110ea1SWei Hu 		drbr_advance(ndev, txq->txq_br);
647ce110ea1SWei Hu 
648ce110ea1SWei Hu 		mana_gd_wq_ring_doorbell(gd->gdma_context, gdma_sq);
649ce110ea1SWei Hu 
650ce110ea1SWei Hu 		packets++;
651ce110ea1SWei Hu 		bytes += len;
652b167e449SWei Hu 
653b167e449SWei Hu 		if (is_tso) {
654b167e449SWei Hu 			txq->tso_pkts++;
655b167e449SWei Hu 			txq->tso_bytes += len;
656b167e449SWei Hu 		}
657ce110ea1SWei Hu 	}
658ce110ea1SWei Hu 
659ce110ea1SWei Hu 	counter_enter();
660ce110ea1SWei Hu 	counter_u64_add_protected(tx_stats->packets, packets);
661ce110ea1SWei Hu 	counter_u64_add_protected(port_stats->tx_packets, packets);
662ce110ea1SWei Hu 	counter_u64_add_protected(tx_stats->bytes, bytes);
663ce110ea1SWei Hu 	counter_u64_add_protected(port_stats->tx_bytes, bytes);
664ce110ea1SWei Hu 	counter_exit();
665ce110ea1SWei Hu 
666ce110ea1SWei Hu 	txq->next_to_use = next_to_use;
667ce110ea1SWei Hu }
668ce110ea1SWei Hu 
669ce110ea1SWei Hu static void
mana_xmit_taskfunc(void * arg,int pending)670ce110ea1SWei Hu mana_xmit_taskfunc(void *arg, int pending)
671ce110ea1SWei Hu {
672ce110ea1SWei Hu 	struct mana_txq *txq = (struct mana_txq *)arg;
67337d22ce0SJustin Hibbits 	if_t ndev = txq->ndev;
674ce110ea1SWei Hu 	struct mana_port_context *apc = if_getsoftc(ndev);
675ce110ea1SWei Hu 
676ce110ea1SWei Hu 	while (!drbr_empty(ndev, txq->txq_br) && apc->port_is_up &&
677ce110ea1SWei Hu 	    (if_getdrvflags(ndev) & MANA_TXQ_FULL) == IFF_DRV_RUNNING) {
678ce110ea1SWei Hu 		mtx_lock(&txq->txq_mtx);
679ce110ea1SWei Hu 		mana_xmit(txq);
680ce110ea1SWei Hu 		mtx_unlock(&txq->txq_mtx);
681ce110ea1SWei Hu 	}
682ce110ea1SWei Hu }
683ce110ea1SWei Hu 
684ce110ea1SWei Hu #define PULLUP_HDR(m, len)				\
685ce110ea1SWei Hu do {							\
686ce110ea1SWei Hu 	if (unlikely((m)->m_len < (len))) {		\
687ce110ea1SWei Hu 		(m) = m_pullup((m), (len));		\
688ce110ea1SWei Hu 		if ((m) == NULL)			\
689ce110ea1SWei Hu 			return (NULL);			\
690ce110ea1SWei Hu 	}						\
691ce110ea1SWei Hu } while (0)
692ce110ea1SWei Hu 
693ce110ea1SWei Hu /*
694ce110ea1SWei Hu  * If this function failed, the mbuf would be freed.
695ce110ea1SWei Hu  */
696ce110ea1SWei Hu static inline struct mbuf *
mana_tso_fixup(struct mbuf * mbuf)697ce110ea1SWei Hu mana_tso_fixup(struct mbuf *mbuf)
698ce110ea1SWei Hu {
699ce110ea1SWei Hu 	struct ether_vlan_header *eh = mtod(mbuf, struct ether_vlan_header *);
700ce110ea1SWei Hu 	struct tcphdr *th;
701ce110ea1SWei Hu 	uint16_t etype;
702ce110ea1SWei Hu 	int ehlen;
703ce110ea1SWei Hu 
704ce110ea1SWei Hu 	if (eh->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) {
705ce110ea1SWei Hu 		etype = ntohs(eh->evl_proto);
706ce110ea1SWei Hu 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
707ce110ea1SWei Hu 	} else {
708ce110ea1SWei Hu 		etype = ntohs(eh->evl_encap_proto);
709ce110ea1SWei Hu 		ehlen = ETHER_HDR_LEN;
710ce110ea1SWei Hu 	}
711ce110ea1SWei Hu 
712ce110ea1SWei Hu 	if (etype == ETHERTYPE_IP) {
713ce110ea1SWei Hu 		struct ip *ip;
714ce110ea1SWei Hu 		int iphlen;
715ce110ea1SWei Hu 
716ce110ea1SWei Hu 		PULLUP_HDR(mbuf, ehlen + sizeof(*ip));
717ce110ea1SWei Hu 		ip = mtodo(mbuf, ehlen);
718ce110ea1SWei Hu 		iphlen = ip->ip_hl << 2;
719ce110ea1SWei Hu 		mbuf->m_pkthdr.l3hlen = ehlen + iphlen;
720ce110ea1SWei Hu 
721ce110ea1SWei Hu 		PULLUP_HDR(mbuf, ehlen + iphlen + sizeof(*th));
722ce110ea1SWei Hu 		th = mtodo(mbuf, ehlen + iphlen);
723ce110ea1SWei Hu 
724ce110ea1SWei Hu 		ip->ip_len = 0;
725ce110ea1SWei Hu 		ip->ip_sum = 0;
726ce110ea1SWei Hu 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
727ce110ea1SWei Hu 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
728ce110ea1SWei Hu 	} else if (etype == ETHERTYPE_IPV6) {
729ce110ea1SWei Hu 		struct ip6_hdr *ip6;
730ce110ea1SWei Hu 
731ce110ea1SWei Hu 		PULLUP_HDR(mbuf, ehlen + sizeof(*ip6) + sizeof(*th));
732ce110ea1SWei Hu 		ip6 = mtodo(mbuf, ehlen);
733ce110ea1SWei Hu 		if (ip6->ip6_nxt != IPPROTO_TCP) {
734ce110ea1SWei Hu 			/* Realy something wrong, just return */
735ce110ea1SWei Hu 			mana_dbg(NULL, "TSO mbuf not TCP, freed.\n");
736ce110ea1SWei Hu 			m_freem(mbuf);
737ce110ea1SWei Hu 			return NULL;
738ce110ea1SWei Hu 		}
739ce110ea1SWei Hu 		mbuf->m_pkthdr.l3hlen = ehlen + sizeof(*ip6);
740ce110ea1SWei Hu 
741ce110ea1SWei Hu 		th = mtodo(mbuf, ehlen + sizeof(*ip6));
742ce110ea1SWei Hu 
743ce110ea1SWei Hu 		ip6->ip6_plen = 0;
744ce110ea1SWei Hu 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
745ce110ea1SWei Hu 	} else {
746ce110ea1SWei Hu 		/* CSUM_TSO is set but not IP protocol. */
747ce110ea1SWei Hu 		mana_warn(NULL, "TSO mbuf not right, freed.\n");
748ce110ea1SWei Hu 		m_freem(mbuf);
749ce110ea1SWei Hu 		return NULL;
750ce110ea1SWei Hu 	}
751ce110ea1SWei Hu 
752ce110ea1SWei Hu 	MANA_L3_PROTO(mbuf) = etype;
753ce110ea1SWei Hu 
754ce110ea1SWei Hu 	return (mbuf);
755ce110ea1SWei Hu }
756ce110ea1SWei Hu 
757ce110ea1SWei Hu /*
758ce110ea1SWei Hu  * If this function failed, the mbuf would be freed.
759ce110ea1SWei Hu  */
760ce110ea1SWei Hu static inline struct mbuf *
mana_mbuf_csum_check(struct mbuf * mbuf)761ce110ea1SWei Hu mana_mbuf_csum_check(struct mbuf *mbuf)
762ce110ea1SWei Hu {
763ce110ea1SWei Hu 	struct ether_vlan_header *eh = mtod(mbuf, struct ether_vlan_header *);
764ce110ea1SWei Hu 	struct mbuf *mbuf_next;
765ce110ea1SWei Hu 	uint16_t etype;
766ce110ea1SWei Hu 	int offset;
767ce110ea1SWei Hu 	int ehlen;
768ce110ea1SWei Hu 
769ce110ea1SWei Hu 	if (eh->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) {
770ce110ea1SWei Hu 		etype = ntohs(eh->evl_proto);
771ce110ea1SWei Hu 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
772ce110ea1SWei Hu 	} else {
773ce110ea1SWei Hu 		etype = ntohs(eh->evl_encap_proto);
774ce110ea1SWei Hu 		ehlen = ETHER_HDR_LEN;
775ce110ea1SWei Hu 	}
776ce110ea1SWei Hu 
777ce110ea1SWei Hu 	mbuf_next = m_getptr(mbuf, ehlen, &offset);
778ce110ea1SWei Hu 
779ce110ea1SWei Hu 	MANA_L4_PROTO(mbuf) = 0;
780ce110ea1SWei Hu 	if (etype == ETHERTYPE_IP) {
781ce110ea1SWei Hu 		const struct ip *ip;
782ce110ea1SWei Hu 		int iphlen;
783ce110ea1SWei Hu 
784ce110ea1SWei Hu 		ip = (struct ip *)(mtodo(mbuf_next, offset));
785ce110ea1SWei Hu 		iphlen = ip->ip_hl << 2;
786ce110ea1SWei Hu 		mbuf->m_pkthdr.l3hlen = ehlen + iphlen;
787ce110ea1SWei Hu 
788ce110ea1SWei Hu 		MANA_L4_PROTO(mbuf) = ip->ip_p;
789ce110ea1SWei Hu 	} else if (etype == ETHERTYPE_IPV6) {
790ce110ea1SWei Hu 		const struct ip6_hdr *ip6;
791ce110ea1SWei Hu 
792ce110ea1SWei Hu 		ip6 = (struct ip6_hdr *)(mtodo(mbuf_next, offset));
793ce110ea1SWei Hu 		mbuf->m_pkthdr.l3hlen = ehlen + sizeof(*ip6);
794ce110ea1SWei Hu 
795ce110ea1SWei Hu 		MANA_L4_PROTO(mbuf) = ip6->ip6_nxt;
796ce110ea1SWei Hu 	} else {
797ce110ea1SWei Hu 		MANA_L4_PROTO(mbuf) = 0;
798ce110ea1SWei Hu 	}
799ce110ea1SWei Hu 
800ce110ea1SWei Hu 	MANA_L3_PROTO(mbuf) = etype;
801ce110ea1SWei Hu 
802ce110ea1SWei Hu 	return (mbuf);
803ce110ea1SWei Hu }
804ce110ea1SWei Hu 
805ce110ea1SWei Hu static int
mana_start_xmit(if_t ifp,struct mbuf * m)80637d22ce0SJustin Hibbits mana_start_xmit(if_t ifp, struct mbuf *m)
807ce110ea1SWei Hu {
808ce110ea1SWei Hu 	struct mana_port_context *apc = if_getsoftc(ifp);
809ce110ea1SWei Hu 	struct mana_txq *txq;
810ce110ea1SWei Hu 	int is_drbr_empty;
811ce110ea1SWei Hu 	uint16_t txq_id;
812ce110ea1SWei Hu 	int err;
813ce110ea1SWei Hu 
814ce110ea1SWei Hu 	if (unlikely((!apc->port_is_up) ||
815ce110ea1SWei Hu 	    (if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0))
816ce110ea1SWei Hu 		return ENODEV;
817ce110ea1SWei Hu 
818ce110ea1SWei Hu 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
819ce110ea1SWei Hu 		m = mana_tso_fixup(m);
820ce110ea1SWei Hu 		if (unlikely(m == NULL)) {
821ce110ea1SWei Hu 			counter_enter();
822ce110ea1SWei Hu 			counter_u64_add_protected(apc->port_stats.tx_drops, 1);
823ce110ea1SWei Hu 			counter_exit();
824ce110ea1SWei Hu 			return EIO;
825ce110ea1SWei Hu 		}
826ce110ea1SWei Hu 	} else {
827ce110ea1SWei Hu 		m = mana_mbuf_csum_check(m);
828ce110ea1SWei Hu 		if (unlikely(m == NULL)) {
829ce110ea1SWei Hu 			counter_enter();
830ce110ea1SWei Hu 			counter_u64_add_protected(apc->port_stats.tx_drops, 1);
831ce110ea1SWei Hu 			counter_exit();
832ce110ea1SWei Hu 			return EIO;
833ce110ea1SWei Hu 		}
834ce110ea1SWei Hu 	}
835ce110ea1SWei Hu 
836ce110ea1SWei Hu 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
837ce110ea1SWei Hu 		uint32_t hash = m->m_pkthdr.flowid;
838ce110ea1SWei Hu 		txq_id = apc->indir_table[(hash) & MANA_INDIRECT_TABLE_MASK] %
839ce110ea1SWei Hu 		    apc->num_queues;
840ce110ea1SWei Hu 	} else {
841ce110ea1SWei Hu 		txq_id = m->m_pkthdr.flowid % apc->num_queues;
842ce110ea1SWei Hu 	}
843ce110ea1SWei Hu 
844ce110ea1SWei Hu 	if (apc->enable_tx_altq)
845ce110ea1SWei Hu 		txq_id = apc->tx_qp[txq_id].txq.alt_txq_idx;
846ce110ea1SWei Hu 
847ce110ea1SWei Hu 	txq = &apc->tx_qp[txq_id].txq;
848ce110ea1SWei Hu 
849ce110ea1SWei Hu 	is_drbr_empty = drbr_empty(ifp, txq->txq_br);
850ce110ea1SWei Hu 	err = drbr_enqueue(ifp, txq->txq_br, m);
851ce110ea1SWei Hu 	if (unlikely(err)) {
852ce110ea1SWei Hu 		mana_warn(NULL, "txq %u failed to enqueue: %d\n",
853ce110ea1SWei Hu 		    txq_id, err);
854ce110ea1SWei Hu 		taskqueue_enqueue(txq->enqueue_tq, &txq->enqueue_task);
855ce110ea1SWei Hu 		return err;
856ce110ea1SWei Hu 	}
857ce110ea1SWei Hu 
858ce110ea1SWei Hu 	if (is_drbr_empty && mtx_trylock(&txq->txq_mtx)) {
859ce110ea1SWei Hu 		mana_xmit(txq);
860ce110ea1SWei Hu 		mtx_unlock(&txq->txq_mtx);
861ce110ea1SWei Hu 	} else {
862ce110ea1SWei Hu 		taskqueue_enqueue(txq->enqueue_tq, &txq->enqueue_task);
863ce110ea1SWei Hu 	}
864ce110ea1SWei Hu 
865ce110ea1SWei Hu 	return 0;
866ce110ea1SWei Hu }
867ce110ea1SWei Hu 
868ce110ea1SWei Hu static void
mana_cleanup_port_context(struct mana_port_context * apc)869ce110ea1SWei Hu mana_cleanup_port_context(struct mana_port_context *apc)
870ce110ea1SWei Hu {
871ce110ea1SWei Hu 	bus_dma_tag_destroy(apc->tx_buf_tag);
872ce110ea1SWei Hu 	bus_dma_tag_destroy(apc->rx_buf_tag);
873ce110ea1SWei Hu 	apc->rx_buf_tag = NULL;
874ce110ea1SWei Hu 
875ce110ea1SWei Hu 	free(apc->rxqs, M_DEVBUF);
876ce110ea1SWei Hu 	apc->rxqs = NULL;
877ce110ea1SWei Hu 
878ce110ea1SWei Hu 	mana_free_counters((counter_u64_t *)&apc->port_stats,
879ce110ea1SWei Hu 	    sizeof(struct mana_port_stats));
880ce110ea1SWei Hu }
881ce110ea1SWei Hu 
882ce110ea1SWei Hu static int
mana_init_port_context(struct mana_port_context * apc)883ce110ea1SWei Hu mana_init_port_context(struct mana_port_context *apc)
884ce110ea1SWei Hu {
885ce110ea1SWei Hu 	device_t dev = apc->ac->gdma_dev->gdma_context->dev;
886ce110ea1SWei Hu 	uint32_t tso_maxsize;
887ce110ea1SWei Hu 	int err;
888ce110ea1SWei Hu 
889643fd7b4SWei Hu 	tso_maxsize = MANA_TSO_MAX_SZ;
890ce110ea1SWei Hu 
891ce110ea1SWei Hu 	/* Create DMA tag for tx bufs */
892ce110ea1SWei Hu 	err = bus_dma_tag_create(bus_get_dma_tag(dev),	/* parent */
893ce110ea1SWei Hu 	    1, 0,			/* alignment, boundary	*/
894ce110ea1SWei Hu 	    BUS_SPACE_MAXADDR,		/* lowaddr		*/
895ce110ea1SWei Hu 	    BUS_SPACE_MAXADDR,		/* highaddr		*/
896ce110ea1SWei Hu 	    NULL, NULL,			/* filter, filterarg	*/
897ce110ea1SWei Hu 	    tso_maxsize,		/* maxsize		*/
898ce110ea1SWei Hu 	    MAX_MBUF_FRAGS,		/* nsegments		*/
899ce110ea1SWei Hu 	    tso_maxsize,		/* maxsegsize		*/
900ce110ea1SWei Hu 	    0,				/* flags		*/
901ce110ea1SWei Hu 	    NULL, NULL,			/* lockfunc, lockfuncarg*/
902ce110ea1SWei Hu 	    &apc->tx_buf_tag);
903ce110ea1SWei Hu 	if (unlikely(err)) {
904ce110ea1SWei Hu 		device_printf(dev, "Feiled to create TX DMA tag\n");
905ce110ea1SWei Hu 		return err;
906ce110ea1SWei Hu 	}
907ce110ea1SWei Hu 
908ce110ea1SWei Hu 	/* Create DMA tag for rx bufs */
909ce110ea1SWei Hu 	err = bus_dma_tag_create(bus_get_dma_tag(dev),	/* parent */
910ce110ea1SWei Hu 	    64, 0,			/* alignment, boundary	*/
911ce110ea1SWei Hu 	    BUS_SPACE_MAXADDR,		/* lowaddr		*/
912ce110ea1SWei Hu 	    BUS_SPACE_MAXADDR,		/* highaddr		*/
913ce110ea1SWei Hu 	    NULL, NULL,			/* filter, filterarg	*/
914ce110ea1SWei Hu 	    MJUMPAGESIZE,		/* maxsize		*/
915ce110ea1SWei Hu 	    1,				/* nsegments		*/
916ce110ea1SWei Hu 	    MJUMPAGESIZE,		/* maxsegsize		*/
917ce110ea1SWei Hu 	    0,				/* flags		*/
918ce110ea1SWei Hu 	    NULL, NULL,			/* lockfunc, lockfuncarg*/
919ce110ea1SWei Hu 	    &apc->rx_buf_tag);
920ce110ea1SWei Hu 	if (unlikely(err)) {
921ce110ea1SWei Hu 		device_printf(dev, "Feiled to create RX DMA tag\n");
922ce110ea1SWei Hu 		return err;
923ce110ea1SWei Hu 	}
924ce110ea1SWei Hu 
925ce110ea1SWei Hu 	apc->rxqs = mallocarray(apc->num_queues, sizeof(struct mana_rxq *),
926ce110ea1SWei Hu 	    M_DEVBUF, M_WAITOK | M_ZERO);
927ce110ea1SWei Hu 
928ce110ea1SWei Hu 	return 0;
929ce110ea1SWei Hu }
930ce110ea1SWei Hu 
931ce110ea1SWei Hu static int
mana_send_request(struct mana_context * ac,void * in_buf,uint32_t in_len,void * out_buf,uint32_t out_len)932ce110ea1SWei Hu mana_send_request(struct mana_context *ac, void *in_buf,
933ce110ea1SWei Hu     uint32_t in_len, void *out_buf, uint32_t out_len)
934ce110ea1SWei Hu {
935ce110ea1SWei Hu 	struct gdma_context *gc = ac->gdma_dev->gdma_context;
936ce110ea1SWei Hu 	struct gdma_resp_hdr *resp = out_buf;
937ce110ea1SWei Hu 	struct gdma_req_hdr *req = in_buf;
938ce110ea1SWei Hu 	device_t dev = gc->dev;
939ce110ea1SWei Hu 	static atomic_t activity_id;
940ce110ea1SWei Hu 	int err;
941ce110ea1SWei Hu 
942ce110ea1SWei Hu 	req->dev_id = gc->mana.dev_id;
943ce110ea1SWei Hu 	req->activity_id = atomic_inc_return(&activity_id);
944ce110ea1SWei Hu 
945ce110ea1SWei Hu 	mana_dbg(NULL, "activity_id  = %u\n", activity_id);
946ce110ea1SWei Hu 
947ce110ea1SWei Hu 	err = mana_gd_send_request(gc, in_len, in_buf, out_len,
948ce110ea1SWei Hu 	    out_buf);
949ce110ea1SWei Hu 	if (err || resp->status) {
950ce110ea1SWei Hu 		device_printf(dev, "Failed to send mana message: %d, 0x%x\n",
951ce110ea1SWei Hu 			err, resp->status);
952ce110ea1SWei Hu 		return err ? err : EPROTO;
953ce110ea1SWei Hu 	}
954ce110ea1SWei Hu 
955ce110ea1SWei Hu 	if (req->dev_id.as_uint32 != resp->dev_id.as_uint32 ||
956ce110ea1SWei Hu 	    req->activity_id != resp->activity_id) {
957ce110ea1SWei Hu 		device_printf(dev,
958ce110ea1SWei Hu 		    "Unexpected mana message response: %x,%x,%x,%x\n",
959ce110ea1SWei Hu 		    req->dev_id.as_uint32, resp->dev_id.as_uint32,
960ce110ea1SWei Hu 		    req->activity_id, resp->activity_id);
961ce110ea1SWei Hu 		return EPROTO;
962ce110ea1SWei Hu 	}
963ce110ea1SWei Hu 
964ce110ea1SWei Hu 	return 0;
965ce110ea1SWei Hu }
966ce110ea1SWei Hu 
967ce110ea1SWei Hu static int
mana_verify_resp_hdr(const struct gdma_resp_hdr * resp_hdr,const enum mana_command_code expected_code,const uint32_t min_size)968ce110ea1SWei Hu mana_verify_resp_hdr(const struct gdma_resp_hdr *resp_hdr,
969ce110ea1SWei Hu     const enum mana_command_code expected_code,
970ce110ea1SWei Hu     const uint32_t min_size)
971ce110ea1SWei Hu {
972ce110ea1SWei Hu 	if (resp_hdr->response.msg_type != expected_code)
973ce110ea1SWei Hu 		return EPROTO;
974ce110ea1SWei Hu 
975ce110ea1SWei Hu 	if (resp_hdr->response.msg_version < GDMA_MESSAGE_V1)
976ce110ea1SWei Hu 		return EPROTO;
977ce110ea1SWei Hu 
978ce110ea1SWei Hu 	if (resp_hdr->response.msg_size < min_size)
979ce110ea1SWei Hu 		return EPROTO;
980ce110ea1SWei Hu 
981ce110ea1SWei Hu 	return 0;
982ce110ea1SWei Hu }
983ce110ea1SWei Hu 
984ce110ea1SWei Hu static int
mana_query_device_cfg(struct mana_context * ac,uint32_t proto_major_ver,uint32_t proto_minor_ver,uint32_t proto_micro_ver,uint16_t * max_num_vports)985ce110ea1SWei Hu mana_query_device_cfg(struct mana_context *ac, uint32_t proto_major_ver,
986ce110ea1SWei Hu     uint32_t proto_minor_ver, uint32_t proto_micro_ver,
987ce110ea1SWei Hu     uint16_t *max_num_vports)
988ce110ea1SWei Hu {
989ce110ea1SWei Hu 	struct gdma_context *gc = ac->gdma_dev->gdma_context;
990ce110ea1SWei Hu 	struct mana_query_device_cfg_resp resp = {};
991ce110ea1SWei Hu 	struct mana_query_device_cfg_req req = {};
992ce110ea1SWei Hu 	device_t dev = gc->dev;
993ce110ea1SWei Hu 	int err = 0;
994ce110ea1SWei Hu 
995ce110ea1SWei Hu 	mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_DEV_CONFIG,
996ce110ea1SWei Hu 	    sizeof(req), sizeof(resp));
997ce110ea1SWei Hu 	req.proto_major_ver = proto_major_ver;
998ce110ea1SWei Hu 	req.proto_minor_ver = proto_minor_ver;
999ce110ea1SWei Hu 	req.proto_micro_ver = proto_micro_ver;
1000ce110ea1SWei Hu 
1001ce110ea1SWei Hu 	err = mana_send_request(ac, &req, sizeof(req), &resp, sizeof(resp));
1002ce110ea1SWei Hu 	if (err) {
1003ce110ea1SWei Hu 		device_printf(dev, "Failed to query config: %d", err);
1004ce110ea1SWei Hu 		return err;
1005ce110ea1SWei Hu 	}
1006ce110ea1SWei Hu 
1007ce110ea1SWei Hu 	err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_DEV_CONFIG,
1008ce110ea1SWei Hu 	    sizeof(resp));
1009ce110ea1SWei Hu 	if (err || resp.hdr.status) {
1010ce110ea1SWei Hu 		device_printf(dev, "Invalid query result: %d, 0x%x\n", err,
1011ce110ea1SWei Hu 		    resp.hdr.status);
1012ce110ea1SWei Hu 		if (!err)
1013ce110ea1SWei Hu 			err = EPROTO;
1014ce110ea1SWei Hu 		return err;
1015ce110ea1SWei Hu 	}
1016ce110ea1SWei Hu 
1017ce110ea1SWei Hu 	*max_num_vports = resp.max_num_vports;
1018ce110ea1SWei Hu 
1019ce110ea1SWei Hu 	mana_dbg(NULL, "mana max_num_vports from device = %d\n",
1020ce110ea1SWei Hu 	    *max_num_vports);
1021ce110ea1SWei Hu 
1022ce110ea1SWei Hu 	return 0;
1023ce110ea1SWei Hu }
1024ce110ea1SWei Hu 
1025ce110ea1SWei Hu static int
mana_query_vport_cfg(struct mana_port_context * apc,uint32_t vport_index,uint32_t * max_sq,uint32_t * max_rq,uint32_t * num_indir_entry)1026ce110ea1SWei Hu mana_query_vport_cfg(struct mana_port_context *apc, uint32_t vport_index,
1027ce110ea1SWei Hu     uint32_t *max_sq, uint32_t *max_rq, uint32_t *num_indir_entry)
1028ce110ea1SWei Hu {
1029ce110ea1SWei Hu 	struct mana_query_vport_cfg_resp resp = {};
1030ce110ea1SWei Hu 	struct mana_query_vport_cfg_req req = {};
1031ce110ea1SWei Hu 	int err;
1032ce110ea1SWei Hu 
1033ce110ea1SWei Hu 	mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_VPORT_CONFIG,
1034ce110ea1SWei Hu 	    sizeof(req), sizeof(resp));
1035ce110ea1SWei Hu 
1036ce110ea1SWei Hu 	req.vport_index = vport_index;
1037ce110ea1SWei Hu 
1038ce110ea1SWei Hu 	err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
1039ce110ea1SWei Hu 	    sizeof(resp));
1040ce110ea1SWei Hu 	if (err)
1041ce110ea1SWei Hu 		return err;
1042ce110ea1SWei Hu 
1043ce110ea1SWei Hu 	err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_VPORT_CONFIG,
1044ce110ea1SWei Hu 	    sizeof(resp));
1045ce110ea1SWei Hu 	if (err)
1046ce110ea1SWei Hu 		return err;
1047ce110ea1SWei Hu 
1048ce110ea1SWei Hu 	if (resp.hdr.status)
1049ce110ea1SWei Hu 		return EPROTO;
1050ce110ea1SWei Hu 
1051ce110ea1SWei Hu 	*max_sq = resp.max_num_sq;
1052ce110ea1SWei Hu 	*max_rq = resp.max_num_rq;
1053ce110ea1SWei Hu 	*num_indir_entry = resp.num_indirection_ent;
1054ce110ea1SWei Hu 
1055ce110ea1SWei Hu 	apc->port_handle = resp.vport;
1056ce110ea1SWei Hu 	memcpy(apc->mac_addr, resp.mac_addr, ETHER_ADDR_LEN);
1057ce110ea1SWei Hu 
1058ce110ea1SWei Hu 	return 0;
1059ce110ea1SWei Hu }
1060ce110ea1SWei Hu 
1061b685df31SWei Hu void
mana_uncfg_vport(struct mana_port_context * apc)1062b685df31SWei Hu mana_uncfg_vport(struct mana_port_context *apc)
1063b685df31SWei Hu {
1064b685df31SWei Hu 	apc->vport_use_count--;
1065b685df31SWei Hu 	if (apc->vport_use_count < 0) {
1066b685df31SWei Hu 		mana_err(NULL,
1067b685df31SWei Hu 		    "WARNING: vport_use_count less than 0: %u\n",
1068b685df31SWei Hu 		    apc->vport_use_count);
1069b685df31SWei Hu 	}
1070b685df31SWei Hu }
1071b685df31SWei Hu 
1072b685df31SWei Hu int
mana_cfg_vport(struct mana_port_context * apc,uint32_t protection_dom_id,uint32_t doorbell_pg_id)1073ce110ea1SWei Hu mana_cfg_vport(struct mana_port_context *apc, uint32_t protection_dom_id,
1074ce110ea1SWei Hu     uint32_t doorbell_pg_id)
1075ce110ea1SWei Hu {
1076ce110ea1SWei Hu 	struct mana_config_vport_resp resp = {};
1077ce110ea1SWei Hu 	struct mana_config_vport_req req = {};
1078ce110ea1SWei Hu 	int err;
1079ce110ea1SWei Hu 
1080b685df31SWei Hu 	/* This function is used to program the Ethernet port in the hardware
1081b685df31SWei Hu 	 * table. It can be called from the Ethernet driver or the RDMA driver.
1082b685df31SWei Hu 	 *
1083b685df31SWei Hu 	 * For Ethernet usage, the hardware supports only one active user on a
1084b685df31SWei Hu 	 * physical port. The driver checks on the port usage before programming
1085b685df31SWei Hu 	 * the hardware when creating the RAW QP (RDMA driver) or exposing the
1086b685df31SWei Hu 	 * device to kernel NET layer (Ethernet driver).
1087b685df31SWei Hu 	 *
1088b685df31SWei Hu 	 * Because the RDMA driver doesn't know in advance which QP type the
1089b685df31SWei Hu 	 * user will create, it exposes the device with all its ports. The user
1090b685df31SWei Hu 	 * may not be able to create RAW QP on a port if this port is already
1091b685df31SWei Hu 	 * in used by the Ethernet driver from the kernel.
1092b685df31SWei Hu 	 *
1093b685df31SWei Hu 	 * This physical port limitation only applies to the RAW QP. For RC QP,
1094b685df31SWei Hu 	 * the hardware doesn't have this limitation. The user can create RC
1095b685df31SWei Hu 	 * QPs on a physical port up to the hardware limits independent of the
1096b685df31SWei Hu 	 * Ethernet usage on the same port.
1097b685df31SWei Hu 	 */
1098b685df31SWei Hu 	if (apc->vport_use_count > 0) {
1099b685df31SWei Hu 		return EBUSY;
1100b685df31SWei Hu 	}
1101b685df31SWei Hu 	apc->vport_use_count++;
1102b685df31SWei Hu 
1103ce110ea1SWei Hu 	mana_gd_init_req_hdr(&req.hdr, MANA_CONFIG_VPORT_TX,
1104ce110ea1SWei Hu 	    sizeof(req), sizeof(resp));
1105ce110ea1SWei Hu 	req.vport = apc->port_handle;
1106ce110ea1SWei Hu 	req.pdid = protection_dom_id;
1107ce110ea1SWei Hu 	req.doorbell_pageid = doorbell_pg_id;
1108ce110ea1SWei Hu 
1109ce110ea1SWei Hu 	err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
1110ce110ea1SWei Hu 	    sizeof(resp));
1111ce110ea1SWei Hu 	if (err) {
1112ce110ea1SWei Hu 		if_printf(apc->ndev, "Failed to configure vPort: %d\n", err);
1113ce110ea1SWei Hu 		goto out;
1114ce110ea1SWei Hu 	}
1115ce110ea1SWei Hu 
1116ce110ea1SWei Hu 	err = mana_verify_resp_hdr(&resp.hdr, MANA_CONFIG_VPORT_TX,
1117ce110ea1SWei Hu 	    sizeof(resp));
1118ce110ea1SWei Hu 	if (err || resp.hdr.status) {
1119ce110ea1SWei Hu 		if_printf(apc->ndev, "Failed to configure vPort: %d, 0x%x\n",
1120ce110ea1SWei Hu 		    err, resp.hdr.status);
1121ce110ea1SWei Hu 		if (!err)
1122ce110ea1SWei Hu 			err = EPROTO;
1123ce110ea1SWei Hu 
1124ce110ea1SWei Hu 		goto out;
1125ce110ea1SWei Hu 	}
1126ce110ea1SWei Hu 
1127ce110ea1SWei Hu 	apc->tx_shortform_allowed = resp.short_form_allowed;
1128ce110ea1SWei Hu 	apc->tx_vp_offset = resp.tx_vport_offset;
1129b685df31SWei Hu 
1130d0b5e4a3SLi-Wen Hsu 	if_printf(apc->ndev, "Configured vPort %ju PD %u DB %u\n",
1131b685df31SWei Hu 	    apc->port_handle, protection_dom_id, doorbell_pg_id);
11329e772f20SWei Hu 
1133ce110ea1SWei Hu out:
1134b685df31SWei Hu 	if (err)
1135b685df31SWei Hu 		mana_uncfg_vport(apc);
1136b685df31SWei Hu 
1137ce110ea1SWei Hu 	return err;
1138ce110ea1SWei Hu }
1139ce110ea1SWei Hu 
1140ce110ea1SWei Hu static int
mana_cfg_vport_steering(struct mana_port_context * apc,enum TRI_STATE rx,bool update_default_rxobj,bool update_key,bool update_tab)1141ce110ea1SWei Hu mana_cfg_vport_steering(struct mana_port_context *apc,
1142ce110ea1SWei Hu     enum TRI_STATE rx,
1143ce110ea1SWei Hu     bool update_default_rxobj, bool update_key,
1144ce110ea1SWei Hu     bool update_tab)
1145ce110ea1SWei Hu {
1146ce110ea1SWei Hu 	uint16_t num_entries = MANA_INDIRECT_TABLE_SIZE;
1147ce110ea1SWei Hu 	struct mana_cfg_rx_steer_req *req = NULL;
1148ce110ea1SWei Hu 	struct mana_cfg_rx_steer_resp resp = {};
114937d22ce0SJustin Hibbits 	if_t ndev = apc->ndev;
1150ce110ea1SWei Hu 	mana_handle_t *req_indir_tab;
1151ce110ea1SWei Hu 	uint32_t req_buf_size;
1152ce110ea1SWei Hu 	int err;
1153ce110ea1SWei Hu 
1154ce110ea1SWei Hu 	req_buf_size = sizeof(*req) + sizeof(mana_handle_t) * num_entries;
1155ce110ea1SWei Hu 	req = malloc(req_buf_size, M_DEVBUF, M_WAITOK | M_ZERO);
1156ce110ea1SWei Hu 
1157ce110ea1SWei Hu 	mana_gd_init_req_hdr(&req->hdr, MANA_CONFIG_VPORT_RX, req_buf_size,
1158ce110ea1SWei Hu 	    sizeof(resp));
1159ce110ea1SWei Hu 
1160ce110ea1SWei Hu 	req->vport = apc->port_handle;
1161ce110ea1SWei Hu 	req->num_indir_entries = num_entries;
1162ce110ea1SWei Hu 	req->indir_tab_offset = sizeof(*req);
1163ce110ea1SWei Hu 	req->rx_enable = rx;
1164ce110ea1SWei Hu 	req->rss_enable = apc->rss_state;
1165ce110ea1SWei Hu 	req->update_default_rxobj = update_default_rxobj;
1166ce110ea1SWei Hu 	req->update_hashkey = update_key;
1167ce110ea1SWei Hu 	req->update_indir_tab = update_tab;
1168ce110ea1SWei Hu 	req->default_rxobj = apc->default_rxobj;
1169ce110ea1SWei Hu 
1170ce110ea1SWei Hu 	if (update_key)
1171ce110ea1SWei Hu 		memcpy(&req->hashkey, apc->hashkey, MANA_HASH_KEY_SIZE);
1172ce110ea1SWei Hu 
1173ce110ea1SWei Hu 	if (update_tab) {
1174ce110ea1SWei Hu 		req_indir_tab = (mana_handle_t *)(req + 1);
1175ce110ea1SWei Hu 		memcpy(req_indir_tab, apc->rxobj_table,
1176ce110ea1SWei Hu 		       req->num_indir_entries * sizeof(mana_handle_t));
1177ce110ea1SWei Hu 	}
1178ce110ea1SWei Hu 
1179ce110ea1SWei Hu 	err = mana_send_request(apc->ac, req, req_buf_size, &resp,
1180ce110ea1SWei Hu 	    sizeof(resp));
1181ce110ea1SWei Hu 	if (err) {
1182ce110ea1SWei Hu 		if_printf(ndev, "Failed to configure vPort RX: %d\n", err);
1183ce110ea1SWei Hu 		goto out;
1184ce110ea1SWei Hu 	}
1185ce110ea1SWei Hu 
1186ce110ea1SWei Hu 	err = mana_verify_resp_hdr(&resp.hdr, MANA_CONFIG_VPORT_RX,
1187ce110ea1SWei Hu 	    sizeof(resp));
1188ce110ea1SWei Hu 	if (err) {
1189ce110ea1SWei Hu 		if_printf(ndev, "vPort RX configuration failed: %d\n", err);
1190ce110ea1SWei Hu 		goto out;
1191ce110ea1SWei Hu 	}
1192ce110ea1SWei Hu 
1193ce110ea1SWei Hu 	if (resp.hdr.status) {
1194ce110ea1SWei Hu 		if_printf(ndev, "vPort RX configuration failed: 0x%x\n",
1195ce110ea1SWei Hu 		    resp.hdr.status);
1196ce110ea1SWei Hu 		err = EPROTO;
1197ce110ea1SWei Hu 	}
1198b685df31SWei Hu 
1199d0b5e4a3SLi-Wen Hsu 	if_printf(ndev, "Configured steering vPort %ju entries %u\n",
1200b685df31SWei Hu 	    apc->port_handle, num_entries);
12019e772f20SWei Hu 
1202ce110ea1SWei Hu out:
1203ce110ea1SWei Hu 	free(req, M_DEVBUF);
1204ce110ea1SWei Hu 	return err;
1205ce110ea1SWei Hu }
1206ce110ea1SWei Hu 
1207b685df31SWei Hu int
mana_create_wq_obj(struct mana_port_context * apc,mana_handle_t vport,uint32_t wq_type,struct mana_obj_spec * wq_spec,struct mana_obj_spec * cq_spec,mana_handle_t * wq_obj)1208ce110ea1SWei Hu mana_create_wq_obj(struct mana_port_context *apc,
1209ce110ea1SWei Hu     mana_handle_t vport,
1210ce110ea1SWei Hu     uint32_t wq_type, struct mana_obj_spec *wq_spec,
1211ce110ea1SWei Hu     struct mana_obj_spec *cq_spec,
1212ce110ea1SWei Hu     mana_handle_t *wq_obj)
1213ce110ea1SWei Hu {
1214ce110ea1SWei Hu 	struct mana_create_wqobj_resp resp = {};
1215ce110ea1SWei Hu 	struct mana_create_wqobj_req req = {};
121637d22ce0SJustin Hibbits 	if_t ndev = apc->ndev;
1217ce110ea1SWei Hu 	int err;
1218ce110ea1SWei Hu 
1219ce110ea1SWei Hu 	mana_gd_init_req_hdr(&req.hdr, MANA_CREATE_WQ_OBJ,
1220ce110ea1SWei Hu 	    sizeof(req), sizeof(resp));
1221ce110ea1SWei Hu 	req.vport = vport;
1222ce110ea1SWei Hu 	req.wq_type = wq_type;
1223ce110ea1SWei Hu 	req.wq_gdma_region = wq_spec->gdma_region;
1224ce110ea1SWei Hu 	req.cq_gdma_region = cq_spec->gdma_region;
1225ce110ea1SWei Hu 	req.wq_size = wq_spec->queue_size;
1226ce110ea1SWei Hu 	req.cq_size = cq_spec->queue_size;
1227ce110ea1SWei Hu 	req.cq_moderation_ctx_id = cq_spec->modr_ctx_id;
1228ce110ea1SWei Hu 	req.cq_parent_qid = cq_spec->attached_eq;
1229ce110ea1SWei Hu 
1230ce110ea1SWei Hu 	err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
1231ce110ea1SWei Hu 	    sizeof(resp));
1232ce110ea1SWei Hu 	if (err) {
1233ce110ea1SWei Hu 		if_printf(ndev, "Failed to create WQ object: %d\n", err);
1234ce110ea1SWei Hu 		goto out;
1235ce110ea1SWei Hu 	}
1236ce110ea1SWei Hu 
1237ce110ea1SWei Hu 	err = mana_verify_resp_hdr(&resp.hdr, MANA_CREATE_WQ_OBJ,
1238ce110ea1SWei Hu 	    sizeof(resp));
1239ce110ea1SWei Hu 	if (err || resp.hdr.status) {
1240ce110ea1SWei Hu 		if_printf(ndev, "Failed to create WQ object: %d, 0x%x\n", err,
1241ce110ea1SWei Hu 		    resp.hdr.status);
1242ce110ea1SWei Hu 		if (!err)
1243ce110ea1SWei Hu 			err = EPROTO;
1244ce110ea1SWei Hu 		goto out;
1245ce110ea1SWei Hu 	}
1246ce110ea1SWei Hu 
1247ce110ea1SWei Hu 	if (resp.wq_obj == INVALID_MANA_HANDLE) {
1248ce110ea1SWei Hu 		if_printf(ndev, "Got an invalid WQ object handle\n");
1249ce110ea1SWei Hu 		err = EPROTO;
1250ce110ea1SWei Hu 		goto out;
1251ce110ea1SWei Hu 	}
1252ce110ea1SWei Hu 
1253ce110ea1SWei Hu 	*wq_obj = resp.wq_obj;
1254ce110ea1SWei Hu 	wq_spec->queue_index = resp.wq_id;
1255ce110ea1SWei Hu 	cq_spec->queue_index = resp.cq_id;
1256ce110ea1SWei Hu 
1257ce110ea1SWei Hu 	return 0;
1258ce110ea1SWei Hu out:
1259ce110ea1SWei Hu 	return err;
1260ce110ea1SWei Hu }
1261ce110ea1SWei Hu 
1262b685df31SWei Hu void
mana_destroy_wq_obj(struct mana_port_context * apc,uint32_t wq_type,mana_handle_t wq_obj)1263ce110ea1SWei Hu mana_destroy_wq_obj(struct mana_port_context *apc, uint32_t wq_type,
1264ce110ea1SWei Hu     mana_handle_t wq_obj)
1265ce110ea1SWei Hu {
1266ce110ea1SWei Hu 	struct mana_destroy_wqobj_resp resp = {};
1267ce110ea1SWei Hu 	struct mana_destroy_wqobj_req req = {};
126837d22ce0SJustin Hibbits 	if_t ndev = apc->ndev;
1269ce110ea1SWei Hu 	int err;
1270ce110ea1SWei Hu 
1271ce110ea1SWei Hu 	mana_gd_init_req_hdr(&req.hdr, MANA_DESTROY_WQ_OBJ,
1272ce110ea1SWei Hu 	    sizeof(req), sizeof(resp));
1273ce110ea1SWei Hu 	req.wq_type = wq_type;
1274ce110ea1SWei Hu 	req.wq_obj_handle = wq_obj;
1275ce110ea1SWei Hu 
1276ce110ea1SWei Hu 	err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
1277ce110ea1SWei Hu 	    sizeof(resp));
1278ce110ea1SWei Hu 	if (err) {
1279ce110ea1SWei Hu 		if_printf(ndev, "Failed to destroy WQ object: %d\n", err);
1280ce110ea1SWei Hu 		return;
1281ce110ea1SWei Hu 	}
1282ce110ea1SWei Hu 
1283ce110ea1SWei Hu 	err = mana_verify_resp_hdr(&resp.hdr, MANA_DESTROY_WQ_OBJ,
1284ce110ea1SWei Hu 	    sizeof(resp));
1285ce110ea1SWei Hu 	if (err || resp.hdr.status)
1286ce110ea1SWei Hu 		if_printf(ndev, "Failed to destroy WQ object: %d, 0x%x\n",
1287ce110ea1SWei Hu 		    err, resp.hdr.status);
1288ce110ea1SWei Hu }
1289ce110ea1SWei Hu 
1290ce110ea1SWei Hu static void
mana_destroy_eq(struct mana_context * ac)12911833cf13SWei Hu mana_destroy_eq(struct mana_context *ac)
1292ce110ea1SWei Hu {
12931833cf13SWei Hu 	struct gdma_context *gc = ac->gdma_dev->gdma_context;
1294ce110ea1SWei Hu 	struct gdma_queue *eq;
1295ce110ea1SWei Hu 	int i;
1296ce110ea1SWei Hu 
12971833cf13SWei Hu 	if (!ac->eqs)
1298ce110ea1SWei Hu 		return;
1299ce110ea1SWei Hu 
13001833cf13SWei Hu 	for (i = 0; i < gc->max_num_queues; i++) {
13011833cf13SWei Hu 		eq = ac->eqs[i].eq;
1302ce110ea1SWei Hu 		if (!eq)
1303ce110ea1SWei Hu 			continue;
1304ce110ea1SWei Hu 
1305ce110ea1SWei Hu 		mana_gd_destroy_queue(gc, eq);
1306ce110ea1SWei Hu 	}
1307ce110ea1SWei Hu 
13081833cf13SWei Hu 	free(ac->eqs, M_DEVBUF);
13091833cf13SWei Hu 	ac->eqs = NULL;
1310ce110ea1SWei Hu }
1311ce110ea1SWei Hu 
1312ce110ea1SWei Hu static int
mana_create_eq(struct mana_context * ac)13131833cf13SWei Hu mana_create_eq(struct mana_context *ac)
1314ce110ea1SWei Hu {
13151833cf13SWei Hu 	struct gdma_dev *gd = ac->gdma_dev;
13161833cf13SWei Hu 	struct gdma_context *gc = gd->gdma_context;
1317ce110ea1SWei Hu 	struct gdma_queue_spec spec = {};
1318ce110ea1SWei Hu 	int err;
1319ce110ea1SWei Hu 	int i;
1320ce110ea1SWei Hu 
13211833cf13SWei Hu 	ac->eqs = mallocarray(gc->max_num_queues, sizeof(struct mana_eq),
1322ce110ea1SWei Hu 	    M_DEVBUF, M_WAITOK | M_ZERO);
1323ce110ea1SWei Hu 
1324ce110ea1SWei Hu 	spec.type = GDMA_EQ;
1325ce110ea1SWei Hu 	spec.monitor_avl_buf = false;
1326ce110ea1SWei Hu 	spec.queue_size = EQ_SIZE;
1327ce110ea1SWei Hu 	spec.eq.callback = NULL;
13281833cf13SWei Hu 	spec.eq.context = ac->eqs;
1329ce110ea1SWei Hu 	spec.eq.log2_throttle_limit = LOG2_EQ_THROTTLE;
1330ce110ea1SWei Hu 
13311833cf13SWei Hu 	for (i = 0; i < gc->max_num_queues; i++) {
13321833cf13SWei Hu 		err = mana_gd_create_mana_eq(gd, &spec, &ac->eqs[i].eq);
1333ce110ea1SWei Hu 		if (err)
1334ce110ea1SWei Hu 			goto out;
1335ce110ea1SWei Hu 	}
1336ce110ea1SWei Hu 
1337ce110ea1SWei Hu 	return 0;
1338ce110ea1SWei Hu out:
13391833cf13SWei Hu 	mana_destroy_eq(ac);
1340ce110ea1SWei Hu 	return err;
1341ce110ea1SWei Hu }
1342ce110ea1SWei Hu 
1343ce110ea1SWei Hu static int
mana_fence_rq(struct mana_port_context * apc,struct mana_rxq * rxq)1344aa108bc7SWei Hu mana_fence_rq(struct mana_port_context *apc, struct mana_rxq *rxq)
1345aa108bc7SWei Hu {
1346aa108bc7SWei Hu 	struct mana_fence_rq_resp resp = {};
1347aa108bc7SWei Hu 	struct mana_fence_rq_req req = {};
1348aa108bc7SWei Hu 	int err;
1349aa108bc7SWei Hu 
1350aa108bc7SWei Hu 	init_completion(&rxq->fence_event);
1351aa108bc7SWei Hu 
1352aa108bc7SWei Hu 	mana_gd_init_req_hdr(&req.hdr, MANA_FENCE_RQ,
1353aa108bc7SWei Hu 	    sizeof(req), sizeof(resp));
1354aa108bc7SWei Hu 	req.wq_obj_handle = rxq->rxobj;
1355aa108bc7SWei Hu 
1356aa108bc7SWei Hu 	err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
1357aa108bc7SWei Hu 	    sizeof(resp));
1358aa108bc7SWei Hu 	if (err) {
1359aa108bc7SWei Hu 		if_printf(apc->ndev, "Failed to fence RQ %u: %d\n",
1360aa108bc7SWei Hu 		    rxq->rxq_idx, err);
1361aa108bc7SWei Hu 		return err;
1362aa108bc7SWei Hu 	}
1363aa108bc7SWei Hu 
1364aa108bc7SWei Hu 	err = mana_verify_resp_hdr(&resp.hdr, MANA_FENCE_RQ, sizeof(resp));
1365aa108bc7SWei Hu 	if (err || resp.hdr.status) {
1366aa108bc7SWei Hu 		if_printf(apc->ndev, "Failed to fence RQ %u: %d, 0x%x\n",
1367aa108bc7SWei Hu 		    rxq->rxq_idx, err, resp.hdr.status);
1368aa108bc7SWei Hu 		if (!err)
1369aa108bc7SWei Hu 			err = EPROTO;
1370aa108bc7SWei Hu 
1371aa108bc7SWei Hu 		return err;
1372aa108bc7SWei Hu 	}
1373aa108bc7SWei Hu 
1374aa108bc7SWei Hu 	if (wait_for_completion_timeout(&rxq->fence_event, 10 * hz)) {
1375aa108bc7SWei Hu 		if_printf(apc->ndev, "Failed to fence RQ %u: timed out\n",
1376aa108bc7SWei Hu 		    rxq->rxq_idx);
1377aa108bc7SWei Hu 		return ETIMEDOUT;
1378aa108bc7SWei Hu         }
1379aa108bc7SWei Hu 
1380aa108bc7SWei Hu 	return 0;
1381aa108bc7SWei Hu }
1382aa108bc7SWei Hu 
1383aa108bc7SWei Hu static void
mana_fence_rqs(struct mana_port_context * apc)1384aa108bc7SWei Hu mana_fence_rqs(struct mana_port_context *apc)
1385aa108bc7SWei Hu {
1386aa108bc7SWei Hu 	unsigned int rxq_idx;
1387aa108bc7SWei Hu 	struct mana_rxq *rxq;
1388aa108bc7SWei Hu 	int err;
1389aa108bc7SWei Hu 
1390aa108bc7SWei Hu 	for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) {
1391aa108bc7SWei Hu 		rxq = apc->rxqs[rxq_idx];
1392aa108bc7SWei Hu 		err = mana_fence_rq(apc, rxq);
1393aa108bc7SWei Hu 
1394aa108bc7SWei Hu 		/* In case of any error, use sleep instead. */
1395aa108bc7SWei Hu 		if (err)
1396aa108bc7SWei Hu 			gdma_msleep(100);
1397aa108bc7SWei Hu 	}
1398aa108bc7SWei Hu }
1399aa108bc7SWei Hu 
1400aa108bc7SWei Hu static int
mana_move_wq_tail(struct gdma_queue * wq,uint32_t num_units)1401ce110ea1SWei Hu mana_move_wq_tail(struct gdma_queue *wq, uint32_t num_units)
1402ce110ea1SWei Hu {
1403ce110ea1SWei Hu 	uint32_t used_space_old;
1404ce110ea1SWei Hu 	uint32_t used_space_new;
1405ce110ea1SWei Hu 
1406ce110ea1SWei Hu 	used_space_old = wq->head - wq->tail;
1407ce110ea1SWei Hu 	used_space_new = wq->head - (wq->tail + num_units);
1408ce110ea1SWei Hu 
1409ce110ea1SWei Hu 	if (used_space_new > used_space_old) {
1410ce110ea1SWei Hu 		mana_err(NULL,
1411ce110ea1SWei Hu 		    "WARNING: new used space %u greater than old one %u\n",
1412ce110ea1SWei Hu 		    used_space_new, used_space_old);
1413ce110ea1SWei Hu 		return ERANGE;
1414ce110ea1SWei Hu 	}
1415ce110ea1SWei Hu 
1416ce110ea1SWei Hu 	wq->tail += num_units;
1417ce110ea1SWei Hu 	return 0;
1418ce110ea1SWei Hu }
1419ce110ea1SWei Hu 
1420ce110ea1SWei Hu static void
mana_poll_tx_cq(struct mana_cq * cq)1421ce110ea1SWei Hu mana_poll_tx_cq(struct mana_cq *cq)
1422ce110ea1SWei Hu {
1423ce110ea1SWei Hu 	struct gdma_comp *completions = cq->gdma_comp_buf;
1424ce110ea1SWei Hu 	struct gdma_posted_wqe_info *wqe_info;
1425ce110ea1SWei Hu 	struct mana_send_buf_info *tx_info;
1426ce110ea1SWei Hu 	unsigned int pkt_transmitted = 0;
1427ce110ea1SWei Hu 	unsigned int wqe_unit_cnt = 0;
1428ce110ea1SWei Hu 	struct mana_txq *txq = cq->txq;
1429ce110ea1SWei Hu 	struct mana_port_context *apc;
1430a18e9994SWei Hu 	unsigned int tx_queue_size;
1431ce110ea1SWei Hu 	uint16_t next_to_complete;
143237d22ce0SJustin Hibbits 	if_t ndev;
1433ce110ea1SWei Hu 	int comp_read;
14346ccf4f40SZhenlei Huang 	int txq_idx = txq->idx;
1435ce110ea1SWei Hu 	int i;
1436ce110ea1SWei Hu 	int sa_drop = 0;
1437ce110ea1SWei Hu 
1438ce110ea1SWei Hu 	struct gdma_queue *gdma_wq;
1439ce110ea1SWei Hu 	unsigned int avail_space;
1440ce110ea1SWei Hu 	bool txq_full = false;
1441ce110ea1SWei Hu 
1442ce110ea1SWei Hu 	ndev = txq->ndev;
1443ce110ea1SWei Hu 	apc = if_getsoftc(ndev);
1444a18e9994SWei Hu 	tx_queue_size = apc->tx_queue_size;
1445ce110ea1SWei Hu 
1446ce110ea1SWei Hu 	comp_read = mana_gd_poll_cq(cq->gdma_cq, completions,
1447ce110ea1SWei Hu 	    CQE_POLLING_BUFFER);
1448ce110ea1SWei Hu 
14491833cf13SWei Hu 	if (comp_read < 1)
14501833cf13SWei Hu 		return;
14511833cf13SWei Hu 
1452ce110ea1SWei Hu 	next_to_complete = txq->next_to_complete;
1453ce110ea1SWei Hu 
1454ce110ea1SWei Hu 	for (i = 0; i < comp_read; i++) {
1455ce110ea1SWei Hu 		struct mana_tx_comp_oob *cqe_oob;
1456ce110ea1SWei Hu 
1457ce110ea1SWei Hu 		if (!completions[i].is_sq) {
1458ce110ea1SWei Hu 			mana_err(NULL, "WARNING: Not for SQ\n");
1459ce110ea1SWei Hu 			return;
1460ce110ea1SWei Hu 		}
1461ce110ea1SWei Hu 
1462ce110ea1SWei Hu 		cqe_oob = (struct mana_tx_comp_oob *)completions[i].cqe_data;
1463ce110ea1SWei Hu 		if (cqe_oob->cqe_hdr.client_type !=
1464ce110ea1SWei Hu 				 MANA_CQE_COMPLETION) {
1465ce110ea1SWei Hu 			mana_err(NULL,
1466ce110ea1SWei Hu 			    "WARNING: Invalid CQE client type %u\n",
1467ce110ea1SWei Hu 			    cqe_oob->cqe_hdr.client_type);
1468ce110ea1SWei Hu 			return;
1469ce110ea1SWei Hu 		}
1470ce110ea1SWei Hu 
1471ce110ea1SWei Hu 		switch (cqe_oob->cqe_hdr.cqe_type) {
1472ce110ea1SWei Hu 		case CQE_TX_OKAY:
1473ce110ea1SWei Hu 			break;
1474ce110ea1SWei Hu 
1475ce110ea1SWei Hu 		case CQE_TX_SA_DROP:
1476ce110ea1SWei Hu 		case CQE_TX_MTU_DROP:
1477ce110ea1SWei Hu 		case CQE_TX_INVALID_OOB:
1478ce110ea1SWei Hu 		case CQE_TX_INVALID_ETH_TYPE:
1479ce110ea1SWei Hu 		case CQE_TX_HDR_PROCESSING_ERROR:
1480ce110ea1SWei Hu 		case CQE_TX_VF_DISABLED:
1481ce110ea1SWei Hu 		case CQE_TX_VPORT_IDX_OUT_OF_RANGE:
1482ce110ea1SWei Hu 		case CQE_TX_VPORT_DISABLED:
1483ce110ea1SWei Hu 		case CQE_TX_VLAN_TAGGING_VIOLATION:
1484ce110ea1SWei Hu 			sa_drop ++;
1485516b5059SWei Hu 			mana_dbg(NULL,
1486ce110ea1SWei Hu 			    "TX: txq %d CQE error %d, ntc = %d, "
1487ce110ea1SWei Hu 			    "pending sends = %d: err ignored.\n",
1488ce110ea1SWei Hu 			    txq_idx, cqe_oob->cqe_hdr.cqe_type,
1489ce110ea1SWei Hu 			    next_to_complete, txq->pending_sends);
1490516b5059SWei Hu 			counter_u64_add(txq->stats.cqe_err, 1);
1491ce110ea1SWei Hu 			break;
1492ce110ea1SWei Hu 
1493ce110ea1SWei Hu 		default:
1494516b5059SWei Hu 			/* If the CQE type is unknown, log a debug msg,
1495516b5059SWei Hu 			 * and still free the mbuf, etc.
1496ce110ea1SWei Hu 			 */
1497516b5059SWei Hu 			mana_dbg(NULL,
1498516b5059SWei Hu 			    "ERROR: TX: Unknown CQE type %d\n",
1499ce110ea1SWei Hu 			    cqe_oob->cqe_hdr.cqe_type);
1500516b5059SWei Hu 			counter_u64_add(txq->stats.cqe_unknown_type, 1);
1501516b5059SWei Hu 			break;
1502ce110ea1SWei Hu 		}
1503ce110ea1SWei Hu 		if (txq->gdma_txq_id != completions[i].wq_num) {
1504ce110ea1SWei Hu 			mana_dbg(NULL,
1505ce110ea1SWei Hu 			    "txq gdma id not match completion wq num: "
1506ce110ea1SWei Hu 			    "%d != %d\n",
1507ce110ea1SWei Hu 			    txq->gdma_txq_id, completions[i].wq_num);
1508ce110ea1SWei Hu 			break;
1509ce110ea1SWei Hu 		}
1510ce110ea1SWei Hu 
1511ce110ea1SWei Hu 		tx_info = &txq->tx_buf_info[next_to_complete];
1512ce110ea1SWei Hu 		if (!tx_info->mbuf) {
1513ce110ea1SWei Hu 			mana_err(NULL,
1514ce110ea1SWei Hu 			    "WARNING: txq %d Empty mbuf on tx_info: %u, "
1515ce110ea1SWei Hu 			    "ntu = %u, pending_sends = %d, "
1516ce110ea1SWei Hu 			    "transmitted = %d, sa_drop = %d, i = %d, comp_read = %d\n",
1517ce110ea1SWei Hu 			    txq_idx, next_to_complete, txq->next_to_use,
1518ce110ea1SWei Hu 			    txq->pending_sends, pkt_transmitted, sa_drop,
1519ce110ea1SWei Hu 			    i, comp_read);
15201833cf13SWei Hu 			break;
1521ce110ea1SWei Hu 		}
1522ce110ea1SWei Hu 
1523ce110ea1SWei Hu 		wqe_info = &tx_info->wqe_inf;
1524ce110ea1SWei Hu 		wqe_unit_cnt += wqe_info->wqe_size_in_bu;
1525ce110ea1SWei Hu 
1526ce110ea1SWei Hu 		mana_tx_unmap_mbuf(apc, tx_info);
1527ce110ea1SWei Hu 		mb();
1528ce110ea1SWei Hu 
1529ce110ea1SWei Hu 		next_to_complete =
1530*9b8701b8SWei Hu 		    MANA_IDX_NEXT(next_to_complete, tx_queue_size);
1531ce110ea1SWei Hu 
1532ce110ea1SWei Hu 		pkt_transmitted++;
1533ce110ea1SWei Hu 	}
1534ce110ea1SWei Hu 
1535ce110ea1SWei Hu 	txq->next_to_complete = next_to_complete;
1536ce110ea1SWei Hu 
1537ce110ea1SWei Hu 	if (wqe_unit_cnt == 0) {
1538ce110ea1SWei Hu 		mana_err(NULL,
1539ce110ea1SWei Hu 		    "WARNING: TX ring not proceeding!\n");
1540ce110ea1SWei Hu 		return;
1541ce110ea1SWei Hu 	}
1542ce110ea1SWei Hu 
1543ce110ea1SWei Hu 	mana_move_wq_tail(txq->gdma_sq, wqe_unit_cnt);
1544ce110ea1SWei Hu 
1545ce110ea1SWei Hu 	/* Ensure tail updated before checking q stop */
1546ce110ea1SWei Hu 	wmb();
1547ce110ea1SWei Hu 
1548ce110ea1SWei Hu 	gdma_wq = txq->gdma_sq;
1549ce110ea1SWei Hu 	avail_space = mana_gd_wq_avail_space(gdma_wq);
1550ce110ea1SWei Hu 
1551ce110ea1SWei Hu 
1552ce110ea1SWei Hu 	if ((if_getdrvflags(ndev) & MANA_TXQ_FULL) == MANA_TXQ_FULL) {
1553ce110ea1SWei Hu 		txq_full = true;
1554ce110ea1SWei Hu 	}
1555ce110ea1SWei Hu 
1556ce110ea1SWei Hu 	/* Ensure checking txq_full before apc->port_is_up. */
1557ce110ea1SWei Hu 	rmb();
1558ce110ea1SWei Hu 
1559ce110ea1SWei Hu 	if (txq_full && apc->port_is_up && avail_space >= MAX_TX_WQE_SIZE) {
1560ce110ea1SWei Hu 		/* Grab the txq lock and re-test */
1561ce110ea1SWei Hu 		mtx_lock(&txq->txq_mtx);
1562ce110ea1SWei Hu 		avail_space = mana_gd_wq_avail_space(gdma_wq);
1563ce110ea1SWei Hu 
1564ce110ea1SWei Hu 		if ((if_getdrvflags(ndev) & MANA_TXQ_FULL) == MANA_TXQ_FULL &&
1565ce110ea1SWei Hu 		    apc->port_is_up && avail_space >= MAX_TX_WQE_SIZE) {
1566ce110ea1SWei Hu 			/* Clear the Q full flag */
1567ce110ea1SWei Hu 			if_setdrvflagbits(apc->ndev, IFF_DRV_RUNNING,
1568ce110ea1SWei Hu 			    IFF_DRV_OACTIVE);
1569ce110ea1SWei Hu 			counter_u64_add(txq->stats.wakeup, 1);
1570ce110ea1SWei Hu 			if (txq->alt_txq_idx != txq->idx) {
1571ce110ea1SWei Hu 				uint64_t stops = counter_u64_fetch(txq->stats.stop);
1572ce110ea1SWei Hu 				uint64_t wakeups = counter_u64_fetch(txq->stats.wakeup);
1573ce110ea1SWei Hu 				/* Reset alt_txq_idx back if it is not overloaded */
1574ce110ea1SWei Hu 				if (stops < wakeups) {
1575ce110ea1SWei Hu 					txq->alt_txq_idx = txq->idx;
1576ce110ea1SWei Hu 					counter_u64_add(txq->stats.alt_reset, 1);
1577ce110ea1SWei Hu 				}
1578ce110ea1SWei Hu 			}
1579ce110ea1SWei Hu 			rmb();
1580ce110ea1SWei Hu 			/* Schedule a tx enqueue task */
1581ce110ea1SWei Hu 			taskqueue_enqueue(txq->enqueue_tq, &txq->enqueue_task);
1582ce110ea1SWei Hu 		}
1583ce110ea1SWei Hu 		mtx_unlock(&txq->txq_mtx);
1584ce110ea1SWei Hu 	}
1585ce110ea1SWei Hu 
1586ce110ea1SWei Hu 	if (atomic_sub_return(pkt_transmitted, &txq->pending_sends) < 0)
1587ce110ea1SWei Hu 		mana_err(NULL,
1588ce110ea1SWei Hu 		    "WARNING: TX %d pending_sends error: %d\n",
1589ce110ea1SWei Hu 		    txq->idx, txq->pending_sends);
15901833cf13SWei Hu 
15911833cf13SWei Hu 	cq->work_done = pkt_transmitted;
1592ce110ea1SWei Hu }
1593ce110ea1SWei Hu 
1594ce110ea1SWei Hu static void
mana_post_pkt_rxq(struct mana_rxq * rxq,struct mana_recv_buf_oob * recv_buf_oob)1595*9b8701b8SWei Hu mana_post_pkt_rxq(struct mana_rxq *rxq,
1596*9b8701b8SWei Hu     struct mana_recv_buf_oob *recv_buf_oob)
1597ce110ea1SWei Hu {
1598ce110ea1SWei Hu 	int err;
1599ce110ea1SWei Hu 
1600e4e11c1dSWei Hu 	err = mana_gd_post_work_request(rxq->gdma_rq, &recv_buf_oob->wqe_req,
1601ce110ea1SWei Hu 	    &recv_buf_oob->wqe_inf);
1602ce110ea1SWei Hu 	if (err) {
1603ce110ea1SWei Hu 		mana_err(NULL, "WARNING: rxq %u post pkt err %d\n",
1604ce110ea1SWei Hu 		    rxq->rxq_idx, err);
1605ce110ea1SWei Hu 		return;
1606ce110ea1SWei Hu 	}
1607ce110ea1SWei Hu 
1608ce110ea1SWei Hu 	if (recv_buf_oob->wqe_inf.wqe_size_in_bu != 1) {
1609ce110ea1SWei Hu 		mana_err(NULL, "WARNING: rxq %u wqe_size_in_bu %u\n",
1610ce110ea1SWei Hu 		    rxq->rxq_idx, recv_buf_oob->wqe_inf.wqe_size_in_bu);
1611ce110ea1SWei Hu 	}
1612ce110ea1SWei Hu }
1613ce110ea1SWei Hu 
1614ce110ea1SWei Hu static void
mana_rx_mbuf(struct mbuf * mbuf,struct mana_rxcomp_oob * cqe,struct mana_rxq * rxq)1615ce110ea1SWei Hu mana_rx_mbuf(struct mbuf *mbuf, struct mana_rxcomp_oob *cqe,
1616ce110ea1SWei Hu     struct mana_rxq *rxq)
1617ce110ea1SWei Hu {
1618ce110ea1SWei Hu 	struct mana_stats *rx_stats = &rxq->stats;
161937d22ce0SJustin Hibbits 	if_t ndev = rxq->ndev;
1620ce110ea1SWei Hu 	uint32_t pkt_len = cqe->ppi[0].pkt_len;
1621ce110ea1SWei Hu 	uint16_t rxq_idx = rxq->rxq_idx;
1622ce110ea1SWei Hu 	struct mana_port_context *apc;
1623ce110ea1SWei Hu 	bool do_lro = false;
1624ce110ea1SWei Hu 	bool do_if_input;
1625ce110ea1SWei Hu 
1626ce110ea1SWei Hu 	apc = if_getsoftc(ndev);
16271833cf13SWei Hu 	rxq->rx_cq.work_done++;
1628ce110ea1SWei Hu 
1629ce110ea1SWei Hu 	if (!mbuf) {
1630ce110ea1SWei Hu 		return;
1631ce110ea1SWei Hu 	}
1632ce110ea1SWei Hu 
1633ce110ea1SWei Hu 	mbuf->m_flags |= M_PKTHDR;
1634ce110ea1SWei Hu 	mbuf->m_pkthdr.len = pkt_len;
1635ce110ea1SWei Hu 	mbuf->m_len = pkt_len;
1636ce110ea1SWei Hu 	mbuf->m_pkthdr.rcvif = ndev;
1637ce110ea1SWei Hu 
163837d22ce0SJustin Hibbits 	if ((if_getcapenable(ndev) & IFCAP_RXCSUM ||
163937d22ce0SJustin Hibbits 	    if_getcapenable(ndev) & IFCAP_RXCSUM_IPV6) &&
1640ce110ea1SWei Hu 	    (cqe->rx_iphdr_csum_succeed)) {
1641ce110ea1SWei Hu 		mbuf->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
1642ce110ea1SWei Hu 		mbuf->m_pkthdr.csum_flags |= CSUM_IP_VALID;
1643ce110ea1SWei Hu 		if (cqe->rx_tcp_csum_succeed || cqe->rx_udp_csum_succeed) {
1644ce110ea1SWei Hu 			mbuf->m_pkthdr.csum_flags |=
1645ce110ea1SWei Hu 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1646ce110ea1SWei Hu 			mbuf->m_pkthdr.csum_data = 0xffff;
1647ce110ea1SWei Hu 
1648ce110ea1SWei Hu 			if (cqe->rx_tcp_csum_succeed)
1649ce110ea1SWei Hu 				do_lro = true;
1650ce110ea1SWei Hu 		}
1651ce110ea1SWei Hu 	}
1652ce110ea1SWei Hu 
1653ce110ea1SWei Hu 	if (cqe->rx_hashtype != 0) {
1654ce110ea1SWei Hu 		mbuf->m_pkthdr.flowid = cqe->ppi[0].pkt_hash;
1655ce110ea1SWei Hu 
1656ce110ea1SWei Hu 		uint16_t hashtype = cqe->rx_hashtype;
1657ce110ea1SWei Hu 		if (hashtype & NDIS_HASH_IPV4_MASK) {
1658ce110ea1SWei Hu 			hashtype &= NDIS_HASH_IPV4_MASK;
1659ce110ea1SWei Hu 			switch (hashtype) {
1660ce110ea1SWei Hu 			case NDIS_HASH_TCP_IPV4:
1661ce110ea1SWei Hu 				M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_TCP_IPV4);
1662ce110ea1SWei Hu 				break;
1663ce110ea1SWei Hu 			case NDIS_HASH_UDP_IPV4:
1664ce110ea1SWei Hu 				M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_UDP_IPV4);
1665ce110ea1SWei Hu 				break;
1666ce110ea1SWei Hu 			default:
1667ce110ea1SWei Hu 				M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_IPV4);
1668ce110ea1SWei Hu 			}
1669ce110ea1SWei Hu 		} else if (hashtype & NDIS_HASH_IPV6_MASK) {
1670ce110ea1SWei Hu 			hashtype &= NDIS_HASH_IPV6_MASK;
1671ce110ea1SWei Hu 			switch (hashtype) {
1672ce110ea1SWei Hu 			case NDIS_HASH_TCP_IPV6:
1673ce110ea1SWei Hu 				M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_TCP_IPV6);
1674ce110ea1SWei Hu 				break;
1675ce110ea1SWei Hu 			case NDIS_HASH_TCP_IPV6_EX:
1676ce110ea1SWei Hu 				M_HASHTYPE_SET(mbuf,
1677ce110ea1SWei Hu 				    M_HASHTYPE_RSS_TCP_IPV6_EX);
1678ce110ea1SWei Hu 				break;
1679ce110ea1SWei Hu 			case NDIS_HASH_UDP_IPV6:
1680ce110ea1SWei Hu 				M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_UDP_IPV6);
1681ce110ea1SWei Hu 				break;
1682ce110ea1SWei Hu 			case NDIS_HASH_UDP_IPV6_EX:
1683ce110ea1SWei Hu 				M_HASHTYPE_SET(mbuf,
1684ce110ea1SWei Hu 				    M_HASHTYPE_RSS_UDP_IPV6_EX);
1685ce110ea1SWei Hu 				break;
1686ce110ea1SWei Hu 			default:
1687ce110ea1SWei Hu 				M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_IPV6);
1688ce110ea1SWei Hu 			}
1689ce110ea1SWei Hu 		} else {
1690ce110ea1SWei Hu 			M_HASHTYPE_SET(mbuf, M_HASHTYPE_OPAQUE_HASH);
1691ce110ea1SWei Hu 		}
1692ce110ea1SWei Hu 	} else {
1693ce110ea1SWei Hu 		mbuf->m_pkthdr.flowid = rxq_idx;
1694ce110ea1SWei Hu 		M_HASHTYPE_SET(mbuf, M_HASHTYPE_NONE);
1695ce110ea1SWei Hu 	}
1696ce110ea1SWei Hu 
1697ce110ea1SWei Hu 	do_if_input = true;
169837d22ce0SJustin Hibbits 	if ((if_getcapenable(ndev) & IFCAP_LRO) && do_lro) {
1699b167e449SWei Hu 		rxq->lro_tried++;
1700ce110ea1SWei Hu 		if (rxq->lro.lro_cnt != 0 &&
1701ce110ea1SWei Hu 		    tcp_lro_rx(&rxq->lro, mbuf, 0) == 0)
1702ce110ea1SWei Hu 			do_if_input = false;
1703b167e449SWei Hu 		else
1704b167e449SWei Hu 			rxq->lro_failed++;
1705ce110ea1SWei Hu 	}
1706ce110ea1SWei Hu 	if (do_if_input) {
170737d22ce0SJustin Hibbits 		if_input(ndev, mbuf);
1708ce110ea1SWei Hu 	}
1709ce110ea1SWei Hu 
1710ce110ea1SWei Hu 	counter_enter();
1711ce110ea1SWei Hu 	counter_u64_add_protected(rx_stats->packets, 1);
1712ce110ea1SWei Hu 	counter_u64_add_protected(apc->port_stats.rx_packets, 1);
1713ce110ea1SWei Hu 	counter_u64_add_protected(rx_stats->bytes, pkt_len);
1714ce110ea1SWei Hu 	counter_u64_add_protected(apc->port_stats.rx_bytes, pkt_len);
1715ce110ea1SWei Hu 	counter_exit();
1716ce110ea1SWei Hu }
1717ce110ea1SWei Hu 
1718*9b8701b8SWei Hu static int
mana_refill_rx_mbufs(struct mana_port_context * apc,struct mana_rxq * rxq,uint32_t num)1719*9b8701b8SWei Hu mana_refill_rx_mbufs(struct mana_port_context *apc,
1720*9b8701b8SWei Hu     struct mana_rxq *rxq, uint32_t num)
1721*9b8701b8SWei Hu {
1722*9b8701b8SWei Hu 	struct mana_recv_buf_oob *rxbuf_oob;
1723*9b8701b8SWei Hu 	uint32_t next_to_refill;
1724*9b8701b8SWei Hu 	uint32_t i;
1725*9b8701b8SWei Hu 	int err;
1726*9b8701b8SWei Hu 
1727*9b8701b8SWei Hu 	next_to_refill = rxq->next_to_refill;
1728*9b8701b8SWei Hu 
1729*9b8701b8SWei Hu 	for (i = 0; i < num; i++) {
1730*9b8701b8SWei Hu 		if (next_to_refill == rxq->buf_index) {
1731*9b8701b8SWei Hu 			mana_warn(NULL, "refilling index reached current, "
1732*9b8701b8SWei Hu 			    "aborted! rxq %u, oob idx %u\n",
1733*9b8701b8SWei Hu 			    rxq->rxq_idx, next_to_refill);
1734*9b8701b8SWei Hu 			break;
1735*9b8701b8SWei Hu 		}
1736*9b8701b8SWei Hu 
1737*9b8701b8SWei Hu 		rxbuf_oob = &rxq->rx_oobs[next_to_refill];
1738*9b8701b8SWei Hu 
1739*9b8701b8SWei Hu 		if (likely(rxbuf_oob->mbuf == NULL)) {
1740*9b8701b8SWei Hu 			err = mana_load_rx_mbuf(apc, rxq, rxbuf_oob, true);
1741*9b8701b8SWei Hu 		} else {
1742*9b8701b8SWei Hu 			mana_warn(NULL, "mbuf not null when refilling, "
1743*9b8701b8SWei Hu 			    "rxq %u, oob idx %u, reusing\n",
1744*9b8701b8SWei Hu 			    rxq->rxq_idx, next_to_refill);
1745*9b8701b8SWei Hu 			err = mana_load_rx_mbuf(apc, rxq, rxbuf_oob, false);
1746*9b8701b8SWei Hu 		}
1747*9b8701b8SWei Hu 
1748*9b8701b8SWei Hu 		if (unlikely(err != 0)) {
1749*9b8701b8SWei Hu 			mana_dbg(NULL,
1750*9b8701b8SWei Hu 			    "failed to load rx mbuf, err = %d, rxq = %u\n",
1751*9b8701b8SWei Hu 			    err, rxq->rxq_idx);
1752*9b8701b8SWei Hu 			counter_u64_add(rxq->stats.mbuf_alloc_fail, 1);
1753*9b8701b8SWei Hu 			break;
1754*9b8701b8SWei Hu 		}
1755*9b8701b8SWei Hu 
1756*9b8701b8SWei Hu 		mana_post_pkt_rxq(rxq, rxbuf_oob);
1757*9b8701b8SWei Hu 
1758*9b8701b8SWei Hu 		next_to_refill = MANA_IDX_NEXT(next_to_refill,
1759*9b8701b8SWei Hu 		    rxq->num_rx_buf);
1760*9b8701b8SWei Hu 	}
1761*9b8701b8SWei Hu 
1762*9b8701b8SWei Hu 	if (likely(i != 0)) {
1763*9b8701b8SWei Hu 		struct gdma_context *gc =
1764*9b8701b8SWei Hu 		    rxq->gdma_rq->gdma_dev->gdma_context;
1765*9b8701b8SWei Hu 
1766*9b8701b8SWei Hu 		mana_gd_wq_ring_doorbell(gc, rxq->gdma_rq);
1767*9b8701b8SWei Hu 	}
1768*9b8701b8SWei Hu 
1769*9b8701b8SWei Hu 	if (unlikely(i < num)) {
1770*9b8701b8SWei Hu 		counter_u64_add(rxq->stats.partial_refill, 1);
1771*9b8701b8SWei Hu 		mana_dbg(NULL,
1772*9b8701b8SWei Hu 		    "refilled rxq %u with only %u mbufs (%u requested)\n",
1773*9b8701b8SWei Hu 		    rxq->rxq_idx, i, num);
1774*9b8701b8SWei Hu 	}
1775*9b8701b8SWei Hu 
1776*9b8701b8SWei Hu 	rxq->next_to_refill = next_to_refill;
1777*9b8701b8SWei Hu 	return (i);
1778*9b8701b8SWei Hu }
1779*9b8701b8SWei Hu 
1780ce110ea1SWei Hu static void
mana_process_rx_cqe(struct mana_rxq * rxq,struct mana_cq * cq,struct gdma_comp * cqe)1781ce110ea1SWei Hu mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
1782ce110ea1SWei Hu     struct gdma_comp *cqe)
1783ce110ea1SWei Hu {
1784ce110ea1SWei Hu 	struct mana_rxcomp_oob *oob = (struct mana_rxcomp_oob *)cqe->cqe_data;
1785ce110ea1SWei Hu 	struct mana_recv_buf_oob *rxbuf_oob;
178637d22ce0SJustin Hibbits 	if_t ndev = rxq->ndev;
1787ce110ea1SWei Hu 	struct mana_port_context *apc;
1788ce110ea1SWei Hu 	struct mbuf *old_mbuf;
1789*9b8701b8SWei Hu 	uint32_t refill_required;
1790ce110ea1SWei Hu 	uint32_t curr, pktlen;
1791ce110ea1SWei Hu 
1792ce110ea1SWei Hu 	switch (oob->cqe_hdr.cqe_type) {
1793ce110ea1SWei Hu 	case CQE_RX_OKAY:
1794ce110ea1SWei Hu 		break;
1795ce110ea1SWei Hu 
1796ce110ea1SWei Hu 	case CQE_RX_TRUNCATED:
1797de64aa32SWei Hu 		apc = if_getsoftc(ndev);
1798de64aa32SWei Hu 		counter_u64_add(apc->port_stats.rx_drops, 1);
1799de64aa32SWei Hu 		rxbuf_oob = &rxq->rx_oobs[rxq->buf_index];
1800ce110ea1SWei Hu 		if_printf(ndev, "Dropped a truncated packet\n");
1801de64aa32SWei Hu 		goto drop;
1802ce110ea1SWei Hu 
1803ce110ea1SWei Hu 	case CQE_RX_COALESCED_4:
1804ce110ea1SWei Hu 		if_printf(ndev, "RX coalescing is unsupported\n");
1805ce110ea1SWei Hu 		return;
1806ce110ea1SWei Hu 
1807ce110ea1SWei Hu 	case CQE_RX_OBJECT_FENCE:
1808aa108bc7SWei Hu 		complete(&rxq->fence_event);
1809ce110ea1SWei Hu 		return;
1810ce110ea1SWei Hu 
1811ce110ea1SWei Hu 	default:
1812ce110ea1SWei Hu 		if_printf(ndev, "Unknown RX CQE type = %d\n",
1813ce110ea1SWei Hu 		    oob->cqe_hdr.cqe_type);
1814ce110ea1SWei Hu 		return;
1815ce110ea1SWei Hu 	}
1816ce110ea1SWei Hu 
1817ce110ea1SWei Hu 	if (oob->cqe_hdr.cqe_type != CQE_RX_OKAY)
1818ce110ea1SWei Hu 		return;
1819ce110ea1SWei Hu 
1820ce110ea1SWei Hu 	pktlen = oob->ppi[0].pkt_len;
1821ce110ea1SWei Hu 
1822ce110ea1SWei Hu 	if (pktlen == 0) {
1823ce110ea1SWei Hu 		/* data packets should never have packetlength of zero */
1824d0b5e4a3SLi-Wen Hsu 		if_printf(ndev, "RX pkt len=0, rq=%u, cq=%u, rxobj=0x%jx\n",
1825ce110ea1SWei Hu 		    rxq->gdma_id, cq->gdma_id, rxq->rxobj);
1826ce110ea1SWei Hu 		return;
1827ce110ea1SWei Hu 	}
1828ce110ea1SWei Hu 
1829ce110ea1SWei Hu 	curr = rxq->buf_index;
1830ce110ea1SWei Hu 	rxbuf_oob = &rxq->rx_oobs[curr];
1831ce110ea1SWei Hu 	if (rxbuf_oob->wqe_inf.wqe_size_in_bu != 1) {
1832ce110ea1SWei Hu 		mana_err(NULL, "WARNING: Rx Incorrect complete "
1833ce110ea1SWei Hu 		    "WQE size %u\n",
1834ce110ea1SWei Hu 		    rxbuf_oob->wqe_inf.wqe_size_in_bu);
1835ce110ea1SWei Hu 	}
1836ce110ea1SWei Hu 
1837ce110ea1SWei Hu 	apc = if_getsoftc(ndev);
1838ce110ea1SWei Hu 
1839ce110ea1SWei Hu 	old_mbuf = rxbuf_oob->mbuf;
1840ce110ea1SWei Hu 
1841ce110ea1SWei Hu 	/* Unload DMA map for the old mbuf */
1842ce110ea1SWei Hu 	mana_unload_rx_mbuf(apc, rxq, rxbuf_oob, false);
1843*9b8701b8SWei Hu 	/* Clear the mbuf pointer to avoid reuse */
1844*9b8701b8SWei Hu 	rxbuf_oob->mbuf = NULL;
1845ce110ea1SWei Hu 
1846ce110ea1SWei Hu 	mana_rx_mbuf(old_mbuf, oob, rxq);
1847ce110ea1SWei Hu 
1848de64aa32SWei Hu drop:
1849ce110ea1SWei Hu 	mana_move_wq_tail(rxq->gdma_rq, rxbuf_oob->wqe_inf.wqe_size_in_bu);
1850ce110ea1SWei Hu 
1851*9b8701b8SWei Hu 	rxq->buf_index = MANA_IDX_NEXT(rxq->buf_index, rxq->num_rx_buf);
1852*9b8701b8SWei Hu 
1853*9b8701b8SWei Hu 	/* Check if refill is needed */
1854*9b8701b8SWei Hu 	refill_required = MANA_GET_SPACE(rxq->next_to_refill,
1855*9b8701b8SWei Hu 	    rxq->buf_index, rxq->num_rx_buf);
1856*9b8701b8SWei Hu 
1857*9b8701b8SWei Hu 	if (refill_required >= rxq->refill_thresh) {
1858*9b8701b8SWei Hu 		/* Refill empty rx_oobs with new mbufs */
1859*9b8701b8SWei Hu 		mana_refill_rx_mbufs(apc, rxq, refill_required);
1860*9b8701b8SWei Hu 	}
1861ce110ea1SWei Hu }
1862ce110ea1SWei Hu 
1863ce110ea1SWei Hu static void
mana_poll_rx_cq(struct mana_cq * cq)1864ce110ea1SWei Hu mana_poll_rx_cq(struct mana_cq *cq)
1865ce110ea1SWei Hu {
1866ce110ea1SWei Hu 	struct gdma_comp *comp = cq->gdma_comp_buf;
1867ce110ea1SWei Hu 	int comp_read, i;
1868ce110ea1SWei Hu 
1869ce110ea1SWei Hu 	comp_read = mana_gd_poll_cq(cq->gdma_cq, comp, CQE_POLLING_BUFFER);
1870ce110ea1SWei Hu 	KASSERT(comp_read <= CQE_POLLING_BUFFER,
1871ce110ea1SWei Hu 	    ("comp_read %d great than buf size %d",
1872ce110ea1SWei Hu 	    comp_read, CQE_POLLING_BUFFER));
1873ce110ea1SWei Hu 
1874ce110ea1SWei Hu 	for (i = 0; i < comp_read; i++) {
1875ce110ea1SWei Hu 		if (comp[i].is_sq == true) {
1876ce110ea1SWei Hu 			mana_err(NULL,
1877ce110ea1SWei Hu 			    "WARNING: CQE not for receive queue\n");
1878ce110ea1SWei Hu 			return;
1879ce110ea1SWei Hu 		}
1880ce110ea1SWei Hu 
1881ce110ea1SWei Hu 		/* verify recv cqe references the right rxq */
1882ce110ea1SWei Hu 		if (comp[i].wq_num != cq->rxq->gdma_id) {
1883ce110ea1SWei Hu 			mana_err(NULL,
1884ce110ea1SWei Hu 			    "WARNING: Received CQE %d  not for "
1885ce110ea1SWei Hu 			    "this receive queue %d\n",
1886ce110ea1SWei Hu 			    comp[i].wq_num,  cq->rxq->gdma_id);
1887ce110ea1SWei Hu 			return;
1888ce110ea1SWei Hu 		}
1889ce110ea1SWei Hu 
1890ce110ea1SWei Hu 		mana_process_rx_cqe(cq->rxq, cq, &comp[i]);
1891ce110ea1SWei Hu 	}
1892ce110ea1SWei Hu 
1893ce110ea1SWei Hu 	tcp_lro_flush_all(&cq->rxq->lro);
1894ce110ea1SWei Hu }
1895ce110ea1SWei Hu 
1896ce110ea1SWei Hu static void
mana_cq_handler(void * context,struct gdma_queue * gdma_queue)1897ce110ea1SWei Hu mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
1898ce110ea1SWei Hu {
1899ce110ea1SWei Hu 	struct mana_cq *cq = context;
19001833cf13SWei Hu 	uint8_t arm_bit;
1901ce110ea1SWei Hu 
1902ce110ea1SWei Hu 	KASSERT(cq->gdma_cq == gdma_queue,
1903ce110ea1SWei Hu 	    ("cq do not match %p, %p", cq->gdma_cq, gdma_queue));
1904ce110ea1SWei Hu 
1905ce110ea1SWei Hu 	if (cq->type == MANA_CQ_TYPE_RX) {
1906ce110ea1SWei Hu 		mana_poll_rx_cq(cq);
1907ce110ea1SWei Hu 	} else {
1908ce110ea1SWei Hu 		mana_poll_tx_cq(cq);
1909ce110ea1SWei Hu 	}
1910ce110ea1SWei Hu 
19111833cf13SWei Hu 	if (cq->work_done < cq->budget && cq->do_not_ring_db == false)
19121833cf13SWei Hu 		arm_bit = SET_ARM_BIT;
19131833cf13SWei Hu 	else
19141833cf13SWei Hu 		arm_bit = 0;
19151833cf13SWei Hu 
19161833cf13SWei Hu 	mana_gd_ring_cq(gdma_queue, arm_bit);
19171833cf13SWei Hu }
19181833cf13SWei Hu 
1919a18e9994SWei Hu #define MANA_POLL_BUDGET	256
1920a18e9994SWei Hu #define MANA_RX_BUDGET		8
1921a18e9994SWei Hu #define MANA_TX_BUDGET		8
19221833cf13SWei Hu 
19231833cf13SWei Hu static void
mana_poll(void * arg,int pending)19241833cf13SWei Hu mana_poll(void *arg, int pending)
19251833cf13SWei Hu {
19261833cf13SWei Hu 	struct mana_cq *cq = arg;
19271833cf13SWei Hu 	int i;
19281833cf13SWei Hu 
19291833cf13SWei Hu 	cq->work_done = 0;
19301833cf13SWei Hu 	if (cq->type == MANA_CQ_TYPE_RX) {
19311833cf13SWei Hu 		cq->budget = MANA_RX_BUDGET;
19321833cf13SWei Hu 	} else {
19331833cf13SWei Hu 		cq->budget = MANA_TX_BUDGET;
19341833cf13SWei Hu 	}
19351833cf13SWei Hu 
19361833cf13SWei Hu 	for (i = 0; i < MANA_POLL_BUDGET; i++) {
19371833cf13SWei Hu 		/*
19381833cf13SWei Hu 		 * If this is the last loop, set the budget big enough
19391833cf13SWei Hu 		 * so it will arm the CQ any way.
19401833cf13SWei Hu 		 */
19411833cf13SWei Hu 		if (i == (MANA_POLL_BUDGET - 1))
19421833cf13SWei Hu 			cq->budget = CQE_POLLING_BUFFER + 1;
19431833cf13SWei Hu 
19441833cf13SWei Hu 		mana_cq_handler(cq, cq->gdma_cq);
19451833cf13SWei Hu 
19461833cf13SWei Hu 		if (cq->work_done < cq->budget)
19471833cf13SWei Hu 			break;
19481833cf13SWei Hu 
19491833cf13SWei Hu 		cq->work_done = 0;
19501833cf13SWei Hu 	}
19511833cf13SWei Hu }
19521833cf13SWei Hu 
19531833cf13SWei Hu static void
mana_schedule_task(void * arg,struct gdma_queue * gdma_queue)19541833cf13SWei Hu mana_schedule_task(void *arg, struct gdma_queue *gdma_queue)
19551833cf13SWei Hu {
19561833cf13SWei Hu 	struct mana_cq *cq = arg;
19571833cf13SWei Hu 
19581833cf13SWei Hu 	taskqueue_enqueue(cq->cleanup_tq, &cq->cleanup_task);
1959ce110ea1SWei Hu }
1960ce110ea1SWei Hu 
1961ce110ea1SWei Hu static void
mana_deinit_cq(struct mana_port_context * apc,struct mana_cq * cq)1962ce110ea1SWei Hu mana_deinit_cq(struct mana_port_context *apc, struct mana_cq *cq)
1963ce110ea1SWei Hu {
1964ce110ea1SWei Hu 	struct gdma_dev *gd = apc->ac->gdma_dev;
1965ce110ea1SWei Hu 
1966ce110ea1SWei Hu 	if (!cq->gdma_cq)
1967ce110ea1SWei Hu 		return;
1968ce110ea1SWei Hu 
19691833cf13SWei Hu 	/* Drain cleanup taskqueue */
19701833cf13SWei Hu 	if (cq->cleanup_tq) {
19711833cf13SWei Hu 		while (taskqueue_cancel(cq->cleanup_tq,
19721833cf13SWei Hu 		    &cq->cleanup_task, NULL)) {
19731833cf13SWei Hu 			taskqueue_drain(cq->cleanup_tq,
19741833cf13SWei Hu 			    &cq->cleanup_task);
19751833cf13SWei Hu 		}
19761833cf13SWei Hu 
19771833cf13SWei Hu 		taskqueue_free(cq->cleanup_tq);
19781833cf13SWei Hu 	}
19791833cf13SWei Hu 
1980ce110ea1SWei Hu 	mana_gd_destroy_queue(gd->gdma_context, cq->gdma_cq);
1981ce110ea1SWei Hu }
1982ce110ea1SWei Hu 
1983ce110ea1SWei Hu static void
mana_deinit_txq(struct mana_port_context * apc,struct mana_txq * txq)1984ce110ea1SWei Hu mana_deinit_txq(struct mana_port_context *apc, struct mana_txq *txq)
1985ce110ea1SWei Hu {
1986ce110ea1SWei Hu 	struct gdma_dev *gd = apc->ac->gdma_dev;
1987ce110ea1SWei Hu 	struct mana_send_buf_info *txbuf_info;
1988ce110ea1SWei Hu 	uint32_t pending_sends;
1989ce110ea1SWei Hu 	int i;
1990ce110ea1SWei Hu 
1991ce110ea1SWei Hu 	if (!txq->gdma_sq)
1992ce110ea1SWei Hu 		return;
1993ce110ea1SWei Hu 
1994ce110ea1SWei Hu 	if ((pending_sends = atomic_read(&txq->pending_sends)) > 0) {
1995ce110ea1SWei Hu 		mana_err(NULL,
1996ce110ea1SWei Hu 		    "WARNING: txq pending sends not zero: %u\n",
1997ce110ea1SWei Hu 		    pending_sends);
1998ce110ea1SWei Hu 	}
1999ce110ea1SWei Hu 
2000ce110ea1SWei Hu 	if (txq->next_to_use != txq->next_to_complete) {
2001ce110ea1SWei Hu 		mana_err(NULL,
2002ce110ea1SWei Hu 		    "WARNING: txq buf not completed, "
2003ce110ea1SWei Hu 		    "next use %u, next complete %u\n",
2004ce110ea1SWei Hu 		    txq->next_to_use, txq->next_to_complete);
2005ce110ea1SWei Hu 	}
2006ce110ea1SWei Hu 
2007ce110ea1SWei Hu 	/* Flush buf ring. Grab txq mtx lock */
2008ce110ea1SWei Hu 	if (txq->txq_br) {
2009ce110ea1SWei Hu 		mtx_lock(&txq->txq_mtx);
2010ce110ea1SWei Hu 		drbr_flush(apc->ndev, txq->txq_br);
2011ce110ea1SWei Hu 		mtx_unlock(&txq->txq_mtx);
2012ce110ea1SWei Hu 		buf_ring_free(txq->txq_br, M_DEVBUF);
2013ce110ea1SWei Hu 	}
2014ce110ea1SWei Hu 
2015ce110ea1SWei Hu 	/* Drain taskqueue */
2016ce110ea1SWei Hu 	if (txq->enqueue_tq) {
2017ce110ea1SWei Hu 		while (taskqueue_cancel(txq->enqueue_tq,
2018ce110ea1SWei Hu 		    &txq->enqueue_task, NULL)) {
2019ce110ea1SWei Hu 			taskqueue_drain(txq->enqueue_tq,
2020ce110ea1SWei Hu 			    &txq->enqueue_task);
2021ce110ea1SWei Hu 		}
2022ce110ea1SWei Hu 
2023ce110ea1SWei Hu 		taskqueue_free(txq->enqueue_tq);
2024ce110ea1SWei Hu 	}
2025ce110ea1SWei Hu 
2026ce110ea1SWei Hu 	if (txq->tx_buf_info) {
2027ce110ea1SWei Hu 		/* Free all mbufs which are still in-flight */
2028a18e9994SWei Hu 		for (i = 0; i < apc->tx_queue_size; i++) {
2029ce110ea1SWei Hu 			txbuf_info = &txq->tx_buf_info[i];
2030ce110ea1SWei Hu 			if (txbuf_info->mbuf) {
2031ce110ea1SWei Hu 				mana_tx_unmap_mbuf(apc, txbuf_info);
2032ce110ea1SWei Hu 			}
2033ce110ea1SWei Hu 		}
2034ce110ea1SWei Hu 
2035ce110ea1SWei Hu 		free(txq->tx_buf_info, M_DEVBUF);
2036ce110ea1SWei Hu 	}
2037ce110ea1SWei Hu 
2038ce110ea1SWei Hu 	mana_free_counters((counter_u64_t *)&txq->stats,
2039ce110ea1SWei Hu 	    sizeof(txq->stats));
2040ce110ea1SWei Hu 
2041ce110ea1SWei Hu 	mana_gd_destroy_queue(gd->gdma_context, txq->gdma_sq);
2042ce110ea1SWei Hu 
2043ce110ea1SWei Hu 	mtx_destroy(&txq->txq_mtx);
2044ce110ea1SWei Hu }
2045ce110ea1SWei Hu 
2046ce110ea1SWei Hu static void
mana_destroy_txq(struct mana_port_context * apc)2047ce110ea1SWei Hu mana_destroy_txq(struct mana_port_context *apc)
2048ce110ea1SWei Hu {
2049ce110ea1SWei Hu 	int i;
2050ce110ea1SWei Hu 
2051ce110ea1SWei Hu 	if (!apc->tx_qp)
2052ce110ea1SWei Hu 		return;
2053ce110ea1SWei Hu 
2054ce110ea1SWei Hu 	for (i = 0; i < apc->num_queues; i++) {
2055ce110ea1SWei Hu 		mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i].tx_object);
2056ce110ea1SWei Hu 
2057ce110ea1SWei Hu 		mana_deinit_cq(apc, &apc->tx_qp[i].tx_cq);
2058ce110ea1SWei Hu 
2059ce110ea1SWei Hu 		mana_deinit_txq(apc, &apc->tx_qp[i].txq);
2060ce110ea1SWei Hu 	}
2061ce110ea1SWei Hu 
2062ce110ea1SWei Hu 	free(apc->tx_qp, M_DEVBUF);
2063ce110ea1SWei Hu 	apc->tx_qp = NULL;
2064ce110ea1SWei Hu }
2065ce110ea1SWei Hu 
2066ce110ea1SWei Hu static int
mana_create_txq(struct mana_port_context * apc,if_t net)206737d22ce0SJustin Hibbits mana_create_txq(struct mana_port_context *apc, if_t net)
2068ce110ea1SWei Hu {
20691833cf13SWei Hu 	struct mana_context *ac = apc->ac;
20701833cf13SWei Hu 	struct gdma_dev *gd = ac->gdma_dev;
2071ce110ea1SWei Hu 	struct mana_obj_spec wq_spec;
2072ce110ea1SWei Hu 	struct mana_obj_spec cq_spec;
2073ce110ea1SWei Hu 	struct gdma_queue_spec spec;
2074ce110ea1SWei Hu 	struct gdma_context *gc;
2075ce110ea1SWei Hu 	struct mana_txq *txq;
2076ce110ea1SWei Hu 	struct mana_cq *cq;
2077ce110ea1SWei Hu 	uint32_t txq_size;
2078ce110ea1SWei Hu 	uint32_t cq_size;
2079ce110ea1SWei Hu 	int err;
2080ce110ea1SWei Hu 	int i;
2081ce110ea1SWei Hu 
2082ce110ea1SWei Hu 	apc->tx_qp = mallocarray(apc->num_queues, sizeof(struct mana_tx_qp),
2083ce110ea1SWei Hu 	    M_DEVBUF, M_WAITOK | M_ZERO);
2084ce110ea1SWei Hu 
2085ce110ea1SWei Hu 	/*  The minimum size of the WQE is 32 bytes, hence
2086a18e9994SWei Hu 	 *  apc->tx_queue_size represents the maximum number of WQEs
2087ce110ea1SWei Hu 	 *  the SQ can store. This value is then used to size other queues
2088ce110ea1SWei Hu 	 *  to prevent overflow.
2089a18e9994SWei Hu 	 *  Also note that the txq_size is always going to be page aligned,
2090a18e9994SWei Hu 	 *  as min val of apc->tx_queue_size is 128 and that would make
2091a18e9994SWei Hu 	 *  txq_size 128 * 32 = 4096 and the other higher values of
2092a18e9994SWei Hu 	 *  apc->tx_queue_size are always power of two.
2093ce110ea1SWei Hu 	 */
2094a18e9994SWei Hu 	txq_size = apc->tx_queue_size * 32;
2095ce110ea1SWei Hu 	KASSERT(IS_ALIGNED(txq_size, PAGE_SIZE),
2096ce110ea1SWei Hu 	    ("txq size not page aligned"));
2097ce110ea1SWei Hu 
2098a18e9994SWei Hu 	cq_size = apc->tx_queue_size * COMP_ENTRY_SIZE;
2099ce110ea1SWei Hu 	cq_size = ALIGN(cq_size, PAGE_SIZE);
2100ce110ea1SWei Hu 
2101ce110ea1SWei Hu 	gc = gd->gdma_context;
2102ce110ea1SWei Hu 
2103ce110ea1SWei Hu 	for (i = 0; i < apc->num_queues; i++) {
2104ce110ea1SWei Hu 		apc->tx_qp[i].tx_object = INVALID_MANA_HANDLE;
2105ce110ea1SWei Hu 
2106ce110ea1SWei Hu 		/* Create SQ */
2107ce110ea1SWei Hu 		txq = &apc->tx_qp[i].txq;
2108ce110ea1SWei Hu 
2109ce110ea1SWei Hu 		txq->ndev = net;
2110ce110ea1SWei Hu 		txq->vp_offset = apc->tx_vp_offset;
2111ce110ea1SWei Hu 		txq->idx = i;
2112ce110ea1SWei Hu 		txq->alt_txq_idx = i;
2113ce110ea1SWei Hu 
2114ce110ea1SWei Hu 		memset(&spec, 0, sizeof(spec));
2115ce110ea1SWei Hu 		spec.type = GDMA_SQ;
2116ce110ea1SWei Hu 		spec.monitor_avl_buf = true;
2117ce110ea1SWei Hu 		spec.queue_size = txq_size;
2118ce110ea1SWei Hu 		err = mana_gd_create_mana_wq_cq(gd, &spec, &txq->gdma_sq);
2119ce110ea1SWei Hu 		if (err)
2120ce110ea1SWei Hu 			goto out;
2121ce110ea1SWei Hu 
2122ce110ea1SWei Hu 		/* Create SQ's CQ */
2123ce110ea1SWei Hu 		cq = &apc->tx_qp[i].tx_cq;
2124ce110ea1SWei Hu 		cq->type = MANA_CQ_TYPE_TX;
2125ce110ea1SWei Hu 
2126ce110ea1SWei Hu 		cq->txq = txq;
2127ce110ea1SWei Hu 
2128ce110ea1SWei Hu 		memset(&spec, 0, sizeof(spec));
2129ce110ea1SWei Hu 		spec.type = GDMA_CQ;
2130ce110ea1SWei Hu 		spec.monitor_avl_buf = false;
2131ce110ea1SWei Hu 		spec.queue_size = cq_size;
21321833cf13SWei Hu 		spec.cq.callback = mana_schedule_task;
21331833cf13SWei Hu 		spec.cq.parent_eq = ac->eqs[i].eq;
2134ce110ea1SWei Hu 		spec.cq.context = cq;
2135ce110ea1SWei Hu 		err = mana_gd_create_mana_wq_cq(gd, &spec, &cq->gdma_cq);
2136ce110ea1SWei Hu 		if (err)
2137ce110ea1SWei Hu 			goto out;
2138ce110ea1SWei Hu 
2139ce110ea1SWei Hu 		memset(&wq_spec, 0, sizeof(wq_spec));
2140ce110ea1SWei Hu 		memset(&cq_spec, 0, sizeof(cq_spec));
2141ce110ea1SWei Hu 
2142b685df31SWei Hu 		wq_spec.gdma_region = txq->gdma_sq->mem_info.dma_region_handle;
2143ce110ea1SWei Hu 		wq_spec.queue_size = txq->gdma_sq->queue_size;
2144ce110ea1SWei Hu 
2145b685df31SWei Hu 		cq_spec.gdma_region = cq->gdma_cq->mem_info.dma_region_handle;
2146ce110ea1SWei Hu 		cq_spec.queue_size = cq->gdma_cq->queue_size;
2147ce110ea1SWei Hu 		cq_spec.modr_ctx_id = 0;
2148ce110ea1SWei Hu 		cq_spec.attached_eq = cq->gdma_cq->cq.parent->id;
2149ce110ea1SWei Hu 
2150ce110ea1SWei Hu 		err = mana_create_wq_obj(apc, apc->port_handle, GDMA_SQ,
2151ce110ea1SWei Hu 		    &wq_spec, &cq_spec, &apc->tx_qp[i].tx_object);
2152ce110ea1SWei Hu 
2153ce110ea1SWei Hu 		if (err)
2154ce110ea1SWei Hu 			goto out;
2155ce110ea1SWei Hu 
2156ce110ea1SWei Hu 		txq->gdma_sq->id = wq_spec.queue_index;
2157ce110ea1SWei Hu 		cq->gdma_cq->id = cq_spec.queue_index;
2158ce110ea1SWei Hu 
2159b685df31SWei Hu 		txq->gdma_sq->mem_info.dma_region_handle =
2160b685df31SWei Hu 		    GDMA_INVALID_DMA_REGION;
2161b685df31SWei Hu 		cq->gdma_cq->mem_info.dma_region_handle =
2162b685df31SWei Hu 		    GDMA_INVALID_DMA_REGION;
2163ce110ea1SWei Hu 
2164ce110ea1SWei Hu 		txq->gdma_txq_id = txq->gdma_sq->id;
2165ce110ea1SWei Hu 
2166ce110ea1SWei Hu 		cq->gdma_id = cq->gdma_cq->id;
2167ce110ea1SWei Hu 
2168ce110ea1SWei Hu 		mana_dbg(NULL,
2169ce110ea1SWei Hu 		    "txq %d, txq gdma id %d, txq cq gdma id %d\n",
21706ccf4f40SZhenlei Huang 		    i, txq->gdma_txq_id, cq->gdma_id);
2171ce110ea1SWei Hu 
2172ce110ea1SWei Hu 		if (cq->gdma_id >= gc->max_num_cqs) {
2173ce110ea1SWei Hu 			if_printf(net, "CQ id %u too large.\n", cq->gdma_id);
2174027d0c1cSWei Hu 			err = EINVAL;
2175027d0c1cSWei Hu 			goto out;
2176ce110ea1SWei Hu 		}
2177ce110ea1SWei Hu 
2178ce110ea1SWei Hu 		gc->cq_table[cq->gdma_id] = cq->gdma_cq;
2179ce110ea1SWei Hu 
2180ce110ea1SWei Hu 		/* Initialize tx specific data */
2181a18e9994SWei Hu 		txq->tx_buf_info = malloc(apc->tx_queue_size *
2182ce110ea1SWei Hu 		    sizeof(struct mana_send_buf_info),
2183ce110ea1SWei Hu 		    M_DEVBUF, M_WAITOK | M_ZERO);
2184ce110ea1SWei Hu 
2185ce110ea1SWei Hu 		snprintf(txq->txq_mtx_name, nitems(txq->txq_mtx_name),
2186ce110ea1SWei Hu 		    "mana:tx(%d)", i);
2187ce110ea1SWei Hu 		mtx_init(&txq->txq_mtx, txq->txq_mtx_name, NULL, MTX_DEF);
2188ce110ea1SWei Hu 
2189a18e9994SWei Hu 		txq->txq_br = buf_ring_alloc(4 * apc->tx_queue_size,
2190ce110ea1SWei Hu 		    M_DEVBUF, M_WAITOK, &txq->txq_mtx);
2191ce110ea1SWei Hu 
2192ce110ea1SWei Hu 		/* Allocate taskqueue for deferred send */
2193ce110ea1SWei Hu 		TASK_INIT(&txq->enqueue_task, 0, mana_xmit_taskfunc, txq);
2194ce110ea1SWei Hu 		txq->enqueue_tq = taskqueue_create_fast("mana_tx_enque",
2195ce110ea1SWei Hu 		    M_NOWAIT, taskqueue_thread_enqueue, &txq->enqueue_tq);
2196ce110ea1SWei Hu 		if (unlikely(txq->enqueue_tq == NULL)) {
2197ce110ea1SWei Hu 			if_printf(net,
2198ce110ea1SWei Hu 			    "Unable to create tx %d enqueue task queue\n", i);
2199ce110ea1SWei Hu 			err = ENOMEM;
2200ce110ea1SWei Hu 			goto out;
2201ce110ea1SWei Hu 		}
2202ce110ea1SWei Hu 		taskqueue_start_threads(&txq->enqueue_tq, 1, PI_NET,
22031833cf13SWei Hu 		    "mana txq p%u-tx%d", apc->port_idx, i);
2204ce110ea1SWei Hu 
2205ce110ea1SWei Hu 		mana_alloc_counters((counter_u64_t *)&txq->stats,
2206ce110ea1SWei Hu 		    sizeof(txq->stats));
2207ce110ea1SWei Hu 
22081833cf13SWei Hu 		/* Allocate and start the cleanup task on CQ */
22091833cf13SWei Hu 		cq->do_not_ring_db = false;
22101833cf13SWei Hu 
22111833cf13SWei Hu 		NET_TASK_INIT(&cq->cleanup_task, 0, mana_poll, cq);
22121833cf13SWei Hu 		cq->cleanup_tq =
22131833cf13SWei Hu 		    taskqueue_create_fast("mana tx cq cleanup",
22141833cf13SWei Hu 		    M_WAITOK, taskqueue_thread_enqueue,
22151833cf13SWei Hu 		    &cq->cleanup_tq);
22161833cf13SWei Hu 
22171833cf13SWei Hu 		if (apc->last_tx_cq_bind_cpu < 0)
22181833cf13SWei Hu 			apc->last_tx_cq_bind_cpu = CPU_FIRST();
22191833cf13SWei Hu 		cq->cpu = apc->last_tx_cq_bind_cpu;
22201833cf13SWei Hu 		apc->last_tx_cq_bind_cpu = CPU_NEXT(apc->last_tx_cq_bind_cpu);
22211833cf13SWei Hu 
22221833cf13SWei Hu 		if (apc->bind_cleanup_thread_cpu) {
22231833cf13SWei Hu 			cpuset_t cpu_mask;
22241833cf13SWei Hu 			CPU_SETOF(cq->cpu, &cpu_mask);
22251833cf13SWei Hu 			taskqueue_start_threads_cpuset(&cq->cleanup_tq,
22261833cf13SWei Hu 			    1, PI_NET, &cpu_mask,
22271833cf13SWei Hu 			    "mana cq p%u-tx%u-cpu%d",
22281833cf13SWei Hu 			    apc->port_idx, txq->idx, cq->cpu);
22291833cf13SWei Hu 		} else {
22301833cf13SWei Hu 			taskqueue_start_threads(&cq->cleanup_tq, 1,
22311833cf13SWei Hu 			    PI_NET, "mana cq p%u-tx%u",
22321833cf13SWei Hu 			    apc->port_idx, txq->idx);
22331833cf13SWei Hu 		}
22341833cf13SWei Hu 
22351833cf13SWei Hu 		mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT);
2236ce110ea1SWei Hu 	}
2237ce110ea1SWei Hu 
2238ce110ea1SWei Hu 	return 0;
2239ce110ea1SWei Hu out:
2240ce110ea1SWei Hu 	mana_destroy_txq(apc);
2241ce110ea1SWei Hu 	return err;
2242ce110ea1SWei Hu }
2243ce110ea1SWei Hu 
2244ce110ea1SWei Hu static void
mana_destroy_rxq(struct mana_port_context * apc,struct mana_rxq * rxq,bool validate_state)2245ce110ea1SWei Hu mana_destroy_rxq(struct mana_port_context *apc, struct mana_rxq *rxq,
2246ce110ea1SWei Hu     bool validate_state)
2247ce110ea1SWei Hu {
2248ce110ea1SWei Hu 	struct gdma_context *gc = apc->ac->gdma_dev->gdma_context;
2249ce110ea1SWei Hu 	struct mana_recv_buf_oob *rx_oob;
2250ce110ea1SWei Hu 	int i;
2251ce110ea1SWei Hu 
2252ce110ea1SWei Hu 	if (!rxq)
2253ce110ea1SWei Hu 		return;
2254ce110ea1SWei Hu 
2255ce110ea1SWei Hu 	if (validate_state) {
2256ce110ea1SWei Hu 		/*
2257ce110ea1SWei Hu 		 * XXX Cancel and drain cleanup task queue here.
2258ce110ea1SWei Hu 		 */
2259ce110ea1SWei Hu 		;
2260ce110ea1SWei Hu 	}
2261ce110ea1SWei Hu 
2262ce110ea1SWei Hu 	mana_destroy_wq_obj(apc, GDMA_RQ, rxq->rxobj);
2263ce110ea1SWei Hu 
2264ce110ea1SWei Hu 	mana_deinit_cq(apc, &rxq->rx_cq);
2265ce110ea1SWei Hu 
2266ce110ea1SWei Hu 	mana_free_counters((counter_u64_t *)&rxq->stats,
2267ce110ea1SWei Hu 	    sizeof(rxq->stats));
2268ce110ea1SWei Hu 
2269ce110ea1SWei Hu 	/* Free LRO resources */
2270ce110ea1SWei Hu 	tcp_lro_free(&rxq->lro);
2271ce110ea1SWei Hu 
2272ce110ea1SWei Hu 	for (i = 0; i < rxq->num_rx_buf; i++) {
2273ce110ea1SWei Hu 		rx_oob = &rxq->rx_oobs[i];
2274ce110ea1SWei Hu 
2275ce110ea1SWei Hu 		if (rx_oob->mbuf)
2276ce110ea1SWei Hu 			mana_unload_rx_mbuf(apc, rxq, rx_oob, true);
2277ce110ea1SWei Hu 
2278ce110ea1SWei Hu 		bus_dmamap_destroy(apc->rx_buf_tag, rx_oob->dma_map);
2279ce110ea1SWei Hu 	}
2280ce110ea1SWei Hu 
2281ce110ea1SWei Hu 	if (rxq->gdma_rq)
2282ce110ea1SWei Hu 		mana_gd_destroy_queue(gc, rxq->gdma_rq);
2283ce110ea1SWei Hu 
2284ce110ea1SWei Hu 	free(rxq, M_DEVBUF);
2285ce110ea1SWei Hu }
2286ce110ea1SWei Hu 
2287ce110ea1SWei Hu #define MANA_WQE_HEADER_SIZE 16
2288ce110ea1SWei Hu #define MANA_WQE_SGE_SIZE 16
2289ce110ea1SWei Hu 
2290ce110ea1SWei Hu static int
mana_alloc_rx_wqe(struct mana_port_context * apc,struct mana_rxq * rxq,uint32_t * rxq_size,uint32_t * cq_size)2291ce110ea1SWei Hu mana_alloc_rx_wqe(struct mana_port_context *apc,
2292ce110ea1SWei Hu     struct mana_rxq *rxq, uint32_t *rxq_size, uint32_t *cq_size)
2293ce110ea1SWei Hu {
2294ce110ea1SWei Hu 	struct mana_recv_buf_oob *rx_oob;
2295ce110ea1SWei Hu 	uint32_t buf_idx;
2296ce110ea1SWei Hu 	int err;
2297ce110ea1SWei Hu 
2298ce110ea1SWei Hu 	if (rxq->datasize == 0 || rxq->datasize > PAGE_SIZE) {
2299ce110ea1SWei Hu 		mana_err(NULL,
2300ce110ea1SWei Hu 		    "WARNING: Invalid rxq datasize %u\n", rxq->datasize);
2301ce110ea1SWei Hu 	}
2302ce110ea1SWei Hu 
2303ce110ea1SWei Hu 	*rxq_size = 0;
2304ce110ea1SWei Hu 	*cq_size = 0;
2305ce110ea1SWei Hu 
2306ce110ea1SWei Hu 	for (buf_idx = 0; buf_idx < rxq->num_rx_buf; buf_idx++) {
2307ce110ea1SWei Hu 		rx_oob = &rxq->rx_oobs[buf_idx];
2308ce110ea1SWei Hu 		memset(rx_oob, 0, sizeof(*rx_oob));
2309ce110ea1SWei Hu 
2310ce110ea1SWei Hu 		err = bus_dmamap_create(apc->rx_buf_tag, 0,
2311ce110ea1SWei Hu 		    &rx_oob->dma_map);
2312ce110ea1SWei Hu 		if (err) {
2313ce110ea1SWei Hu 			mana_err(NULL,
2314ce110ea1SWei Hu 			    "Failed to  create rx DMA map for buf %d\n",
2315ce110ea1SWei Hu 			    buf_idx);
2316ce110ea1SWei Hu 			return err;
2317ce110ea1SWei Hu 		}
2318ce110ea1SWei Hu 
2319ce110ea1SWei Hu 		err = mana_load_rx_mbuf(apc, rxq, rx_oob, true);
2320ce110ea1SWei Hu 		if (err) {
2321ce110ea1SWei Hu 			mana_err(NULL,
2322ce110ea1SWei Hu 			    "Failed to  create rx DMA map for buf %d\n",
2323ce110ea1SWei Hu 			    buf_idx);
2324ce110ea1SWei Hu 			bus_dmamap_destroy(apc->rx_buf_tag, rx_oob->dma_map);
2325ce110ea1SWei Hu 			return err;
2326ce110ea1SWei Hu 		}
2327ce110ea1SWei Hu 
2328ce110ea1SWei Hu 		rx_oob->wqe_req.sgl = rx_oob->sgl;
2329ce110ea1SWei Hu 		rx_oob->wqe_req.num_sge = rx_oob->num_sge;
2330ce110ea1SWei Hu 		rx_oob->wqe_req.inline_oob_size = 0;
2331ce110ea1SWei Hu 		rx_oob->wqe_req.inline_oob_data = NULL;
2332ce110ea1SWei Hu 		rx_oob->wqe_req.flags = 0;
2333ce110ea1SWei Hu 		rx_oob->wqe_req.client_data_unit = 0;
2334ce110ea1SWei Hu 
2335ce110ea1SWei Hu 		*rxq_size += ALIGN(MANA_WQE_HEADER_SIZE +
2336ce110ea1SWei Hu 				   MANA_WQE_SGE_SIZE * rx_oob->num_sge, 32);
2337ce110ea1SWei Hu 		*cq_size += COMP_ENTRY_SIZE;
2338ce110ea1SWei Hu 	}
2339ce110ea1SWei Hu 
2340ce110ea1SWei Hu 	return 0;
2341ce110ea1SWei Hu }
2342ce110ea1SWei Hu 
2343ce110ea1SWei Hu static int
mana_push_wqe(struct mana_rxq * rxq)2344ce110ea1SWei Hu mana_push_wqe(struct mana_rxq *rxq)
2345ce110ea1SWei Hu {
2346ce110ea1SWei Hu 	struct mana_recv_buf_oob *rx_oob;
2347ce110ea1SWei Hu 	uint32_t buf_idx;
2348ce110ea1SWei Hu 	int err;
2349ce110ea1SWei Hu 
2350ce110ea1SWei Hu 	for (buf_idx = 0; buf_idx < rxq->num_rx_buf; buf_idx++) {
2351ce110ea1SWei Hu 		rx_oob = &rxq->rx_oobs[buf_idx];
2352ce110ea1SWei Hu 
2353ce110ea1SWei Hu 		err = mana_gd_post_and_ring(rxq->gdma_rq, &rx_oob->wqe_req,
2354ce110ea1SWei Hu 		    &rx_oob->wqe_inf);
2355ce110ea1SWei Hu 		if (err)
2356ce110ea1SWei Hu 			return ENOSPC;
2357ce110ea1SWei Hu 	}
2358ce110ea1SWei Hu 
2359ce110ea1SWei Hu 	return 0;
2360ce110ea1SWei Hu }
2361ce110ea1SWei Hu 
2362ce110ea1SWei Hu static struct mana_rxq *
mana_create_rxq(struct mana_port_context * apc,uint32_t rxq_idx,struct mana_eq * eq,if_t ndev)2363ce110ea1SWei Hu mana_create_rxq(struct mana_port_context *apc, uint32_t rxq_idx,
236437d22ce0SJustin Hibbits     struct mana_eq *eq, if_t ndev)
2365ce110ea1SWei Hu {
2366ce110ea1SWei Hu 	struct gdma_dev *gd = apc->ac->gdma_dev;
2367ce110ea1SWei Hu 	struct mana_obj_spec wq_spec;
2368ce110ea1SWei Hu 	struct mana_obj_spec cq_spec;
2369ce110ea1SWei Hu 	struct gdma_queue_spec spec;
2370ce110ea1SWei Hu 	struct mana_cq *cq = NULL;
2371ce110ea1SWei Hu 	uint32_t cq_size, rq_size;
2372ce110ea1SWei Hu 	struct gdma_context *gc;
2373ce110ea1SWei Hu 	struct mana_rxq *rxq;
2374ce110ea1SWei Hu 	int err;
2375ce110ea1SWei Hu 
2376ce110ea1SWei Hu 	gc = gd->gdma_context;
2377ce110ea1SWei Hu 
2378ce110ea1SWei Hu 	rxq = malloc(sizeof(*rxq) +
2379a18e9994SWei Hu 	    apc->rx_queue_size * sizeof(struct mana_recv_buf_oob),
2380ce110ea1SWei Hu 	    M_DEVBUF, M_WAITOK | M_ZERO);
2381ce110ea1SWei Hu 	rxq->ndev = ndev;
2382a18e9994SWei Hu 	rxq->num_rx_buf = apc->rx_queue_size;
2383ce110ea1SWei Hu 	rxq->rxq_idx = rxq_idx;
2384ce110ea1SWei Hu 	/*
2385ce110ea1SWei Hu 	 * Minimum size is MCLBYTES(2048) bytes for a mbuf cluster.
2386a506133aSGordon Bergling 	 * Now we just allow maximum size of 4096.
2387ce110ea1SWei Hu 	 */
2388ce110ea1SWei Hu 	rxq->datasize = ALIGN(apc->frame_size, MCLBYTES);
2389ce110ea1SWei Hu 	if (rxq->datasize > MAX_FRAME_SIZE)
2390ce110ea1SWei Hu 		rxq->datasize = MAX_FRAME_SIZE;
2391ce110ea1SWei Hu 
2392ce110ea1SWei Hu 	mana_dbg(NULL, "Setting rxq %d datasize %d\n",
2393ce110ea1SWei Hu 	    rxq_idx, rxq->datasize);
2394ce110ea1SWei Hu 
2395*9b8701b8SWei Hu 	/*
2396*9b8701b8SWei Hu 	 * Two steps to set the mbuf refill_thresh.
2397*9b8701b8SWei Hu 	 * 1) If mana_rx_refill_threshold is set, honor it.
2398*9b8701b8SWei Hu 	 *    Set to default value otherwise.
2399*9b8701b8SWei Hu 	 * 2) Select the smaller of 1) above and 1/4 of the
2400*9b8701b8SWei Hu 	 *    rx buffer size.
2401*9b8701b8SWei Hu 	 */
2402*9b8701b8SWei Hu 	if (mana_rx_refill_threshold != 0)
2403*9b8701b8SWei Hu 		rxq->refill_thresh = mana_rx_refill_threshold;
2404*9b8701b8SWei Hu 	else
2405*9b8701b8SWei Hu 		rxq->refill_thresh = MANA_RX_REFILL_THRESH;
2406*9b8701b8SWei Hu 	rxq->refill_thresh = min_t(uint32_t,
2407*9b8701b8SWei Hu 	    rxq->num_rx_buf / 4, rxq->refill_thresh);
2408*9b8701b8SWei Hu 
2409*9b8701b8SWei Hu 	mana_dbg(NULL, "Setting rxq %d refill thresh %u\n",
2410*9b8701b8SWei Hu 	    rxq_idx, rxq->refill_thresh);
2411*9b8701b8SWei Hu 
2412ce110ea1SWei Hu 	rxq->rxobj = INVALID_MANA_HANDLE;
2413ce110ea1SWei Hu 
2414ce110ea1SWei Hu 	err = mana_alloc_rx_wqe(apc, rxq, &rq_size, &cq_size);
2415ce110ea1SWei Hu 	if (err)
2416ce110ea1SWei Hu 		goto out;
2417ce110ea1SWei Hu 
2418ce110ea1SWei Hu 	/* Create LRO for the RQ */
241937d22ce0SJustin Hibbits 	if (if_getcapenable(ndev) & IFCAP_LRO) {
2420ce110ea1SWei Hu 		err = tcp_lro_init(&rxq->lro);
2421ce110ea1SWei Hu 		if (err) {
2422ce110ea1SWei Hu 			if_printf(ndev, "Failed to create LRO for rxq %d\n",
2423ce110ea1SWei Hu 			    rxq_idx);
2424ce110ea1SWei Hu 		} else {
2425ce110ea1SWei Hu 			rxq->lro.ifp = ndev;
2426ce110ea1SWei Hu 		}
2427ce110ea1SWei Hu 	}
2428ce110ea1SWei Hu 
2429ce110ea1SWei Hu 	mana_alloc_counters((counter_u64_t *)&rxq->stats,
2430ce110ea1SWei Hu 	    sizeof(rxq->stats));
2431ce110ea1SWei Hu 
2432ce110ea1SWei Hu 	rq_size = ALIGN(rq_size, PAGE_SIZE);
2433ce110ea1SWei Hu 	cq_size = ALIGN(cq_size, PAGE_SIZE);
2434ce110ea1SWei Hu 
2435ce110ea1SWei Hu 	/* Create RQ */
2436ce110ea1SWei Hu 	memset(&spec, 0, sizeof(spec));
2437ce110ea1SWei Hu 	spec.type = GDMA_RQ;
2438ce110ea1SWei Hu 	spec.monitor_avl_buf = true;
2439ce110ea1SWei Hu 	spec.queue_size = rq_size;
2440ce110ea1SWei Hu 	err = mana_gd_create_mana_wq_cq(gd, &spec, &rxq->gdma_rq);
2441ce110ea1SWei Hu 	if (err)
2442ce110ea1SWei Hu 		goto out;
2443ce110ea1SWei Hu 
2444ce110ea1SWei Hu 	/* Create RQ's CQ */
2445ce110ea1SWei Hu 	cq = &rxq->rx_cq;
2446ce110ea1SWei Hu 	cq->type = MANA_CQ_TYPE_RX;
2447ce110ea1SWei Hu 	cq->rxq = rxq;
2448ce110ea1SWei Hu 
2449ce110ea1SWei Hu 	memset(&spec, 0, sizeof(spec));
2450ce110ea1SWei Hu 	spec.type = GDMA_CQ;
2451ce110ea1SWei Hu 	spec.monitor_avl_buf = false;
2452ce110ea1SWei Hu 	spec.queue_size = cq_size;
24531833cf13SWei Hu 	spec.cq.callback = mana_schedule_task;
2454ce110ea1SWei Hu 	spec.cq.parent_eq = eq->eq;
2455ce110ea1SWei Hu 	spec.cq.context = cq;
2456ce110ea1SWei Hu 	err = mana_gd_create_mana_wq_cq(gd, &spec, &cq->gdma_cq);
2457ce110ea1SWei Hu 	if (err)
2458ce110ea1SWei Hu 		goto out;
2459ce110ea1SWei Hu 
2460ce110ea1SWei Hu 	memset(&wq_spec, 0, sizeof(wq_spec));
2461ce110ea1SWei Hu 	memset(&cq_spec, 0, sizeof(cq_spec));
2462b685df31SWei Hu 	wq_spec.gdma_region = rxq->gdma_rq->mem_info.dma_region_handle;
2463ce110ea1SWei Hu 	wq_spec.queue_size = rxq->gdma_rq->queue_size;
2464ce110ea1SWei Hu 
2465b685df31SWei Hu 	cq_spec.gdma_region = cq->gdma_cq->mem_info.dma_region_handle;
2466ce110ea1SWei Hu 	cq_spec.queue_size = cq->gdma_cq->queue_size;
2467ce110ea1SWei Hu 	cq_spec.modr_ctx_id = 0;
2468ce110ea1SWei Hu 	cq_spec.attached_eq = cq->gdma_cq->cq.parent->id;
2469ce110ea1SWei Hu 
2470ce110ea1SWei Hu 	err = mana_create_wq_obj(apc, apc->port_handle, GDMA_RQ,
2471ce110ea1SWei Hu 	    &wq_spec, &cq_spec, &rxq->rxobj);
2472ce110ea1SWei Hu 	if (err)
2473ce110ea1SWei Hu 		goto out;
2474ce110ea1SWei Hu 
2475ce110ea1SWei Hu 	rxq->gdma_rq->id = wq_spec.queue_index;
2476ce110ea1SWei Hu 	cq->gdma_cq->id = cq_spec.queue_index;
2477ce110ea1SWei Hu 
2478b685df31SWei Hu 	rxq->gdma_rq->mem_info.dma_region_handle = GDMA_INVALID_DMA_REGION;
2479b685df31SWei Hu 	cq->gdma_cq->mem_info.dma_region_handle = GDMA_INVALID_DMA_REGION;
2480ce110ea1SWei Hu 
2481ce110ea1SWei Hu 	rxq->gdma_id = rxq->gdma_rq->id;
2482ce110ea1SWei Hu 	cq->gdma_id = cq->gdma_cq->id;
2483ce110ea1SWei Hu 
2484ce110ea1SWei Hu 	err = mana_push_wqe(rxq);
2485ce110ea1SWei Hu 	if (err)
2486ce110ea1SWei Hu 		goto out;
2487ce110ea1SWei Hu 
2488027d0c1cSWei Hu 	if (cq->gdma_id >= gc->max_num_cqs) {
2489027d0c1cSWei Hu 		err = EINVAL;
2490ce110ea1SWei Hu 		goto out;
2491027d0c1cSWei Hu 	}
2492ce110ea1SWei Hu 
2493ce110ea1SWei Hu 	gc->cq_table[cq->gdma_id] = cq->gdma_cq;
2494ce110ea1SWei Hu 
24951833cf13SWei Hu 	/* Allocate and start the cleanup task on CQ */
24961833cf13SWei Hu 	cq->do_not_ring_db = false;
24971833cf13SWei Hu 
24981833cf13SWei Hu 	NET_TASK_INIT(&cq->cleanup_task, 0, mana_poll, cq);
24991833cf13SWei Hu 	cq->cleanup_tq =
25001833cf13SWei Hu 	    taskqueue_create_fast("mana rx cq cleanup",
25011833cf13SWei Hu 	    M_WAITOK, taskqueue_thread_enqueue,
25021833cf13SWei Hu 	    &cq->cleanup_tq);
25031833cf13SWei Hu 
25041833cf13SWei Hu 	if (apc->last_rx_cq_bind_cpu < 0)
25051833cf13SWei Hu 		apc->last_rx_cq_bind_cpu = CPU_FIRST();
25061833cf13SWei Hu 	cq->cpu = apc->last_rx_cq_bind_cpu;
25071833cf13SWei Hu 	apc->last_rx_cq_bind_cpu = CPU_NEXT(apc->last_rx_cq_bind_cpu);
25081833cf13SWei Hu 
25091833cf13SWei Hu 	if (apc->bind_cleanup_thread_cpu) {
25101833cf13SWei Hu 		cpuset_t cpu_mask;
25111833cf13SWei Hu 		CPU_SETOF(cq->cpu, &cpu_mask);
25121833cf13SWei Hu 		taskqueue_start_threads_cpuset(&cq->cleanup_tq,
25131833cf13SWei Hu 		    1, PI_NET, &cpu_mask,
25141833cf13SWei Hu 		    "mana cq p%u-rx%u-cpu%d",
25151833cf13SWei Hu 		    apc->port_idx, rxq->rxq_idx, cq->cpu);
25161833cf13SWei Hu 	} else {
25171833cf13SWei Hu 		taskqueue_start_threads(&cq->cleanup_tq, 1,
25181833cf13SWei Hu 		    PI_NET, "mana cq p%u-rx%u",
25191833cf13SWei Hu 		    apc->port_idx, rxq->rxq_idx);
25201833cf13SWei Hu 	}
25211833cf13SWei Hu 
25221833cf13SWei Hu 	mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT);
2523ce110ea1SWei Hu out:
2524ce110ea1SWei Hu 	if (!err)
2525ce110ea1SWei Hu 		return rxq;
2526ce110ea1SWei Hu 
2527ce110ea1SWei Hu 	if_printf(ndev, "Failed to create RXQ: err = %d\n", err);
2528ce110ea1SWei Hu 
2529ce110ea1SWei Hu 	mana_destroy_rxq(apc, rxq, false);
2530ce110ea1SWei Hu 
2531ce110ea1SWei Hu 	if (cq)
2532ce110ea1SWei Hu 		mana_deinit_cq(apc, cq);
2533ce110ea1SWei Hu 
2534ce110ea1SWei Hu 	return NULL;
2535ce110ea1SWei Hu }
2536ce110ea1SWei Hu 
2537ce110ea1SWei Hu static int
mana_add_rx_queues(struct mana_port_context * apc,if_t ndev)253837d22ce0SJustin Hibbits mana_add_rx_queues(struct mana_port_context *apc, if_t ndev)
2539ce110ea1SWei Hu {
25401833cf13SWei Hu 	struct mana_context *ac = apc->ac;
2541ce110ea1SWei Hu 	struct mana_rxq *rxq;
2542ce110ea1SWei Hu 	int err = 0;
2543ce110ea1SWei Hu 	int i;
2544ce110ea1SWei Hu 
2545ce110ea1SWei Hu 	for (i = 0; i < apc->num_queues; i++) {
25461833cf13SWei Hu 		rxq = mana_create_rxq(apc, i, &ac->eqs[i], ndev);
2547ce110ea1SWei Hu 		if (!rxq) {
2548ce110ea1SWei Hu 			err = ENOMEM;
2549ce110ea1SWei Hu 			goto out;
2550ce110ea1SWei Hu 		}
2551ce110ea1SWei Hu 
2552ce110ea1SWei Hu 		apc->rxqs[i] = rxq;
2553ce110ea1SWei Hu 	}
2554ce110ea1SWei Hu 
2555ce110ea1SWei Hu 	apc->default_rxobj = apc->rxqs[0]->rxobj;
2556ce110ea1SWei Hu out:
2557ce110ea1SWei Hu 	return err;
2558ce110ea1SWei Hu }
2559ce110ea1SWei Hu 
2560ce110ea1SWei Hu static void
mana_destroy_vport(struct mana_port_context * apc)2561ce110ea1SWei Hu mana_destroy_vport(struct mana_port_context *apc)
2562ce110ea1SWei Hu {
2563ce110ea1SWei Hu 	struct mana_rxq *rxq;
2564ce110ea1SWei Hu 	uint32_t rxq_idx;
2565ce110ea1SWei Hu 
2566ce110ea1SWei Hu 	for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) {
2567ce110ea1SWei Hu 		rxq = apc->rxqs[rxq_idx];
2568ce110ea1SWei Hu 		if (!rxq)
2569ce110ea1SWei Hu 			continue;
2570ce110ea1SWei Hu 
2571ce110ea1SWei Hu 		mana_destroy_rxq(apc, rxq, true);
2572ce110ea1SWei Hu 		apc->rxqs[rxq_idx] = NULL;
2573ce110ea1SWei Hu 	}
2574ce110ea1SWei Hu 
2575ce110ea1SWei Hu 	mana_destroy_txq(apc);
2576b685df31SWei Hu 
2577b685df31SWei Hu 	mana_uncfg_vport(apc);
2578ce110ea1SWei Hu }
2579ce110ea1SWei Hu 
2580ce110ea1SWei Hu static int
mana_create_vport(struct mana_port_context * apc,if_t net)258137d22ce0SJustin Hibbits mana_create_vport(struct mana_port_context *apc, if_t net)
2582ce110ea1SWei Hu {
2583ce110ea1SWei Hu 	struct gdma_dev *gd = apc->ac->gdma_dev;
2584ce110ea1SWei Hu 	int err;
2585ce110ea1SWei Hu 
2586ce110ea1SWei Hu 	apc->default_rxobj = INVALID_MANA_HANDLE;
2587ce110ea1SWei Hu 
2588ce110ea1SWei Hu 	err = mana_cfg_vport(apc, gd->pdid, gd->doorbell);
2589ce110ea1SWei Hu 	if (err)
2590ce110ea1SWei Hu 		return err;
2591ce110ea1SWei Hu 
2592ce110ea1SWei Hu 	return mana_create_txq(apc, net);
2593ce110ea1SWei Hu }
2594ce110ea1SWei Hu 
2595ce110ea1SWei Hu 
mana_rss_table_init(struct mana_port_context * apc)2596ce110ea1SWei Hu static void mana_rss_table_init(struct mana_port_context *apc)
2597ce110ea1SWei Hu {
2598ce110ea1SWei Hu 	int i;
2599ce110ea1SWei Hu 
2600ce110ea1SWei Hu 	for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++)
2601ce110ea1SWei Hu 		apc->indir_table[i] = i % apc->num_queues;
2602ce110ea1SWei Hu }
2603ce110ea1SWei Hu 
mana_config_rss(struct mana_port_context * apc,enum TRI_STATE rx,bool update_hash,bool update_tab)2604ce110ea1SWei Hu int mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx,
2605ce110ea1SWei Hu 		    bool update_hash, bool update_tab)
2606ce110ea1SWei Hu {
2607ce110ea1SWei Hu 	uint32_t queue_idx;
2608aa108bc7SWei Hu 	int err;
2609ce110ea1SWei Hu 	int i;
2610ce110ea1SWei Hu 
2611ce110ea1SWei Hu 	if (update_tab) {
2612ce110ea1SWei Hu 		for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) {
2613ce110ea1SWei Hu 			queue_idx = apc->indir_table[i];
2614ce110ea1SWei Hu 			apc->rxobj_table[i] = apc->rxqs[queue_idx]->rxobj;
2615ce110ea1SWei Hu 		}
2616ce110ea1SWei Hu 	}
2617ce110ea1SWei Hu 
2618aa108bc7SWei Hu 	err = mana_cfg_vport_steering(apc, rx, true, update_hash, update_tab);
2619aa108bc7SWei Hu 	if (err)
2620aa108bc7SWei Hu 		return err;
2621aa108bc7SWei Hu 
2622aa108bc7SWei Hu 	mana_fence_rqs(apc);
2623aa108bc7SWei Hu 
2624aa108bc7SWei Hu 	return 0;
2625ce110ea1SWei Hu }
2626ce110ea1SWei Hu 
2627ce110ea1SWei Hu static int
mana_init_port(if_t ndev)262837d22ce0SJustin Hibbits mana_init_port(if_t ndev)
2629ce110ea1SWei Hu {
2630ce110ea1SWei Hu 	struct mana_port_context *apc = if_getsoftc(ndev);
2631ce110ea1SWei Hu 	uint32_t max_txq, max_rxq, max_queues;
2632ce110ea1SWei Hu 	int port_idx = apc->port_idx;
2633ce110ea1SWei Hu 	uint32_t num_indirect_entries;
2634ce110ea1SWei Hu 	int err;
2635ce110ea1SWei Hu 
2636ce110ea1SWei Hu 	err = mana_init_port_context(apc);
2637ce110ea1SWei Hu 	if (err)
2638ce110ea1SWei Hu 		return err;
2639ce110ea1SWei Hu 
2640ce110ea1SWei Hu 	err = mana_query_vport_cfg(apc, port_idx, &max_txq, &max_rxq,
2641ce110ea1SWei Hu 	    &num_indirect_entries);
2642ce110ea1SWei Hu 	if (err) {
2643027d0c1cSWei Hu 		if_printf(ndev, "Failed to query info for vPort %d\n",
2644027d0c1cSWei Hu 		    port_idx);
2645ce110ea1SWei Hu 		goto reset_apc;
2646ce110ea1SWei Hu 	}
2647ce110ea1SWei Hu 
2648ce110ea1SWei Hu 	max_queues = min_t(uint32_t, max_txq, max_rxq);
2649ce110ea1SWei Hu 	if (apc->max_queues > max_queues)
2650ce110ea1SWei Hu 		apc->max_queues = max_queues;
2651ce110ea1SWei Hu 
2652ce110ea1SWei Hu 	if (apc->num_queues > apc->max_queues)
2653ce110ea1SWei Hu 		apc->num_queues = apc->max_queues;
2654ce110ea1SWei Hu 
2655ce110ea1SWei Hu 	return 0;
2656ce110ea1SWei Hu 
2657ce110ea1SWei Hu reset_apc:
2658ce110ea1SWei Hu 	bus_dma_tag_destroy(apc->rx_buf_tag);
2659ce110ea1SWei Hu 	apc->rx_buf_tag = NULL;
2660ce110ea1SWei Hu 	free(apc->rxqs, M_DEVBUF);
2661ce110ea1SWei Hu 	apc->rxqs = NULL;
2662ce110ea1SWei Hu 	return err;
2663ce110ea1SWei Hu }
2664ce110ea1SWei Hu 
2665ce110ea1SWei Hu int
mana_alloc_queues(if_t ndev)266637d22ce0SJustin Hibbits mana_alloc_queues(if_t ndev)
2667ce110ea1SWei Hu {
2668ce110ea1SWei Hu 	struct mana_port_context *apc = if_getsoftc(ndev);
2669ce110ea1SWei Hu 	int err;
2670ce110ea1SWei Hu 
2671ce110ea1SWei Hu 	err = mana_create_vport(apc, ndev);
2672ce110ea1SWei Hu 	if (err)
26731833cf13SWei Hu 		return err;
2674ce110ea1SWei Hu 
2675ce110ea1SWei Hu 	err = mana_add_rx_queues(apc, ndev);
2676ce110ea1SWei Hu 	if (err)
2677ce110ea1SWei Hu 		goto destroy_vport;
2678ce110ea1SWei Hu 
2679ce110ea1SWei Hu 	apc->rss_state = apc->num_queues > 1 ? TRI_STATE_TRUE : TRI_STATE_FALSE;
2680ce110ea1SWei Hu 
2681ce110ea1SWei Hu 	mana_rss_table_init(apc);
2682ce110ea1SWei Hu 
2683ce110ea1SWei Hu 	err = mana_config_rss(apc, TRI_STATE_TRUE, true, true);
2684ce110ea1SWei Hu 	if (err)
2685ce110ea1SWei Hu 		goto destroy_vport;
2686ce110ea1SWei Hu 
2687ce110ea1SWei Hu 	return 0;
2688ce110ea1SWei Hu 
2689ce110ea1SWei Hu destroy_vport:
2690ce110ea1SWei Hu 	mana_destroy_vport(apc);
2691ce110ea1SWei Hu 	return err;
2692ce110ea1SWei Hu }
2693ce110ea1SWei Hu 
2694ce110ea1SWei Hu static int
mana_up(struct mana_port_context * apc)2695ce110ea1SWei Hu mana_up(struct mana_port_context *apc)
2696ce110ea1SWei Hu {
2697ce110ea1SWei Hu 	int err;
2698ce110ea1SWei Hu 
2699ce110ea1SWei Hu 	mana_dbg(NULL, "mana_up called\n");
2700ce110ea1SWei Hu 
2701ce110ea1SWei Hu 	err = mana_alloc_queues(apc->ndev);
2702ce110ea1SWei Hu 	if (err) {
2703ce110ea1SWei Hu 		mana_err(NULL, "Faile alloc mana queues: %d\n", err);
2704ce110ea1SWei Hu 		return err;
2705ce110ea1SWei Hu 	}
2706ce110ea1SWei Hu 
2707ce110ea1SWei Hu 	/* Add queue specific sysctl */
2708ce110ea1SWei Hu 	mana_sysctl_add_queues(apc);
2709ce110ea1SWei Hu 
2710ce110ea1SWei Hu 	apc->port_is_up = true;
2711ce110ea1SWei Hu 
2712ce110ea1SWei Hu 	/* Ensure port state updated before txq state */
2713ce110ea1SWei Hu 	wmb();
2714ce110ea1SWei Hu 
2715ce110ea1SWei Hu 	if_link_state_change(apc->ndev, LINK_STATE_UP);
2716ce110ea1SWei Hu 	if_setdrvflagbits(apc->ndev, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
2717ce110ea1SWei Hu 
2718ce110ea1SWei Hu 	return 0;
2719ce110ea1SWei Hu }
2720ce110ea1SWei Hu 
2721ce110ea1SWei Hu 
2722ce110ea1SWei Hu static void
mana_init(void * arg)2723ce110ea1SWei Hu mana_init(void *arg)
2724ce110ea1SWei Hu {
2725ce110ea1SWei Hu 	struct mana_port_context *apc = (struct mana_port_context *)arg;
2726ce110ea1SWei Hu 
2727ce110ea1SWei Hu 	MANA_APC_LOCK_LOCK(apc);
2728ce110ea1SWei Hu 	if (!apc->port_is_up) {
2729ce110ea1SWei Hu 		mana_up(apc);
2730ce110ea1SWei Hu 	}
2731ce110ea1SWei Hu 	MANA_APC_LOCK_UNLOCK(apc);
2732ce110ea1SWei Hu }
2733ce110ea1SWei Hu 
2734ce110ea1SWei Hu static int
mana_dealloc_queues(if_t ndev)273537d22ce0SJustin Hibbits mana_dealloc_queues(if_t ndev)
2736ce110ea1SWei Hu {
2737ce110ea1SWei Hu 	struct mana_port_context *apc = if_getsoftc(ndev);
2738ce110ea1SWei Hu 	struct mana_txq *txq;
2739ce110ea1SWei Hu 	int i, err;
2740ce110ea1SWei Hu 
2741ce110ea1SWei Hu 	if (apc->port_is_up)
2742ce110ea1SWei Hu 		return EINVAL;
2743ce110ea1SWei Hu 
2744ce110ea1SWei Hu 	/* No packet can be transmitted now since apc->port_is_up is false.
2745ce110ea1SWei Hu 	 * There is still a tiny chance that mana_poll_tx_cq() can re-enable
2746ce110ea1SWei Hu 	 * a txq because it may not timely see apc->port_is_up being cleared
2747ce110ea1SWei Hu 	 * to false, but it doesn't matter since mana_start_xmit() drops any
2748ce110ea1SWei Hu 	 * new packets due to apc->port_is_up being false.
2749ce110ea1SWei Hu 	 *
2750ce110ea1SWei Hu 	 * Drain all the in-flight TX packets
2751ce110ea1SWei Hu 	 */
2752ce110ea1SWei Hu 	for (i = 0; i < apc->num_queues; i++) {
2753ce110ea1SWei Hu 		txq = &apc->tx_qp[i].txq;
2754ce110ea1SWei Hu 
2755ce110ea1SWei Hu 		struct mana_cq *tx_cq = &apc->tx_qp[i].tx_cq;
27561833cf13SWei Hu 		struct mana_cq *rx_cq = &(apc->rxqs[i]->rx_cq);
27571833cf13SWei Hu 
27581833cf13SWei Hu 		tx_cq->do_not_ring_db = true;
27591833cf13SWei Hu 		rx_cq->do_not_ring_db = true;
27601833cf13SWei Hu 
2761ce110ea1SWei Hu 		/* Schedule a cleanup task */
27621833cf13SWei Hu 		taskqueue_enqueue(tx_cq->cleanup_tq, &tx_cq->cleanup_task);
2763ce110ea1SWei Hu 
2764ce110ea1SWei Hu 		while (atomic_read(&txq->pending_sends) > 0)
2765ce110ea1SWei Hu 			usleep_range(1000, 2000);
2766ce110ea1SWei Hu 	}
2767ce110ea1SWei Hu 
2768ce110ea1SWei Hu 	/* We're 100% sure the queues can no longer be woken up, because
2769ce110ea1SWei Hu 	 * we're sure now mana_poll_tx_cq() can't be running.
2770ce110ea1SWei Hu 	 */
2771ce110ea1SWei Hu 
2772ce110ea1SWei Hu 	apc->rss_state = TRI_STATE_FALSE;
2773ce110ea1SWei Hu 	err = mana_config_rss(apc, TRI_STATE_FALSE, false, false);
2774ce110ea1SWei Hu 	if (err) {
2775ce110ea1SWei Hu 		if_printf(ndev, "Failed to disable vPort: %d\n", err);
2776ce110ea1SWei Hu 		return err;
2777ce110ea1SWei Hu 	}
2778ce110ea1SWei Hu 
2779ce110ea1SWei Hu 	mana_destroy_vport(apc);
2780ce110ea1SWei Hu 
2781ce110ea1SWei Hu 	return 0;
2782ce110ea1SWei Hu }
2783ce110ea1SWei Hu 
2784ce110ea1SWei Hu static int
mana_down(struct mana_port_context * apc)2785ce110ea1SWei Hu mana_down(struct mana_port_context *apc)
2786ce110ea1SWei Hu {
2787ce110ea1SWei Hu 	int err = 0;
2788ce110ea1SWei Hu 
2789ce110ea1SWei Hu 	apc->port_st_save = apc->port_is_up;
2790ce110ea1SWei Hu 	apc->port_is_up = false;
2791ce110ea1SWei Hu 
2792ce110ea1SWei Hu 	/* Ensure port state updated before txq state */
2793ce110ea1SWei Hu 	wmb();
2794ce110ea1SWei Hu 
2795ce110ea1SWei Hu 	if (apc->port_st_save) {
2796ce110ea1SWei Hu 		if_setdrvflagbits(apc->ndev, IFF_DRV_OACTIVE,
2797ce110ea1SWei Hu 		    IFF_DRV_RUNNING);
2798ce110ea1SWei Hu 		if_link_state_change(apc->ndev, LINK_STATE_DOWN);
2799ce110ea1SWei Hu 
2800ce110ea1SWei Hu 		mana_sysctl_free_queues(apc);
2801ce110ea1SWei Hu 
2802ce110ea1SWei Hu 		err = mana_dealloc_queues(apc->ndev);
2803ce110ea1SWei Hu 		if (err) {
2804ce110ea1SWei Hu 			if_printf(apc->ndev,
2805ce110ea1SWei Hu 			    "Failed to bring down mana interface: %d\n", err);
2806ce110ea1SWei Hu 		}
2807ce110ea1SWei Hu 	}
2808ce110ea1SWei Hu 
2809ce110ea1SWei Hu 	return err;
2810ce110ea1SWei Hu }
2811ce110ea1SWei Hu 
2812ce110ea1SWei Hu int
mana_detach(if_t ndev)281337d22ce0SJustin Hibbits mana_detach(if_t ndev)
2814ce110ea1SWei Hu {
2815ce110ea1SWei Hu 	struct mana_port_context *apc = if_getsoftc(ndev);
2816ce110ea1SWei Hu 	int err;
2817ce110ea1SWei Hu 
2818ce110ea1SWei Hu 	ether_ifdetach(ndev);
2819ce110ea1SWei Hu 
2820ce110ea1SWei Hu 	if (!apc)
2821ce110ea1SWei Hu 		return 0;
2822ce110ea1SWei Hu 
2823ce110ea1SWei Hu 	MANA_APC_LOCK_LOCK(apc);
2824ce110ea1SWei Hu 	err = mana_down(apc);
2825ce110ea1SWei Hu 	MANA_APC_LOCK_UNLOCK(apc);
2826ce110ea1SWei Hu 
2827ce110ea1SWei Hu 	mana_cleanup_port_context(apc);
2828ce110ea1SWei Hu 
2829ce110ea1SWei Hu 	MANA_APC_LOCK_DESTROY(apc);
2830ce110ea1SWei Hu 
2831ce110ea1SWei Hu 	free(apc, M_DEVBUF);
2832ce110ea1SWei Hu 
2833ce110ea1SWei Hu 	return err;
2834ce110ea1SWei Hu }
2835ce110ea1SWei Hu 
2836a18e9994SWei Hu static unsigned int
mana_get_tx_queue_size(int port_idx,unsigned int request_size)2837a18e9994SWei Hu mana_get_tx_queue_size(int port_idx, unsigned int request_size)
2838a18e9994SWei Hu {
2839a18e9994SWei Hu 	unsigned int new_size;
2840a18e9994SWei Hu 
2841a18e9994SWei Hu 	if (request_size == 0)
2842a18e9994SWei Hu 		/* Uninitialized */
2843a18e9994SWei Hu 		new_size = DEF_SEND_BUFFERS_PER_QUEUE;
2844a18e9994SWei Hu 	else
2845a18e9994SWei Hu 		new_size = roundup_pow_of_two(request_size);
2846a18e9994SWei Hu 
2847a18e9994SWei Hu 	if (new_size < MIN_SEND_BUFFERS_PER_QUEUE ||
2848a18e9994SWei Hu 	    new_size > MAX_SEND_BUFFERS_PER_QUEUE) {
2849a18e9994SWei Hu 		mana_info(NULL, "mana port %d: requested tx buffer "
2850a18e9994SWei Hu 		    "size %u out of allowable range (%u - %u), "
2851a18e9994SWei Hu 		    "setting to default\n",
2852a18e9994SWei Hu 		    port_idx, request_size,
2853a18e9994SWei Hu 		    MIN_SEND_BUFFERS_PER_QUEUE,
2854a18e9994SWei Hu 		    MAX_SEND_BUFFERS_PER_QUEUE);
2855a18e9994SWei Hu 		new_size = DEF_SEND_BUFFERS_PER_QUEUE;
2856a18e9994SWei Hu 	}
2857a18e9994SWei Hu 	mana_info(NULL, "mana port %d: tx buffer size %u "
2858a18e9994SWei Hu 	    "(%u requested)\n",
2859a18e9994SWei Hu 	    port_idx, new_size, request_size);
2860a18e9994SWei Hu 
2861a18e9994SWei Hu 	return (new_size);
2862a18e9994SWei Hu }
2863a18e9994SWei Hu 
2864a18e9994SWei Hu static unsigned int
mana_get_rx_queue_size(int port_idx,unsigned int request_size)2865a18e9994SWei Hu mana_get_rx_queue_size(int port_idx, unsigned int request_size)
2866a18e9994SWei Hu {
2867a18e9994SWei Hu 	unsigned int new_size;
2868a18e9994SWei Hu 
2869a18e9994SWei Hu 	if (request_size == 0)
2870a18e9994SWei Hu 		/* Uninitialized */
2871a18e9994SWei Hu 		new_size = DEF_RX_BUFFERS_PER_QUEUE;
2872a18e9994SWei Hu 	else
2873a18e9994SWei Hu 		new_size = roundup_pow_of_two(request_size);
2874a18e9994SWei Hu 
2875a18e9994SWei Hu 	if (new_size < MIN_RX_BUFFERS_PER_QUEUE ||
2876a18e9994SWei Hu 	    new_size > MAX_RX_BUFFERS_PER_QUEUE) {
2877a18e9994SWei Hu 		mana_info(NULL, "mana port %d: requested rx buffer "
2878a18e9994SWei Hu 		    "size %u out of allowable range (%u - %u), "
2879a18e9994SWei Hu 		    "setting to default\n",
2880a18e9994SWei Hu 		    port_idx, request_size,
2881a18e9994SWei Hu 		    MIN_RX_BUFFERS_PER_QUEUE,
2882a18e9994SWei Hu 		    MAX_RX_BUFFERS_PER_QUEUE);
2883a18e9994SWei Hu 		new_size = DEF_RX_BUFFERS_PER_QUEUE;
2884a18e9994SWei Hu 	}
2885a18e9994SWei Hu 	mana_info(NULL, "mana port %d: rx buffer size %u "
2886a18e9994SWei Hu 	    "(%u requested)\n",
2887a18e9994SWei Hu 	    port_idx, new_size, request_size);
2888a18e9994SWei Hu 
2889a18e9994SWei Hu 	return (new_size);
2890a18e9994SWei Hu }
2891a18e9994SWei Hu 
2892ce110ea1SWei Hu static int
mana_probe_port(struct mana_context * ac,int port_idx,if_t * ndev_storage)2893ce110ea1SWei Hu mana_probe_port(struct mana_context *ac, int port_idx,
289437d22ce0SJustin Hibbits     if_t *ndev_storage)
2895ce110ea1SWei Hu {
2896ce110ea1SWei Hu 	struct gdma_context *gc = ac->gdma_dev->gdma_context;
2897ce110ea1SWei Hu 	struct mana_port_context *apc;
2898643fd7b4SWei Hu 	uint32_t hwassist;
289937d22ce0SJustin Hibbits 	if_t ndev;
2900ce110ea1SWei Hu 	int err;
2901ce110ea1SWei Hu 
2902ce110ea1SWei Hu 	ndev = if_alloc_dev(IFT_ETHER, gc->dev);
2903ce110ea1SWei Hu 	*ndev_storage = ndev;
2904ce110ea1SWei Hu 
2905ce110ea1SWei Hu 	apc = malloc(sizeof(*apc), M_DEVBUF, M_WAITOK | M_ZERO);
2906ce110ea1SWei Hu 	apc->ac = ac;
2907ce110ea1SWei Hu 	apc->ndev = ndev;
2908ce110ea1SWei Hu 	apc->max_queues = gc->max_num_queues;
2909ce110ea1SWei Hu 	apc->num_queues = min_t(unsigned int,
2910ce110ea1SWei Hu 	    gc->max_num_queues, MANA_MAX_NUM_QUEUES);
2911a18e9994SWei Hu 	apc->tx_queue_size = mana_get_tx_queue_size(port_idx,
2912a18e9994SWei Hu 	    mana_tx_req_size);
2913a18e9994SWei Hu 	apc->rx_queue_size = mana_get_rx_queue_size(port_idx,
2914a18e9994SWei Hu 	    mana_rx_req_size);
2915ce110ea1SWei Hu 	apc->port_handle = INVALID_MANA_HANDLE;
2916ce110ea1SWei Hu 	apc->port_idx = port_idx;
2917ce110ea1SWei Hu 	apc->frame_size = DEFAULT_FRAME_SIZE;
29181833cf13SWei Hu 	apc->last_tx_cq_bind_cpu = -1;
29191833cf13SWei Hu 	apc->last_rx_cq_bind_cpu = -1;
2920b685df31SWei Hu 	apc->vport_use_count = 0;
2921ce110ea1SWei Hu 
2922ce110ea1SWei Hu 	MANA_APC_LOCK_INIT(apc);
2923ce110ea1SWei Hu 
2924ce110ea1SWei Hu 	if_initname(ndev, device_get_name(gc->dev), port_idx);
2925ce110ea1SWei Hu 	if_setdev(ndev,gc->dev);
2926ce110ea1SWei Hu 	if_setsoftc(ndev, apc);
2927ce110ea1SWei Hu 
2928ce110ea1SWei Hu 	if_setflags(ndev, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
2929ce110ea1SWei Hu 	if_setinitfn(ndev, mana_init);
2930ce110ea1SWei Hu 	if_settransmitfn(ndev, mana_start_xmit);
2931ce110ea1SWei Hu 	if_setqflushfn(ndev, mana_qflush);
2932ce110ea1SWei Hu 	if_setioctlfn(ndev, mana_ioctl);
2933ce110ea1SWei Hu 	if_setgetcounterfn(ndev, mana_get_counter);
2934ce110ea1SWei Hu 
2935ce110ea1SWei Hu 	if_setmtu(ndev, ETHERMTU);
2936ce110ea1SWei Hu 	if_setbaudrate(ndev, IF_Gbps(100));
2937ce110ea1SWei Hu 
2938ce110ea1SWei Hu 	mana_rss_key_fill(apc->hashkey, MANA_HASH_KEY_SIZE);
2939ce110ea1SWei Hu 
2940ce110ea1SWei Hu 	err = mana_init_port(ndev);
2941ce110ea1SWei Hu 	if (err)
2942ce110ea1SWei Hu 		goto reset_apc;
2943ce110ea1SWei Hu 
294437d22ce0SJustin Hibbits 	if_setcapabilitiesbit(ndev,
294537d22ce0SJustin Hibbits 	    IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6 |
294637d22ce0SJustin Hibbits 	    IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 |
294737d22ce0SJustin Hibbits 	    IFCAP_TSO4 | IFCAP_TSO6 |
294837d22ce0SJustin Hibbits 	    IFCAP_LRO | IFCAP_LINKSTATE, 0);
2949ce110ea1SWei Hu 
2950ce110ea1SWei Hu 	/* Enable all available capabilities by default. */
295137d22ce0SJustin Hibbits 	if_setcapenable(ndev, if_getcapabilities(ndev));
2952ce110ea1SWei Hu 
2953ce110ea1SWei Hu 	/* TSO parameters */
2954643fd7b4SWei Hu 	if_sethwtsomax(ndev, MANA_TSO_MAX_SZ -
295537d22ce0SJustin Hibbits 	    (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN));
295637d22ce0SJustin Hibbits 	if_sethwtsomaxsegcount(ndev, MAX_MBUF_FRAGS);
295737d22ce0SJustin Hibbits 	if_sethwtsomaxsegsize(ndev, PAGE_SIZE);
2958ce110ea1SWei Hu 
2959643fd7b4SWei Hu 	hwassist = 0;
2960643fd7b4SWei Hu 	if (if_getcapenable(ndev) & (IFCAP_TSO4 | IFCAP_TSO6))
2961643fd7b4SWei Hu 		hwassist |= CSUM_TSO;
2962643fd7b4SWei Hu 	if (if_getcapenable(ndev) & IFCAP_TXCSUM)
2963643fd7b4SWei Hu 		hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP);
2964643fd7b4SWei Hu 	if (if_getcapenable(ndev) & IFCAP_TXCSUM_IPV6)
2965643fd7b4SWei Hu 		hwassist |= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6);
2966643fd7b4SWei Hu 	mana_dbg(NULL, "set hwassist 0x%x\n", hwassist);
2967643fd7b4SWei Hu 	if_sethwassist(ndev, hwassist);
2968643fd7b4SWei Hu 
2969ce110ea1SWei Hu 	ifmedia_init(&apc->media, IFM_IMASK,
2970ce110ea1SWei Hu 	    mana_ifmedia_change, mana_ifmedia_status);
2971ce110ea1SWei Hu 	ifmedia_add(&apc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
2972ce110ea1SWei Hu 	ifmedia_set(&apc->media, IFM_ETHER | IFM_AUTO);
2973ce110ea1SWei Hu 
2974ce110ea1SWei Hu 	ether_ifattach(ndev, apc->mac_addr);
2975ce110ea1SWei Hu 
2976ce110ea1SWei Hu 	/* Initialize statistics */
2977ce110ea1SWei Hu 	mana_alloc_counters((counter_u64_t *)&apc->port_stats,
2978ce110ea1SWei Hu 	    sizeof(struct mana_port_stats));
2979ce110ea1SWei Hu 	mana_sysctl_add_port(apc);
2980ce110ea1SWei Hu 
2981ce110ea1SWei Hu 	/* Tell the stack that the interface is not active */
2982ce110ea1SWei Hu 	if_setdrvflagbits(ndev, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
2983ce110ea1SWei Hu 
2984ce110ea1SWei Hu 	return 0;
2985ce110ea1SWei Hu 
2986ce110ea1SWei Hu reset_apc:
2987ce110ea1SWei Hu 	free(apc, M_DEVBUF);
2988ce110ea1SWei Hu 	*ndev_storage = NULL;
2989ce110ea1SWei Hu 	if_printf(ndev, "Failed to probe vPort %d: %d\n", port_idx, err);
2990ce110ea1SWei Hu 	if_free(ndev);
2991ce110ea1SWei Hu 	return err;
2992ce110ea1SWei Hu }
2993ce110ea1SWei Hu 
mana_probe(struct gdma_dev * gd)2994ce110ea1SWei Hu int mana_probe(struct gdma_dev *gd)
2995ce110ea1SWei Hu {
2996ce110ea1SWei Hu 	struct gdma_context *gc = gd->gdma_context;
2997ce110ea1SWei Hu 	device_t dev = gc->dev;
2998ce110ea1SWei Hu 	struct mana_context *ac;
2999ce110ea1SWei Hu 	int err;
3000ce110ea1SWei Hu 	int i;
3001ce110ea1SWei Hu 
3002ce110ea1SWei Hu 	device_printf(dev, "%s protocol version: %d.%d.%d\n", DEVICE_NAME,
3003ce110ea1SWei Hu 		 MANA_MAJOR_VERSION, MANA_MINOR_VERSION, MANA_MICRO_VERSION);
3004ce110ea1SWei Hu 
3005ce110ea1SWei Hu 	err = mana_gd_register_device(gd);
3006ce110ea1SWei Hu 	if (err)
3007ce110ea1SWei Hu 		return err;
3008ce110ea1SWei Hu 
3009ce110ea1SWei Hu 	ac = malloc(sizeof(*ac), M_DEVBUF, M_WAITOK | M_ZERO);
3010ce110ea1SWei Hu 	ac->gdma_dev = gd;
3011ce110ea1SWei Hu 	ac->num_ports = 1;
3012ce110ea1SWei Hu 	gd->driver_data = ac;
3013ce110ea1SWei Hu 
30141833cf13SWei Hu 	err = mana_create_eq(ac);
30151833cf13SWei Hu 	if (err)
30161833cf13SWei Hu 		goto out;
30171833cf13SWei Hu 
3018ce110ea1SWei Hu 	err = mana_query_device_cfg(ac, MANA_MAJOR_VERSION, MANA_MINOR_VERSION,
3019ce110ea1SWei Hu 	    MANA_MICRO_VERSION, &ac->num_ports);
3020ce110ea1SWei Hu 	if (err)
3021ce110ea1SWei Hu 		goto out;
3022ce110ea1SWei Hu 
3023ce110ea1SWei Hu 	if (ac->num_ports > MAX_PORTS_IN_MANA_DEV)
3024ce110ea1SWei Hu 		ac->num_ports = MAX_PORTS_IN_MANA_DEV;
3025ce110ea1SWei Hu 
3026ce110ea1SWei Hu 	for (i = 0; i < ac->num_ports; i++) {
3027ce110ea1SWei Hu 		err = mana_probe_port(ac, i, &ac->ports[i]);
3028ce110ea1SWei Hu 		if (err) {
3029ce110ea1SWei Hu 			device_printf(dev,
3030ce110ea1SWei Hu 			    "Failed to probe mana port %d\n", i);
3031ce110ea1SWei Hu 			break;
3032ce110ea1SWei Hu 		}
3033ce110ea1SWei Hu 	}
3034ce110ea1SWei Hu 
3035ce110ea1SWei Hu out:
3036ce110ea1SWei Hu 	if (err)
3037ce110ea1SWei Hu 		mana_remove(gd);
3038ce110ea1SWei Hu 
3039ce110ea1SWei Hu 	return err;
3040ce110ea1SWei Hu }
3041ce110ea1SWei Hu 
3042ce110ea1SWei Hu void
mana_remove(struct gdma_dev * gd)3043ce110ea1SWei Hu mana_remove(struct gdma_dev *gd)
3044ce110ea1SWei Hu {
3045ce110ea1SWei Hu 	struct gdma_context *gc = gd->gdma_context;
3046ce110ea1SWei Hu 	struct mana_context *ac = gd->driver_data;
3047ce110ea1SWei Hu 	device_t dev = gc->dev;
304837d22ce0SJustin Hibbits 	if_t ndev;
3049ce110ea1SWei Hu 	int i;
3050ce110ea1SWei Hu 
3051ce110ea1SWei Hu 	for (i = 0; i < ac->num_ports; i++) {
3052ce110ea1SWei Hu 		ndev = ac->ports[i];
3053ce110ea1SWei Hu 		if (!ndev) {
3054ce110ea1SWei Hu 			if (i == 0)
3055ce110ea1SWei Hu 				device_printf(dev, "No net device to remove\n");
3056ce110ea1SWei Hu 			goto out;
3057ce110ea1SWei Hu 		}
3058ce110ea1SWei Hu 
3059ce110ea1SWei Hu 		mana_detach(ndev);
3060ce110ea1SWei Hu 
3061ce110ea1SWei Hu 		if_free(ndev);
3062ce110ea1SWei Hu 	}
30631833cf13SWei Hu 
30641833cf13SWei Hu 	mana_destroy_eq(ac);
30651833cf13SWei Hu 
3066ce110ea1SWei Hu out:
3067ce110ea1SWei Hu 	mana_gd_deregister_device(gd);
3068ce110ea1SWei Hu 	gd->driver_data = NULL;
3069ce110ea1SWei Hu 	gd->gdma_context = NULL;
3070ce110ea1SWei Hu 	free(ac, M_DEVBUF);
3071ce110ea1SWei Hu }
3072