xref: /freebsd-src/sys/dev/dpaa2/dpaa2_ni.c (revision e69e172d40585cfbcfdb28433cec523ca4867cf1)
1ba7319e9SDmitry Salychev /*-
2ba7319e9SDmitry Salychev  * SPDX-License-Identifier: BSD-2-Clause
3ba7319e9SDmitry Salychev  *
4718bdb6aSDmitry Salychev  * Copyright © 2021-2023 Dmitry Salychev
5ba7319e9SDmitry Salychev  * Copyright © 2022 Mathew McBride
6ba7319e9SDmitry Salychev  *
7ba7319e9SDmitry Salychev  * Redistribution and use in source and binary forms, with or without
8ba7319e9SDmitry Salychev  * modification, are permitted provided that the following conditions
9ba7319e9SDmitry Salychev  * are met:
10ba7319e9SDmitry Salychev  * 1. Redistributions of source code must retain the above copyright
11ba7319e9SDmitry Salychev  *    notice, this list of conditions and the following disclaimer.
12ba7319e9SDmitry Salychev  * 2. Redistributions in binary form must reproduce the above copyright
13ba7319e9SDmitry Salychev  *    notice, this list of conditions and the following disclaimer in the
14ba7319e9SDmitry Salychev  *    documentation and/or other materials provided with the distribution.
15ba7319e9SDmitry Salychev  *
16ba7319e9SDmitry Salychev  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17ba7319e9SDmitry Salychev  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18ba7319e9SDmitry Salychev  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ba7319e9SDmitry Salychev  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20ba7319e9SDmitry Salychev  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21ba7319e9SDmitry Salychev  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22ba7319e9SDmitry Salychev  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23ba7319e9SDmitry Salychev  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24ba7319e9SDmitry Salychev  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25ba7319e9SDmitry Salychev  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26ba7319e9SDmitry Salychev  * SUCH DAMAGE.
27ba7319e9SDmitry Salychev  */
28ba7319e9SDmitry Salychev 
29ba7319e9SDmitry Salychev #include <sys/cdefs.h>
30ba7319e9SDmitry Salychev /*
31ba7319e9SDmitry Salychev  * The DPAA2 Network Interface (DPNI) driver.
32ba7319e9SDmitry Salychev  *
33ba7319e9SDmitry Salychev  * The DPNI object is a network interface that is configurable to support a wide
34ba7319e9SDmitry Salychev  * range of features from a very basic Ethernet interface up to a
35ba7319e9SDmitry Salychev  * high-functioning network interface. The DPNI supports features that are
36ba7319e9SDmitry Salychev  * expected by standard network stacks, from basic features to offloads.
37ba7319e9SDmitry Salychev  *
38ba7319e9SDmitry Salychev  * DPNIs work with Ethernet traffic, starting with the L2 header. Additional
39ba7319e9SDmitry Salychev  * functions are provided for standard network protocols (L2, L3, L4, etc.).
40ba7319e9SDmitry Salychev  */
41ba7319e9SDmitry Salychev 
42ba7319e9SDmitry Salychev #include <sys/param.h>
43ba7319e9SDmitry Salychev #include <sys/systm.h>
44ba7319e9SDmitry Salychev #include <sys/kernel.h>
45ba7319e9SDmitry Salychev #include <sys/bus.h>
46ba7319e9SDmitry Salychev #include <sys/rman.h>
47ba7319e9SDmitry Salychev #include <sys/module.h>
48ba7319e9SDmitry Salychev #include <sys/malloc.h>
49ba7319e9SDmitry Salychev #include <sys/mutex.h>
50ba7319e9SDmitry Salychev #include <sys/socket.h>
51ba7319e9SDmitry Salychev #include <sys/sockio.h>
52ba7319e9SDmitry Salychev #include <sys/sysctl.h>
53ba7319e9SDmitry Salychev #include <sys/mbuf.h>
54ba7319e9SDmitry Salychev #include <sys/taskqueue.h>
55ba7319e9SDmitry Salychev #include <sys/sysctl.h>
56ba7319e9SDmitry Salychev #include <sys/buf_ring.h>
57ba7319e9SDmitry Salychev #include <sys/smp.h>
58ba7319e9SDmitry Salychev #include <sys/proc.h>
59ba7319e9SDmitry Salychev 
60ba7319e9SDmitry Salychev #include <vm/vm.h>
61ba7319e9SDmitry Salychev #include <vm/pmap.h>
62ba7319e9SDmitry Salychev 
63ba7319e9SDmitry Salychev #include <machine/bus.h>
64ba7319e9SDmitry Salychev #include <machine/resource.h>
65ba7319e9SDmitry Salychev #include <machine/atomic.h>
66718bdb6aSDmitry Salychev #include <machine/vmparam.h>
67ba7319e9SDmitry Salychev 
68ba7319e9SDmitry Salychev #include <net/ethernet.h>
69ba7319e9SDmitry Salychev #include <net/bpf.h>
70ba7319e9SDmitry Salychev #include <net/if.h>
71ba7319e9SDmitry Salychev #include <net/if_dl.h>
72ba7319e9SDmitry Salychev #include <net/if_media.h>
73ba7319e9SDmitry Salychev #include <net/if_types.h>
74ba7319e9SDmitry Salychev #include <net/if_var.h>
75ba7319e9SDmitry Salychev 
76ba7319e9SDmitry Salychev #include <dev/pci/pcivar.h>
77ba7319e9SDmitry Salychev #include <dev/mii/mii.h>
78ba7319e9SDmitry Salychev #include <dev/mii/miivar.h>
79ba7319e9SDmitry Salychev #include <dev/mdio/mdio.h>
80ba7319e9SDmitry Salychev 
81ba7319e9SDmitry Salychev #include "opt_acpi.h"
82ba7319e9SDmitry Salychev #include "opt_platform.h"
83ba7319e9SDmitry Salychev 
84ba7319e9SDmitry Salychev #include "pcib_if.h"
85ba7319e9SDmitry Salychev #include "pci_if.h"
86ba7319e9SDmitry Salychev #include "miibus_if.h"
87ba7319e9SDmitry Salychev #include "memac_mdio_if.h"
88ba7319e9SDmitry Salychev 
89ba7319e9SDmitry Salychev #include "dpaa2_types.h"
90ba7319e9SDmitry Salychev #include "dpaa2_mc.h"
91ba7319e9SDmitry Salychev #include "dpaa2_mc_if.h"
92ba7319e9SDmitry Salychev #include "dpaa2_mcp.h"
93ba7319e9SDmitry Salychev #include "dpaa2_swp.h"
94ba7319e9SDmitry Salychev #include "dpaa2_swp_if.h"
95ba7319e9SDmitry Salychev #include "dpaa2_cmd_if.h"
96ba7319e9SDmitry Salychev #include "dpaa2_ni.h"
9758983e4bSDmitry Salychev #include "dpaa2_channel.h"
9858983e4bSDmitry Salychev #include "dpaa2_buf.h"
99ba7319e9SDmitry Salychev 
100ba7319e9SDmitry Salychev #define BIT(x)			(1ul << (x))
101ba7319e9SDmitry Salychev #define WRIOP_VERSION(x, y, z)	((x) << 10 | (y) << 5 | (z) << 0)
102ba7319e9SDmitry Salychev #define ARRAY_SIZE(a)		(sizeof(a) / sizeof((a)[0]))
103ba7319e9SDmitry Salychev 
104ba7319e9SDmitry Salychev /* Frame Dequeue Response status bits. */
105ba7319e9SDmitry Salychev #define IS_NULL_RESPONSE(stat)	((((stat) >> 4) & 1) == 0)
106ba7319e9SDmitry Salychev 
107ba7319e9SDmitry Salychev #define	ALIGN_UP(x, y)		roundup2((x), (y))
108ba7319e9SDmitry Salychev #define	ALIGN_DOWN(x, y)	rounddown2((x), (y))
109ba7319e9SDmitry Salychev #define CACHE_LINE_ALIGN(x)	ALIGN_UP((x), CACHE_LINE_SIZE)
110ba7319e9SDmitry Salychev 
111ba7319e9SDmitry Salychev #define DPNI_LOCK(__sc) do {			\
112ba7319e9SDmitry Salychev 	mtx_assert(&(__sc)->lock, MA_NOTOWNED);	\
113ba7319e9SDmitry Salychev 	mtx_lock(&(__sc)->lock);		\
114ba7319e9SDmitry Salychev } while (0)
115ba7319e9SDmitry Salychev #define	DPNI_UNLOCK(__sc) do {			\
116ba7319e9SDmitry Salychev 	mtx_assert(&(__sc)->lock, MA_OWNED);	\
117ba7319e9SDmitry Salychev 	mtx_unlock(&(__sc)->lock);		\
118ba7319e9SDmitry Salychev } while (0)
119964b3408SBjoern A. Zeeb #define	DPNI_LOCK_ASSERT(__sc) do {		\
120964b3408SBjoern A. Zeeb 	mtx_assert(&(__sc)->lock, MA_OWNED);	\
121964b3408SBjoern A. Zeeb } while (0)
122ba7319e9SDmitry Salychev 
123ba7319e9SDmitry Salychev #define DPAA2_TX_RING(sc, chan, tc) \
124ba7319e9SDmitry Salychev 	(&(sc)->channels[(chan)]->txc_queue.tx_rings[(tc)])
125ba7319e9SDmitry Salychev 
12658983e4bSDmitry Salychev MALLOC_DEFINE(M_DPAA2_TXB, "dpaa2_txb", "DPAA2 DMA-mapped buffer (Tx)");
12758983e4bSDmitry Salychev 
12858983e4bSDmitry Salychev /*
12958983e4bSDmitry Salychev  * How many times channel cleanup routine will be repeated if the RX or TX
13058983e4bSDmitry Salychev  * budget was depleted.
13158983e4bSDmitry Salychev  */
13258983e4bSDmitry Salychev #define DPAA2_CLEAN_BUDGET	64 /* sysctl(9)? */
13358983e4bSDmitry Salychev /* TX/RX budget for the channel cleanup task */
13458983e4bSDmitry Salychev #define DPAA2_TX_BUDGET		128 /* sysctl(9)? */
13558983e4bSDmitry Salychev #define DPAA2_RX_BUDGET		256 /* sysctl(9)? */
13658983e4bSDmitry Salychev 
137ba7319e9SDmitry Salychev #define DPNI_IRQ_INDEX		0 /* Index of the only DPNI IRQ. */
138ba7319e9SDmitry Salychev #define DPNI_IRQ_LINK_CHANGED	1 /* Link state changed */
139ba7319e9SDmitry Salychev #define DPNI_IRQ_EP_CHANGED	2 /* DPAA2 endpoint dis/connected */
140ba7319e9SDmitry Salychev 
141fa3dfeffSBjoern A. Zeeb /* Default maximum RX frame length w/o CRC. */
142fa3dfeffSBjoern A. Zeeb #define	DPAA2_ETH_MFL		(ETHER_MAX_LEN_JUMBO + ETHER_VLAN_ENCAP_LEN - \
143fa3dfeffSBjoern A. Zeeb     ETHER_CRC_LEN)
144ba7319e9SDmitry Salychev 
145ba7319e9SDmitry Salychev /* Minimally supported version of the DPNI API. */
146ba7319e9SDmitry Salychev #define DPNI_VER_MAJOR		7
147ba7319e9SDmitry Salychev #define DPNI_VER_MINOR		0
148ba7319e9SDmitry Salychev 
149ba7319e9SDmitry Salychev /* Rx/Tx buffers configuration. */
150ba7319e9SDmitry Salychev #define BUF_ALIGN_V1		256 /* WRIOP v1.0.0 limitation */
151ba7319e9SDmitry Salychev #define BUF_ALIGN		64
152ba7319e9SDmitry Salychev #define BUF_SWA_SIZE		64  /* SW annotation size */
153ba7319e9SDmitry Salychev #define BUF_RX_HWA_SIZE		64  /* HW annotation size */
154ba7319e9SDmitry Salychev #define BUF_TX_HWA_SIZE		128 /* HW annotation size */
155ba7319e9SDmitry Salychev 
15658983e4bSDmitry Salychev #define DPAA2_RX_BUFRING_SZ	(4096u)
15758983e4bSDmitry Salychev #define DPAA2_RXE_BUFRING_SZ	(1024u)
15858983e4bSDmitry Salychev #define DPAA2_TXC_BUFRING_SZ	(4096u)
159ba7319e9SDmitry Salychev #define DPAA2_TX_SEGLIMIT	(16u) /* arbitrary number */
16058983e4bSDmitry Salychev #define DPAA2_TX_SEG_SZ		(PAGE_SIZE)
161ba7319e9SDmitry Salychev #define DPAA2_TX_SEGS_MAXSZ	(DPAA2_TX_SEGLIMIT * DPAA2_TX_SEG_SZ)
162718bdb6aSDmitry Salychev #define DPAA2_TX_SGT_SZ		(PAGE_SIZE) /* bytes */
163ba7319e9SDmitry Salychev 
164ba7319e9SDmitry Salychev /* Size of a buffer to keep a QoS table key configuration. */
16558983e4bSDmitry Salychev #define ETH_QOS_KCFG_BUF_SIZE	(PAGE_SIZE)
166ba7319e9SDmitry Salychev 
167ba7319e9SDmitry Salychev /* Required by struct dpni_rx_tc_dist_cfg::key_cfg_iova */
16858983e4bSDmitry Salychev #define DPAA2_CLASSIFIER_DMA_SIZE (PAGE_SIZE)
169ba7319e9SDmitry Salychev 
170ba7319e9SDmitry Salychev /* Buffers layout options. */
171ba7319e9SDmitry Salychev #define BUF_LOPT_TIMESTAMP	0x1
172ba7319e9SDmitry Salychev #define BUF_LOPT_PARSER_RESULT	0x2
173ba7319e9SDmitry Salychev #define BUF_LOPT_FRAME_STATUS	0x4
174ba7319e9SDmitry Salychev #define BUF_LOPT_PRIV_DATA_SZ	0x8
175ba7319e9SDmitry Salychev #define BUF_LOPT_DATA_ALIGN	0x10
176ba7319e9SDmitry Salychev #define BUF_LOPT_DATA_HEAD_ROOM	0x20
177ba7319e9SDmitry Salychev #define BUF_LOPT_DATA_TAIL_ROOM	0x40
178ba7319e9SDmitry Salychev 
179ba7319e9SDmitry Salychev #define DPAA2_NI_BUF_ADDR_MASK	(0x1FFFFFFFFFFFFul) /* 49-bit addresses max. */
180ba7319e9SDmitry Salychev #define DPAA2_NI_BUF_CHAN_MASK	(0xFu)
181ba7319e9SDmitry Salychev #define DPAA2_NI_BUF_CHAN_SHIFT	(60)
182ba7319e9SDmitry Salychev #define DPAA2_NI_BUF_IDX_MASK	(0x7FFFu)
183ba7319e9SDmitry Salychev #define DPAA2_NI_BUF_IDX_SHIFT	(49)
184ba7319e9SDmitry Salychev #define DPAA2_NI_TX_IDX_MASK	(0x7u)
185ba7319e9SDmitry Salychev #define DPAA2_NI_TX_IDX_SHIFT	(57)
186ba7319e9SDmitry Salychev #define DPAA2_NI_TXBUF_IDX_MASK	(0xFFu)
187ba7319e9SDmitry Salychev #define DPAA2_NI_TXBUF_IDX_SHIFT (49)
188ba7319e9SDmitry Salychev 
189ba7319e9SDmitry Salychev #define DPAA2_NI_FD_FMT_MASK	(0x3u)
190ba7319e9SDmitry Salychev #define DPAA2_NI_FD_FMT_SHIFT	(12)
191ba7319e9SDmitry Salychev #define DPAA2_NI_FD_ERR_MASK	(0xFFu)
192ba7319e9SDmitry Salychev #define DPAA2_NI_FD_ERR_SHIFT	(0)
193ba7319e9SDmitry Salychev #define DPAA2_NI_FD_SL_MASK	(0x1u)
194ba7319e9SDmitry Salychev #define DPAA2_NI_FD_SL_SHIFT	(14)
195ba7319e9SDmitry Salychev #define DPAA2_NI_FD_LEN_MASK	(0x3FFFFu)
196ba7319e9SDmitry Salychev #define DPAA2_NI_FD_OFFSET_MASK (0x0FFFu)
197ba7319e9SDmitry Salychev 
198ba7319e9SDmitry Salychev /* Enables TCAM for Flow Steering and QoS look-ups. */
199ba7319e9SDmitry Salychev #define DPNI_OPT_HAS_KEY_MASKING 0x10
200ba7319e9SDmitry Salychev 
201ba7319e9SDmitry Salychev /* Unique IDs for the supported Rx classification header fields. */
202ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_ETHDST	BIT(0)
203ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_ETHSRC	BIT(1)
204ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_ETHTYPE	BIT(2)
205ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_VLAN	BIT(3)
206ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_IPSRC	BIT(4)
207ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_IPDST	BIT(5)
208ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_IPPROTO	BIT(6)
209ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_L4SRC	BIT(7)
210ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_L4DST	BIT(8)
211ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_ALL	(~0ULL)
212ba7319e9SDmitry Salychev 
213ba7319e9SDmitry Salychev /* L3-L4 network traffic flow hash options. */
214ba7319e9SDmitry Salychev #define	RXH_L2DA		(1 << 1)
215ba7319e9SDmitry Salychev #define	RXH_VLAN		(1 << 2)
216ba7319e9SDmitry Salychev #define	RXH_L3_PROTO		(1 << 3)
217ba7319e9SDmitry Salychev #define	RXH_IP_SRC		(1 << 4)
218ba7319e9SDmitry Salychev #define	RXH_IP_DST		(1 << 5)
219ba7319e9SDmitry Salychev #define	RXH_L4_B_0_1		(1 << 6) /* src port in case of TCP/UDP/SCTP */
220ba7319e9SDmitry Salychev #define	RXH_L4_B_2_3		(1 << 7) /* dst port in case of TCP/UDP/SCTP */
221ba7319e9SDmitry Salychev #define	RXH_DISCARD		(1 << 31)
222ba7319e9SDmitry Salychev 
223ba7319e9SDmitry Salychev /* Default Rx hash options, set during attaching. */
224ba7319e9SDmitry Salychev #define DPAA2_RXH_DEFAULT	(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)
225ba7319e9SDmitry Salychev 
226ba7319e9SDmitry Salychev MALLOC_DEFINE(M_DPAA2_NI, "dpaa2_ni", "DPAA2 Network Interface");
227ba7319e9SDmitry Salychev 
22858983e4bSDmitry Salychev /*
22958983e4bSDmitry Salychev  * DPAA2 Network Interface resource specification.
23058983e4bSDmitry Salychev  *
23158983e4bSDmitry Salychev  * NOTE: Don't forget to update macros in dpaa2_ni.h in case of any changes in
23258983e4bSDmitry Salychev  *       the specification!
23358983e4bSDmitry Salychev  */
234ba7319e9SDmitry Salychev struct resource_spec dpaa2_ni_spec[] = {
235ba7319e9SDmitry Salychev 	/*
236ba7319e9SDmitry Salychev 	 * DPMCP resources.
237ba7319e9SDmitry Salychev 	 *
238ba7319e9SDmitry Salychev 	 * NOTE: MC command portals (MCPs) are used to send commands to, and
239ba7319e9SDmitry Salychev 	 *	 receive responses from, the MC firmware. One portal per DPNI.
240ba7319e9SDmitry Salychev 	 */
24158983e4bSDmitry Salychev 	{ DPAA2_DEV_MCP, DPAA2_NI_MCP_RID(0),   RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
242ba7319e9SDmitry Salychev 	/*
243ba7319e9SDmitry Salychev 	 * DPIO resources (software portals).
244ba7319e9SDmitry Salychev 	 *
245ba7319e9SDmitry Salychev 	 * NOTE: One per running core. While DPIOs are the source of data
246ba7319e9SDmitry Salychev 	 *	 availability interrupts, the DPCONs are used to identify the
247ba7319e9SDmitry Salychev 	 *	 network interface that has produced ingress data to that core.
248ba7319e9SDmitry Salychev 	 */
24958983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(0),    RF_ACTIVE | RF_SHAREABLE },
25058983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(1),    RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
25158983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(2),    RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
25258983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(3),    RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
25358983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(4),    RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
25458983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(5),    RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
25558983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(6),    RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
25658983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(7),    RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
25758983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(8),    RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
25858983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(9),    RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
25958983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(10),   RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
26058983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(11),   RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
26158983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(12),   RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
26258983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(13),   RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
26358983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(14),   RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
26458983e4bSDmitry Salychev 	{ DPAA2_DEV_IO,  DPAA2_NI_IO_RID(15),   RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
265ba7319e9SDmitry Salychev 	/*
266ba7319e9SDmitry Salychev 	 * DPBP resources (buffer pools).
267ba7319e9SDmitry Salychev 	 *
268ba7319e9SDmitry Salychev 	 * NOTE: One per network interface.
269ba7319e9SDmitry Salychev 	 */
27058983e4bSDmitry Salychev 	{ DPAA2_DEV_BP,  DPAA2_NI_BP_RID(0),   RF_ACTIVE },
271ba7319e9SDmitry Salychev 	/*
272ba7319e9SDmitry Salychev 	 * DPCON resources (channels).
273ba7319e9SDmitry Salychev 	 *
274ba7319e9SDmitry Salychev 	 * NOTE: One DPCON per core where Rx or Tx confirmation traffic to be
275ba7319e9SDmitry Salychev 	 *	 distributed to.
276ba7319e9SDmitry Salychev 	 * NOTE: Since it is necessary to distinguish between traffic from
277ba7319e9SDmitry Salychev 	 *	 different network interfaces arriving on the same core, the
278ba7319e9SDmitry Salychev 	 *	 DPCONs must be private to the DPNIs.
279ba7319e9SDmitry Salychev 	 */
28058983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(0),   RF_ACTIVE },
28158983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(1),   RF_ACTIVE | RF_OPTIONAL },
28258983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(2),   RF_ACTIVE | RF_OPTIONAL },
28358983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(3),   RF_ACTIVE | RF_OPTIONAL },
28458983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(4),   RF_ACTIVE | RF_OPTIONAL },
28558983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(5),   RF_ACTIVE | RF_OPTIONAL },
28658983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(6),   RF_ACTIVE | RF_OPTIONAL },
28758983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(7),   RF_ACTIVE | RF_OPTIONAL },
28858983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(8),   RF_ACTIVE | RF_OPTIONAL },
28958983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(9),   RF_ACTIVE | RF_OPTIONAL },
29058983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(10),  RF_ACTIVE | RF_OPTIONAL },
29158983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(11),  RF_ACTIVE | RF_OPTIONAL },
29258983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(12),  RF_ACTIVE | RF_OPTIONAL },
29358983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(13),  RF_ACTIVE | RF_OPTIONAL },
29458983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(14),  RF_ACTIVE | RF_OPTIONAL },
29558983e4bSDmitry Salychev 	{ DPAA2_DEV_CON, DPAA2_NI_CON_RID(15),  RF_ACTIVE | RF_OPTIONAL },
29658983e4bSDmitry Salychev 
297ba7319e9SDmitry Salychev 	RESOURCE_SPEC_END
298ba7319e9SDmitry Salychev };
299ba7319e9SDmitry Salychev 
300ba7319e9SDmitry Salychev /* Supported header fields for Rx hash distribution key */
301ba7319e9SDmitry Salychev static const struct dpaa2_eth_dist_fields dist_fields[] = {
302ba7319e9SDmitry Salychev 	{
303ba7319e9SDmitry Salychev 		/* L2 header */
304ba7319e9SDmitry Salychev 		.rxnfc_field = RXH_L2DA,
305ba7319e9SDmitry Salychev 		.cls_prot = NET_PROT_ETH,
306ba7319e9SDmitry Salychev 		.cls_field = NH_FLD_ETH_DA,
307ba7319e9SDmitry Salychev 		.id = DPAA2_ETH_DIST_ETHDST,
308ba7319e9SDmitry Salychev 		.size = 6,
309ba7319e9SDmitry Salychev 	}, {
310ba7319e9SDmitry Salychev 		.cls_prot = NET_PROT_ETH,
311ba7319e9SDmitry Salychev 		.cls_field = NH_FLD_ETH_SA,
312ba7319e9SDmitry Salychev 		.id = DPAA2_ETH_DIST_ETHSRC,
313ba7319e9SDmitry Salychev 		.size = 6,
314ba7319e9SDmitry Salychev 	}, {
315ba7319e9SDmitry Salychev 		/* This is the last ethertype field parsed:
316ba7319e9SDmitry Salychev 		 * depending on frame format, it can be the MAC ethertype
317ba7319e9SDmitry Salychev 		 * or the VLAN etype.
318ba7319e9SDmitry Salychev 		 */
319ba7319e9SDmitry Salychev 		.cls_prot = NET_PROT_ETH,
320ba7319e9SDmitry Salychev 		.cls_field = NH_FLD_ETH_TYPE,
321ba7319e9SDmitry Salychev 		.id = DPAA2_ETH_DIST_ETHTYPE,
322ba7319e9SDmitry Salychev 		.size = 2,
323ba7319e9SDmitry Salychev 	}, {
324ba7319e9SDmitry Salychev 		/* VLAN header */
325ba7319e9SDmitry Salychev 		.rxnfc_field = RXH_VLAN,
326ba7319e9SDmitry Salychev 		.cls_prot = NET_PROT_VLAN,
327ba7319e9SDmitry Salychev 		.cls_field = NH_FLD_VLAN_TCI,
328ba7319e9SDmitry Salychev 		.id = DPAA2_ETH_DIST_VLAN,
329ba7319e9SDmitry Salychev 		.size = 2,
330ba7319e9SDmitry Salychev 	}, {
331ba7319e9SDmitry Salychev 		/* IP header */
332ba7319e9SDmitry Salychev 		.rxnfc_field = RXH_IP_SRC,
333ba7319e9SDmitry Salychev 		.cls_prot = NET_PROT_IP,
334ba7319e9SDmitry Salychev 		.cls_field = NH_FLD_IP_SRC,
335ba7319e9SDmitry Salychev 		.id = DPAA2_ETH_DIST_IPSRC,
336ba7319e9SDmitry Salychev 		.size = 4,
337ba7319e9SDmitry Salychev 	}, {
338ba7319e9SDmitry Salychev 		.rxnfc_field = RXH_IP_DST,
339ba7319e9SDmitry Salychev 		.cls_prot = NET_PROT_IP,
340ba7319e9SDmitry Salychev 		.cls_field = NH_FLD_IP_DST,
341ba7319e9SDmitry Salychev 		.id = DPAA2_ETH_DIST_IPDST,
342ba7319e9SDmitry Salychev 		.size = 4,
343ba7319e9SDmitry Salychev 	}, {
344ba7319e9SDmitry Salychev 		.rxnfc_field = RXH_L3_PROTO,
345ba7319e9SDmitry Salychev 		.cls_prot = NET_PROT_IP,
346ba7319e9SDmitry Salychev 		.cls_field = NH_FLD_IP_PROTO,
347ba7319e9SDmitry Salychev 		.id = DPAA2_ETH_DIST_IPPROTO,
348ba7319e9SDmitry Salychev 		.size = 1,
349ba7319e9SDmitry Salychev 	}, {
350ba7319e9SDmitry Salychev 		/* Using UDP ports, this is functionally equivalent to raw
351ba7319e9SDmitry Salychev 		 * byte pairs from L4 header.
352ba7319e9SDmitry Salychev 		 */
353ba7319e9SDmitry Salychev 		.rxnfc_field = RXH_L4_B_0_1,
354ba7319e9SDmitry Salychev 		.cls_prot = NET_PROT_UDP,
355ba7319e9SDmitry Salychev 		.cls_field = NH_FLD_UDP_PORT_SRC,
356ba7319e9SDmitry Salychev 		.id = DPAA2_ETH_DIST_L4SRC,
357ba7319e9SDmitry Salychev 		.size = 2,
358ba7319e9SDmitry Salychev 	}, {
359ba7319e9SDmitry Salychev 		.rxnfc_field = RXH_L4_B_2_3,
360ba7319e9SDmitry Salychev 		.cls_prot = NET_PROT_UDP,
361ba7319e9SDmitry Salychev 		.cls_field = NH_FLD_UDP_PORT_DST,
362ba7319e9SDmitry Salychev 		.id = DPAA2_ETH_DIST_L4DST,
363ba7319e9SDmitry Salychev 		.size = 2,
364ba7319e9SDmitry Salychev 	},
365ba7319e9SDmitry Salychev };
366ba7319e9SDmitry Salychev 
367ba7319e9SDmitry Salychev static struct dpni_stat {
368ba7319e9SDmitry Salychev 	int	 page;
369ba7319e9SDmitry Salychev 	int	 cnt;
370ba7319e9SDmitry Salychev 	char	*name;
371ba7319e9SDmitry Salychev 	char	*desc;
372ba7319e9SDmitry Salychev } dpni_stat_sysctls[DPAA2_NI_STAT_SYSCTLS] = {
373ba7319e9SDmitry Salychev 	/* PAGE, COUNTER, NAME, DESCRIPTION */
374ba7319e9SDmitry Salychev 	{  0, 0, "in_all_frames",	"All accepted ingress frames" },
375ba7319e9SDmitry Salychev 	{  0, 1, "in_all_bytes",	"Bytes in all accepted ingress frames" },
376ba7319e9SDmitry Salychev 	{  0, 2, "in_multi_frames",	"Multicast accepted ingress frames" },
377ba7319e9SDmitry Salychev 	{  1, 0, "eg_all_frames",	"All egress frames transmitted" },
378ba7319e9SDmitry Salychev 	{  1, 1, "eg_all_bytes",	"Bytes in all frames transmitted" },
379ba7319e9SDmitry Salychev 	{  1, 2, "eg_multi_frames",	"Multicast egress frames transmitted" },
380ba7319e9SDmitry Salychev 	{  2, 0, "in_filtered_frames",	"All ingress frames discarded due to "
381ba7319e9SDmitry Salychev 	   				"filtering" },
382ba7319e9SDmitry Salychev 	{  2, 1, "in_discarded_frames",	"All frames discarded due to errors" },
383ba7319e9SDmitry Salychev 	{  2, 2, "in_nobuf_discards",	"Discards on ingress side due to buffer "
384ba7319e9SDmitry Salychev 	   				"depletion in DPNI buffer pools" },
385ba7319e9SDmitry Salychev };
386ba7319e9SDmitry Salychev 
38758983e4bSDmitry Salychev struct dpaa2_ni_rx_ctx {
38858983e4bSDmitry Salychev 	struct mbuf	*head;
38958983e4bSDmitry Salychev 	struct mbuf	*tail;
39058983e4bSDmitry Salychev 	int		 cnt;
39158983e4bSDmitry Salychev 	bool		 last;
39258983e4bSDmitry Salychev };
39358983e4bSDmitry Salychev 
394ba7319e9SDmitry Salychev /* Device interface */
395ba7319e9SDmitry Salychev static int dpaa2_ni_probe(device_t);
396ba7319e9SDmitry Salychev static int dpaa2_ni_attach(device_t);
397ba7319e9SDmitry Salychev static int dpaa2_ni_detach(device_t);
398ba7319e9SDmitry Salychev 
399ba7319e9SDmitry Salychev /* DPAA2 network interface setup and configuration */
400ba7319e9SDmitry Salychev static int dpaa2_ni_setup(device_t);
401ba7319e9SDmitry Salychev static int dpaa2_ni_setup_channels(device_t);
402ba7319e9SDmitry Salychev static int dpaa2_ni_bind(device_t);
403ba7319e9SDmitry Salychev static int dpaa2_ni_setup_rx_dist(device_t);
404ba7319e9SDmitry Salychev static int dpaa2_ni_setup_irqs(device_t);
405ba7319e9SDmitry Salychev static int dpaa2_ni_setup_msi(struct dpaa2_ni_softc *);
406ba7319e9SDmitry Salychev static int dpaa2_ni_setup_if_caps(struct dpaa2_ni_softc *);
407ba7319e9SDmitry Salychev static int dpaa2_ni_setup_if_flags(struct dpaa2_ni_softc *);
408ba7319e9SDmitry Salychev static int dpaa2_ni_setup_sysctls(struct dpaa2_ni_softc *);
409ba7319e9SDmitry Salychev static int dpaa2_ni_setup_dma(struct dpaa2_ni_softc *);
410ba7319e9SDmitry Salychev 
411ba7319e9SDmitry Salychev /* Tx/Rx flow configuration */
4124cd96614SDmitry Salychev static int dpaa2_ni_setup_rx_flow(device_t, struct dpaa2_ni_fq *);
4134cd96614SDmitry Salychev static int dpaa2_ni_setup_tx_flow(device_t, struct dpaa2_ni_fq *);
4144cd96614SDmitry Salychev static int dpaa2_ni_setup_rx_err_flow(device_t, struct dpaa2_ni_fq *);
415ba7319e9SDmitry Salychev 
416ba7319e9SDmitry Salychev /* Configuration subroutines */
4174cd96614SDmitry Salychev static int dpaa2_ni_set_buf_layout(device_t);
4184cd96614SDmitry Salychev static int dpaa2_ni_set_pause_frame(device_t);
4194cd96614SDmitry Salychev static int dpaa2_ni_set_qos_table(device_t);
4204cd96614SDmitry Salychev static int dpaa2_ni_set_mac_addr(device_t);
421ba7319e9SDmitry Salychev static int dpaa2_ni_set_hash(device_t, uint64_t);
422ba7319e9SDmitry Salychev static int dpaa2_ni_set_dist_key(device_t, enum dpaa2_ni_dist_mode, uint64_t);
423ba7319e9SDmitry Salychev 
424ba7319e9SDmitry Salychev /* Frame descriptor routines */
425ba7319e9SDmitry Salychev static int dpaa2_ni_build_fd(struct dpaa2_ni_softc *, struct dpaa2_ni_tx_ring *,
426ba7319e9SDmitry Salychev     struct dpaa2_buf *, bus_dma_segment_t *, int, struct dpaa2_fd *);
427ba7319e9SDmitry Salychev static int dpaa2_ni_fd_err(struct dpaa2_fd *);
428ba7319e9SDmitry Salychev static uint32_t dpaa2_ni_fd_data_len(struct dpaa2_fd *);
429ba7319e9SDmitry Salychev static int dpaa2_ni_fd_format(struct dpaa2_fd *);
430ba7319e9SDmitry Salychev static bool dpaa2_ni_fd_short_len(struct dpaa2_fd *);
431ba7319e9SDmitry Salychev static int dpaa2_ni_fd_offset(struct dpaa2_fd *);
432ba7319e9SDmitry Salychev 
433ba7319e9SDmitry Salychev /* Various subroutines */
434ba7319e9SDmitry Salychev static int dpaa2_ni_cmp_api_version(struct dpaa2_ni_softc *, uint16_t, uint16_t);
435ba7319e9SDmitry Salychev static int dpaa2_ni_prepare_key_cfg(struct dpkg_profile_cfg *, uint8_t *);
436ba7319e9SDmitry Salychev 
437ba7319e9SDmitry Salychev /* Network interface routines */
438ba7319e9SDmitry Salychev static void dpaa2_ni_init(void *);
439d936c29eSJustin Hibbits static int  dpaa2_ni_transmit(if_t , struct mbuf *);
440d936c29eSJustin Hibbits static void dpaa2_ni_qflush(if_t );
441d936c29eSJustin Hibbits static int  dpaa2_ni_ioctl(if_t , u_long, caddr_t);
442d936c29eSJustin Hibbits static int  dpaa2_ni_update_mac_filters(if_t );
443ba7319e9SDmitry Salychev static u_int dpaa2_ni_add_maddr(void *, struct sockaddr_dl *, u_int);
444ba7319e9SDmitry Salychev 
445ba7319e9SDmitry Salychev /* Interrupt handlers */
446ba7319e9SDmitry Salychev static void dpaa2_ni_intr(void *);
447ba7319e9SDmitry Salychev 
448ba7319e9SDmitry Salychev /* MII handlers */
449ba7319e9SDmitry Salychev static void dpaa2_ni_miibus_statchg(device_t);
450d936c29eSJustin Hibbits static int  dpaa2_ni_media_change(if_t );
451d936c29eSJustin Hibbits static void dpaa2_ni_media_status(if_t , struct ifmediareq *);
452ba7319e9SDmitry Salychev static void dpaa2_ni_media_tick(void *);
453ba7319e9SDmitry Salychev 
454ba7319e9SDmitry Salychev /* Tx/Rx routines. */
45558983e4bSDmitry Salychev static int dpaa2_ni_rx_cleanup(struct dpaa2_channel *);
45658983e4bSDmitry Salychev static int dpaa2_ni_tx_cleanup(struct dpaa2_channel *);
45758983e4bSDmitry Salychev static void dpaa2_ni_tx(struct dpaa2_ni_softc *, struct dpaa2_channel *,
458ba7319e9SDmitry Salychev     struct dpaa2_ni_tx_ring *, struct mbuf *);
45958983e4bSDmitry Salychev static void dpaa2_ni_cleanup_task(void *, int);
460ba7319e9SDmitry Salychev 
461ba7319e9SDmitry Salychev /* Tx/Rx subroutines */
46258983e4bSDmitry Salychev static int dpaa2_ni_consume_frames(struct dpaa2_channel *, struct dpaa2_ni_fq **,
46358983e4bSDmitry Salychev     uint32_t *);
46458983e4bSDmitry Salychev static int dpaa2_ni_rx(struct dpaa2_channel *, struct dpaa2_ni_fq *,
46558983e4bSDmitry Salychev     struct dpaa2_fd *, struct dpaa2_ni_rx_ctx *);
46658983e4bSDmitry Salychev static int dpaa2_ni_rx_err(struct dpaa2_channel *, struct dpaa2_ni_fq *,
467ba7319e9SDmitry Salychev     struct dpaa2_fd *);
46858983e4bSDmitry Salychev static int dpaa2_ni_tx_conf(struct dpaa2_channel *, struct dpaa2_ni_fq *,
469ba7319e9SDmitry Salychev     struct dpaa2_fd *);
470ba7319e9SDmitry Salychev 
471ba7319e9SDmitry Salychev /* sysctl(9) */
472ba7319e9SDmitry Salychev static int dpaa2_ni_collect_stats(SYSCTL_HANDLER_ARGS);
473ba7319e9SDmitry Salychev static int dpaa2_ni_collect_buf_num(SYSCTL_HANDLER_ARGS);
474ba7319e9SDmitry Salychev static int dpaa2_ni_collect_buf_free(SYSCTL_HANDLER_ARGS);
475ba7319e9SDmitry Salychev 
476ba7319e9SDmitry Salychev static int
477ba7319e9SDmitry Salychev dpaa2_ni_probe(device_t dev)
478ba7319e9SDmitry Salychev {
479ba7319e9SDmitry Salychev 	/* DPNI device will be added by a parent resource container itself. */
480ba7319e9SDmitry Salychev 	device_set_desc(dev, "DPAA2 Network Interface");
481ba7319e9SDmitry Salychev 	return (BUS_PROBE_DEFAULT);
482ba7319e9SDmitry Salychev }
483ba7319e9SDmitry Salychev 
484ba7319e9SDmitry Salychev static int
485ba7319e9SDmitry Salychev dpaa2_ni_attach(device_t dev)
486ba7319e9SDmitry Salychev {
487ba7319e9SDmitry Salychev 	device_t pdev = device_get_parent(dev);
488ba7319e9SDmitry Salychev 	device_t child = dev;
489ba7319e9SDmitry Salychev 	device_t mcp_dev;
490ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
491ba7319e9SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
492ba7319e9SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
493ba7319e9SDmitry Salychev 	struct dpaa2_devinfo *mcp_dinfo;
4944cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
4954cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
496d936c29eSJustin Hibbits 	if_t ifp;
497ba7319e9SDmitry Salychev 	char tq_name[32];
498ba7319e9SDmitry Salychev 	int error;
499ba7319e9SDmitry Salychev 
500ba7319e9SDmitry Salychev 	sc->dev = dev;
501ba7319e9SDmitry Salychev 	sc->ifp = NULL;
502ba7319e9SDmitry Salychev 	sc->miibus = NULL;
503ba7319e9SDmitry Salychev 	sc->mii = NULL;
504ba7319e9SDmitry Salychev 	sc->media_status = 0;
505ba7319e9SDmitry Salychev 	sc->if_flags = 0;
506ba7319e9SDmitry Salychev 	sc->link_state = LINK_STATE_UNKNOWN;
507ba7319e9SDmitry Salychev 	sc->buf_align = 0;
508ba7319e9SDmitry Salychev 
509ba7319e9SDmitry Salychev 	/* For debug purposes only! */
510ba7319e9SDmitry Salychev 	sc->rx_anomaly_frames = 0;
511ba7319e9SDmitry Salychev 	sc->rx_single_buf_frames = 0;
512ba7319e9SDmitry Salychev 	sc->rx_sg_buf_frames = 0;
513ba7319e9SDmitry Salychev 	sc->rx_enq_rej_frames = 0;
514ba7319e9SDmitry Salychev 	sc->rx_ieoi_err_frames = 0;
515ba7319e9SDmitry Salychev 	sc->tx_single_buf_frames = 0;
516ba7319e9SDmitry Salychev 	sc->tx_sg_frames = 0;
517ba7319e9SDmitry Salychev 
518ba7319e9SDmitry Salychev 	DPAA2_ATOMIC_XCHG(&sc->buf_num, 0);
519ba7319e9SDmitry Salychev 	DPAA2_ATOMIC_XCHG(&sc->buf_free, 0);
520ba7319e9SDmitry Salychev 
521ba7319e9SDmitry Salychev 	sc->rxd_dmat = NULL;
522ba7319e9SDmitry Salychev 	sc->qos_dmat = NULL;
523ba7319e9SDmitry Salychev 
52458983e4bSDmitry Salychev 	sc->qos_kcfg.dmap = NULL;
52558983e4bSDmitry Salychev 	sc->qos_kcfg.paddr = 0;
52658983e4bSDmitry Salychev 	sc->qos_kcfg.vaddr = NULL;
527ba7319e9SDmitry Salychev 
52858983e4bSDmitry Salychev 	sc->rxd_kcfg.dmap = NULL;
52958983e4bSDmitry Salychev 	sc->rxd_kcfg.paddr = 0;
53058983e4bSDmitry Salychev 	sc->rxd_kcfg.vaddr = NULL;
531ba7319e9SDmitry Salychev 
532ba7319e9SDmitry Salychev 	sc->mac.dpmac_id = 0;
533ba7319e9SDmitry Salychev 	sc->mac.phy_dev = NULL;
534ba7319e9SDmitry Salychev 	memset(sc->mac.addr, 0, ETHER_ADDR_LEN);
535ba7319e9SDmitry Salychev 
536ba7319e9SDmitry Salychev 	error = bus_alloc_resources(sc->dev, dpaa2_ni_spec, sc->res);
537ba7319e9SDmitry Salychev 	if (error) {
538ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to allocate resources: "
539ba7319e9SDmitry Salychev 		    "error=%d\n", __func__, error);
5404cd96614SDmitry Salychev 		goto err_exit;
541ba7319e9SDmitry Salychev 	}
542ba7319e9SDmitry Salychev 
543ba7319e9SDmitry Salychev 	/* Obtain MC portal. */
54458983e4bSDmitry Salychev 	mcp_dev = (device_t) rman_get_start(sc->res[DPAA2_NI_MCP_RID(0)]);
545ba7319e9SDmitry Salychev 	mcp_dinfo = device_get_ivars(mcp_dev);
546ba7319e9SDmitry Salychev 	dinfo->portal = mcp_dinfo->portal;
547ba7319e9SDmitry Salychev 
548ba7319e9SDmitry Salychev 	mtx_init(&sc->lock, device_get_nameunit(dev), "dpaa2_ni", MTX_DEF);
549ba7319e9SDmitry Salychev 
550ba7319e9SDmitry Salychev 	/* Allocate network interface */
551ba7319e9SDmitry Salychev 	ifp = if_alloc(IFT_ETHER);
552ba7319e9SDmitry Salychev 	sc->ifp = ifp;
553ba7319e9SDmitry Salychev 	if_initname(ifp, DPAA2_NI_IFNAME, device_get_unit(sc->dev));
554ba7319e9SDmitry Salychev 
555d936c29eSJustin Hibbits 	if_setsoftc(ifp, sc);
556d936c29eSJustin Hibbits 	if_setflags(ifp, IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST);
557d936c29eSJustin Hibbits 	if_setinitfn(ifp, dpaa2_ni_init);
558d936c29eSJustin Hibbits 	if_setioctlfn(ifp, dpaa2_ni_ioctl);
559d936c29eSJustin Hibbits 	if_settransmitfn(ifp, dpaa2_ni_transmit);
560d936c29eSJustin Hibbits 	if_setqflushfn(ifp, dpaa2_ni_qflush);
561ba7319e9SDmitry Salychev 
562d936c29eSJustin Hibbits 	if_setcapabilities(ifp, IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU);
563d936c29eSJustin Hibbits 	if_setcapenable(ifp, if_getcapabilities(ifp));
564ba7319e9SDmitry Salychev 
5654cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
566ba7319e9SDmitry Salychev 
567ba7319e9SDmitry Salychev 	/* Open resource container and network interface object. */
5684cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
569ba7319e9SDmitry Salychev 	if (error) {
570ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
571ba7319e9SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
5724cd96614SDmitry Salychev 		goto err_exit;
573ba7319e9SDmitry Salychev 	}
5744cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
575ba7319e9SDmitry Salychev 	if (error) {
576ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
577ba7319e9SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
5784cd96614SDmitry Salychev 		goto close_rc;
579ba7319e9SDmitry Salychev 	}
580ba7319e9SDmitry Salychev 
58158983e4bSDmitry Salychev 	bzero(tq_name, sizeof(tq_name));
58258983e4bSDmitry Salychev 	snprintf(tq_name, sizeof(tq_name), "%s_tqbp", device_get_nameunit(dev));
58358983e4bSDmitry Salychev 
5844cd96614SDmitry Salychev 	/*
5854cd96614SDmitry Salychev 	 * XXX-DSL: Release new buffers on Buffer Pool State Change Notification
5864cd96614SDmitry Salychev 	 *          (BPSCN) returned as a result to the VDQ command instead.
5874cd96614SDmitry Salychev 	 *          It is similar to CDAN processed in dpaa2_io_intr().
5884cd96614SDmitry Salychev 	 */
589ba7319e9SDmitry Salychev 	/* Create a taskqueue thread to release new buffers to the pool. */
590ba7319e9SDmitry Salychev 	sc->bp_taskq = taskqueue_create(tq_name, M_WAITOK,
591ba7319e9SDmitry Salychev 	    taskqueue_thread_enqueue, &sc->bp_taskq);
592ba7319e9SDmitry Salychev 	taskqueue_start_threads(&sc->bp_taskq, 1, PI_NET, "%s", tq_name);
593ba7319e9SDmitry Salychev 
59458983e4bSDmitry Salychev 	/* sc->cleanup_taskq = taskqueue_create("dpaa2_ch cleanup", M_WAITOK, */
59558983e4bSDmitry Salychev 	/*     taskqueue_thread_enqueue, &sc->cleanup_taskq); */
59658983e4bSDmitry Salychev 	/* taskqueue_start_threads(&sc->cleanup_taskq, 1, PI_NET, */
59758983e4bSDmitry Salychev 	/*     "dpaa2_ch cleanup"); */
59858983e4bSDmitry Salychev 
599ba7319e9SDmitry Salychev 	error = dpaa2_ni_setup(dev);
600ba7319e9SDmitry Salychev 	if (error) {
601ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to setup DPNI: error=%d\n",
602ba7319e9SDmitry Salychev 		    __func__, error);
6034cd96614SDmitry Salychev 		goto close_ni;
604ba7319e9SDmitry Salychev 	}
605ba7319e9SDmitry Salychev 	error = dpaa2_ni_setup_channels(dev);
606ba7319e9SDmitry Salychev 	if (error) {
607ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to setup QBMan channels: "
608ba7319e9SDmitry Salychev 		    "error=%d\n", __func__, error);
6094cd96614SDmitry Salychev 		goto close_ni;
610ba7319e9SDmitry Salychev 	}
611ba7319e9SDmitry Salychev 
612ba7319e9SDmitry Salychev 	error = dpaa2_ni_bind(dev);
613ba7319e9SDmitry Salychev 	if (error) {
614ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to bind DPNI: error=%d\n",
615ba7319e9SDmitry Salychev 		    __func__, error);
6164cd96614SDmitry Salychev 		goto close_ni;
617ba7319e9SDmitry Salychev 	}
618ba7319e9SDmitry Salychev 	error = dpaa2_ni_setup_irqs(dev);
619ba7319e9SDmitry Salychev 	if (error) {
620ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to setup IRQs: error=%d\n",
621ba7319e9SDmitry Salychev 		    __func__, error);
6224cd96614SDmitry Salychev 		goto close_ni;
623ba7319e9SDmitry Salychev 	}
624ba7319e9SDmitry Salychev 	error = dpaa2_ni_setup_sysctls(sc);
625ba7319e9SDmitry Salychev 	if (error) {
626ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to setup sysctls: error=%d\n",
627ba7319e9SDmitry Salychev 		    __func__, error);
6284cd96614SDmitry Salychev 		goto close_ni;
629ba7319e9SDmitry Salychev 	}
630ba7319e9SDmitry Salychev 
631ba7319e9SDmitry Salychev 	ether_ifattach(sc->ifp, sc->mac.addr);
632ba7319e9SDmitry Salychev 	callout_init(&sc->mii_callout, 0);
633ba7319e9SDmitry Salychev 
634ba7319e9SDmitry Salychev 	return (0);
635ba7319e9SDmitry Salychev 
6364cd96614SDmitry Salychev close_ni:
6374cd96614SDmitry Salychev 	DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
6384cd96614SDmitry Salychev close_rc:
6394cd96614SDmitry Salychev 	DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
640ba7319e9SDmitry Salychev err_exit:
641ba7319e9SDmitry Salychev 	return (ENXIO);
642ba7319e9SDmitry Salychev }
643ba7319e9SDmitry Salychev 
644ba7319e9SDmitry Salychev static void
645ba7319e9SDmitry Salychev dpaa2_ni_fixed_media_status(if_t ifp, struct ifmediareq* ifmr)
646ba7319e9SDmitry Salychev {
647d936c29eSJustin Hibbits 	struct dpaa2_ni_softc *sc = if_getsoftc(ifp);
648ba7319e9SDmitry Salychev 
649ba7319e9SDmitry Salychev 	DPNI_LOCK(sc);
650ba7319e9SDmitry Salychev 	ifmr->ifm_count = 0;
651ba7319e9SDmitry Salychev 	ifmr->ifm_mask = 0;
652ba7319e9SDmitry Salychev 	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
653ba7319e9SDmitry Salychev 	ifmr->ifm_current = ifmr->ifm_active =
654ba7319e9SDmitry Salychev 	    sc->fixed_ifmedia.ifm_cur->ifm_media;
655ba7319e9SDmitry Salychev 
656ba7319e9SDmitry Salychev 	/*
657ba7319e9SDmitry Salychev 	 * In non-PHY usecases, we need to signal link state up, otherwise
658ba7319e9SDmitry Salychev 	 * certain things requiring a link event (e.g async DHCP client) from
659ba7319e9SDmitry Salychev 	 * devd do not happen.
660ba7319e9SDmitry Salychev 	 */
661d936c29eSJustin Hibbits 	if (if_getlinkstate(ifp) == LINK_STATE_UNKNOWN) {
662ba7319e9SDmitry Salychev 		if_link_state_change(ifp, LINK_STATE_UP);
663ba7319e9SDmitry Salychev 	}
664ba7319e9SDmitry Salychev 
665ba7319e9SDmitry Salychev 	/*
666ba7319e9SDmitry Salychev 	 * TODO: Check the status of the link partner (DPMAC, DPNI or other) and
667ba7319e9SDmitry Salychev 	 * reset if down. This is different to the DPAA2_MAC_LINK_TYPE_PHY as
668ba7319e9SDmitry Salychev 	 * the MC firmware sets the status, instead of us telling the MC what
669ba7319e9SDmitry Salychev 	 * it is.
670ba7319e9SDmitry Salychev 	 */
671ba7319e9SDmitry Salychev 	DPNI_UNLOCK(sc);
672ba7319e9SDmitry Salychev 
673ba7319e9SDmitry Salychev 	return;
674ba7319e9SDmitry Salychev }
675ba7319e9SDmitry Salychev 
676ba7319e9SDmitry Salychev static void
677ba7319e9SDmitry Salychev dpaa2_ni_setup_fixed_link(struct dpaa2_ni_softc *sc)
678ba7319e9SDmitry Salychev {
679ba7319e9SDmitry Salychev 	/*
680ba7319e9SDmitry Salychev 	 * FIXME: When the DPNI is connected to a DPMAC, we can get the
681ba7319e9SDmitry Salychev 	 * 'apparent' speed from it.
682ba7319e9SDmitry Salychev 	 */
683ba7319e9SDmitry Salychev 	sc->fixed_link = true;
684ba7319e9SDmitry Salychev 
685ba7319e9SDmitry Salychev 	ifmedia_init(&sc->fixed_ifmedia, 0, dpaa2_ni_media_change,
686ba7319e9SDmitry Salychev 		     dpaa2_ni_fixed_media_status);
687ba7319e9SDmitry Salychev 	ifmedia_add(&sc->fixed_ifmedia, IFM_ETHER | IFM_1000_T, 0, NULL);
688ba7319e9SDmitry Salychev 	ifmedia_set(&sc->fixed_ifmedia, IFM_ETHER | IFM_1000_T);
689ba7319e9SDmitry Salychev }
690ba7319e9SDmitry Salychev 
691ba7319e9SDmitry Salychev static int
692ba7319e9SDmitry Salychev dpaa2_ni_detach(device_t dev)
693ba7319e9SDmitry Salychev {
6944cd96614SDmitry Salychev 	/* TBD */
695ba7319e9SDmitry Salychev 	return (0);
696ba7319e9SDmitry Salychev }
697ba7319e9SDmitry Salychev 
698ba7319e9SDmitry Salychev /**
699ba7319e9SDmitry Salychev  * @brief Configure DPAA2 network interface object.
700ba7319e9SDmitry Salychev  */
701ba7319e9SDmitry Salychev static int
702ba7319e9SDmitry Salychev dpaa2_ni_setup(device_t dev)
703ba7319e9SDmitry Salychev {
7044cd96614SDmitry Salychev 	device_t pdev = device_get_parent(dev);
705ba7319e9SDmitry Salychev 	device_t child = dev;
706ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
7074cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
708ba7319e9SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
709ba7319e9SDmitry Salychev 	struct dpaa2_ep_desc ep1_desc, ep2_desc; /* endpoint descriptors */
7104cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
711ba7319e9SDmitry Salychev 	uint8_t eth_bca[ETHER_ADDR_LEN]; /* broadcast physical address */
7124cd96614SDmitry Salychev 	uint16_t rc_token, ni_token, mac_token;
713ba7319e9SDmitry Salychev 	struct dpaa2_mac_attr attr;
714ba7319e9SDmitry Salychev 	enum dpaa2_mac_link_type link_type;
715ba7319e9SDmitry Salychev 	uint32_t link;
716ba7319e9SDmitry Salychev 	int error;
717ba7319e9SDmitry Salychev 
7184cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
7194cd96614SDmitry Salychev 
7204cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
7214cd96614SDmitry Salychev 	if (error) {
7224cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
7234cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
7244cd96614SDmitry Salychev 		goto err_exit;
7254cd96614SDmitry Salychev 	}
7264cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
7274cd96614SDmitry Salychev 	if (error) {
7284cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
7294cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
7304cd96614SDmitry Salychev 		goto close_rc;
7314cd96614SDmitry Salychev 	}
7324cd96614SDmitry Salychev 
733ba7319e9SDmitry Salychev 	/* Check if we can work with this DPNI object. */
7344cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_GET_API_VERSION(dev, child, &cmd, &sc->api_major,
7354cd96614SDmitry Salychev 	    &sc->api_minor);
736ba7319e9SDmitry Salychev 	if (error) {
737ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to get DPNI API version\n",
738ba7319e9SDmitry Salychev 		    __func__);
7394cd96614SDmitry Salychev 		goto close_ni;
740ba7319e9SDmitry Salychev 	}
741ba7319e9SDmitry Salychev 	if (dpaa2_ni_cmp_api_version(sc, DPNI_VER_MAJOR, DPNI_VER_MINOR) < 0) {
742ba7319e9SDmitry Salychev 		device_printf(dev, "%s: DPNI API version %u.%u not supported, "
743ba7319e9SDmitry Salychev 		    "need >= %u.%u\n", __func__, sc->api_major, sc->api_minor,
744ba7319e9SDmitry Salychev 		    DPNI_VER_MAJOR, DPNI_VER_MINOR);
745ba7319e9SDmitry Salychev 		error = ENODEV;
7464cd96614SDmitry Salychev 		goto close_ni;
747ba7319e9SDmitry Salychev 	}
748ba7319e9SDmitry Salychev 
749ba7319e9SDmitry Salychev 	/* Reset the DPNI object. */
7504cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_RESET(dev, child, &cmd);
751ba7319e9SDmitry Salychev 	if (error) {
752ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to reset DPNI: id=%d\n",
753ba7319e9SDmitry Salychev 		    __func__, dinfo->id);
7544cd96614SDmitry Salychev 		goto close_ni;
755ba7319e9SDmitry Salychev 	}
756ba7319e9SDmitry Salychev 
757ba7319e9SDmitry Salychev 	/* Obtain attributes of the DPNI object. */
7584cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_GET_ATTRIBUTES(dev, child, &cmd, &sc->attr);
759ba7319e9SDmitry Salychev 	if (error) {
760ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to obtain DPNI attributes: "
761ba7319e9SDmitry Salychev 		    "id=%d\n", __func__, dinfo->id);
7624cd96614SDmitry Salychev 		goto close_ni;
763ba7319e9SDmitry Salychev 	}
764ba7319e9SDmitry Salychev 	if (bootverbose) {
7654cd96614SDmitry Salychev 		device_printf(dev, "\toptions=0x%#x queues=%d tx_channels=%d "
766ba7319e9SDmitry Salychev 		    "wriop_version=%#x\n", sc->attr.options, sc->attr.num.queues,
767ba7319e9SDmitry Salychev 		    sc->attr.num.channels, sc->attr.wriop_ver);
768ba7319e9SDmitry Salychev 		device_printf(dev, "\ttraffic classes: rx=%d tx=%d "
769ba7319e9SDmitry Salychev 		    "cgs_groups=%d\n", sc->attr.num.rx_tcs, sc->attr.num.tx_tcs,
770ba7319e9SDmitry Salychev 		    sc->attr.num.cgs);
771ba7319e9SDmitry Salychev 		device_printf(dev, "\ttable entries: mac=%d vlan=%d qos=%d "
772ba7319e9SDmitry Salychev 		    "fs=%d\n", sc->attr.entries.mac, sc->attr.entries.vlan,
773ba7319e9SDmitry Salychev 		    sc->attr.entries.qos, sc->attr.entries.fs);
774ba7319e9SDmitry Salychev 		device_printf(dev, "\tkey sizes: qos=%d fs=%d\n",
775ba7319e9SDmitry Salychev 		    sc->attr.key_size.qos, sc->attr.key_size.fs);
776ba7319e9SDmitry Salychev 	}
777ba7319e9SDmitry Salychev 
778ba7319e9SDmitry Salychev 	/* Configure buffer layouts of the DPNI queues. */
7794cd96614SDmitry Salychev 	error = dpaa2_ni_set_buf_layout(dev);
780ba7319e9SDmitry Salychev 	if (error) {
781ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to configure buffer layout\n",
782ba7319e9SDmitry Salychev 		    __func__);
7834cd96614SDmitry Salychev 		goto close_ni;
784ba7319e9SDmitry Salychev 	}
785ba7319e9SDmitry Salychev 
786ba7319e9SDmitry Salychev 	/* Configure DMA resources. */
787ba7319e9SDmitry Salychev 	error = dpaa2_ni_setup_dma(sc);
788ba7319e9SDmitry Salychev 	if (error) {
789ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to setup DMA\n", __func__);
7904cd96614SDmitry Salychev 		goto close_ni;
791ba7319e9SDmitry Salychev 	}
792ba7319e9SDmitry Salychev 
793ba7319e9SDmitry Salychev 	/* Setup link between DPNI and an object it's connected to. */
794ba7319e9SDmitry Salychev 	ep1_desc.obj_id = dinfo->id;
795ba7319e9SDmitry Salychev 	ep1_desc.if_id = 0; /* DPNI has the only endpoint */
796ba7319e9SDmitry Salychev 	ep1_desc.type = dinfo->dtype;
797ba7319e9SDmitry Salychev 
7984cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_GET_CONN(dev, child, DPAA2_CMD_TK(&cmd, rc_token),
799ba7319e9SDmitry Salychev 	    &ep1_desc, &ep2_desc, &link);
8004cd96614SDmitry Salychev 	if (error) {
801ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to obtain an object DPNI is "
802ba7319e9SDmitry Salychev 		    "connected to: error=%d\n", __func__, error);
8034cd96614SDmitry Salychev 	} else {
804ba7319e9SDmitry Salychev 		device_printf(dev, "connected to %s (id=%d)\n",
805ba7319e9SDmitry Salychev 		    dpaa2_ttos(ep2_desc.type), ep2_desc.obj_id);
806ba7319e9SDmitry Salychev 
8074cd96614SDmitry Salychev 		error = dpaa2_ni_set_mac_addr(dev);
8084cd96614SDmitry Salychev 		if (error) {
8094cd96614SDmitry Salychev 			device_printf(dev, "%s: failed to set MAC address: "
8104cd96614SDmitry Salychev 			    "error=%d\n", __func__, error);
8114cd96614SDmitry Salychev 		}
812ba7319e9SDmitry Salychev 
813ba7319e9SDmitry Salychev 		if (ep2_desc.type == DPAA2_DEV_MAC) {
814ba7319e9SDmitry Salychev 			/*
815ba7319e9SDmitry Salychev 			 * This is the simplest case when DPNI is connected to
816ba7319e9SDmitry Salychev 			 * DPMAC directly.
817ba7319e9SDmitry Salychev 			 */
818ba7319e9SDmitry Salychev 			sc->mac.dpmac_id = ep2_desc.obj_id;
819ba7319e9SDmitry Salychev 
820ba7319e9SDmitry Salychev 			link_type = DPAA2_MAC_LINK_TYPE_NONE;
821ba7319e9SDmitry Salychev 
822ba7319e9SDmitry Salychev 			/*
823ba7319e9SDmitry Salychev 			 * Need to determine if DPMAC type is PHY (attached to
824ba7319e9SDmitry Salychev 			 * conventional MII PHY) or FIXED (usually SFP/SerDes,
825ba7319e9SDmitry Salychev 			 * link state managed by MC firmware).
826ba7319e9SDmitry Salychev 			 */
827ba7319e9SDmitry Salychev 			error = DPAA2_CMD_MAC_OPEN(sc->dev, child,
8284cd96614SDmitry Salychev 			    DPAA2_CMD_TK(&cmd, rc_token), sc->mac.dpmac_id,
8294cd96614SDmitry Salychev 			    &mac_token);
830ba7319e9SDmitry Salychev 			/*
831ba7319e9SDmitry Salychev 			 * Under VFIO, the DPMAC might be sitting in another
832ba7319e9SDmitry Salychev 			 * container (DPRC) we don't have access to.
833ba7319e9SDmitry Salychev 			 * Assume DPAA2_MAC_LINK_TYPE_FIXED if this is
834ba7319e9SDmitry Salychev 			 * the case.
835ba7319e9SDmitry Salychev 			 */
836ba7319e9SDmitry Salychev 			if (error) {
837ba7319e9SDmitry Salychev 				device_printf(dev, "%s: failed to open "
838ba7319e9SDmitry Salychev 				    "connected DPMAC: %d (assuming in other DPRC)\n", __func__,
839ba7319e9SDmitry Salychev 				    sc->mac.dpmac_id);
840ba7319e9SDmitry Salychev 				link_type = DPAA2_MAC_LINK_TYPE_FIXED;
841ba7319e9SDmitry Salychev 			} else {
842ba7319e9SDmitry Salychev 				error = DPAA2_CMD_MAC_GET_ATTRIBUTES(dev, child,
8434cd96614SDmitry Salychev 				    &cmd, &attr);
8444cd96614SDmitry Salychev 				if (error) {
845ba7319e9SDmitry Salychev 					device_printf(dev, "%s: failed to get "
846ba7319e9SDmitry Salychev 					    "DPMAC attributes: id=%d, "
847ba7319e9SDmitry Salychev 					    "error=%d\n", __func__, dinfo->id,
848ba7319e9SDmitry Salychev 					    error);
8494cd96614SDmitry Salychev 				} else {
850ba7319e9SDmitry Salychev 					link_type = attr.link_type;
851ba7319e9SDmitry Salychev 				}
8524cd96614SDmitry Salychev 			}
8534cd96614SDmitry Salychev 			DPAA2_CMD_MAC_CLOSE(dev, child, &cmd);
854ba7319e9SDmitry Salychev 
855ba7319e9SDmitry Salychev 			if (link_type == DPAA2_MAC_LINK_TYPE_FIXED) {
856ba7319e9SDmitry Salychev 				device_printf(dev, "connected DPMAC is in FIXED "
857ba7319e9SDmitry Salychev 				    "mode\n");
858ba7319e9SDmitry Salychev 				dpaa2_ni_setup_fixed_link(sc);
859ba7319e9SDmitry Salychev 			} else if (link_type == DPAA2_MAC_LINK_TYPE_PHY) {
860ba7319e9SDmitry Salychev 				device_printf(dev, "connected DPMAC is in PHY "
861ba7319e9SDmitry Salychev 				    "mode\n");
862ba7319e9SDmitry Salychev 				error = DPAA2_MC_GET_PHY_DEV(dev,
863ba7319e9SDmitry Salychev 				    &sc->mac.phy_dev, sc->mac.dpmac_id);
864ba7319e9SDmitry Salychev 				if (error == 0) {
865ba7319e9SDmitry Salychev 					error = MEMAC_MDIO_SET_NI_DEV(
866ba7319e9SDmitry Salychev 					    sc->mac.phy_dev, dev);
8674cd96614SDmitry Salychev 					if (error != 0) {
868ba7319e9SDmitry Salychev 						device_printf(dev, "%s: failed "
869ba7319e9SDmitry Salychev 						    "to set dpni dev on memac "
870ba7319e9SDmitry Salychev 						    "mdio dev %s: error=%d\n",
871ba7319e9SDmitry Salychev 						    __func__,
872ba7319e9SDmitry Salychev 						    device_get_nameunit(
873ba7319e9SDmitry Salychev 						    sc->mac.phy_dev), error);
874ba7319e9SDmitry Salychev 					}
8754cd96614SDmitry Salychev 				}
876ba7319e9SDmitry Salychev 				if (error == 0) {
877ba7319e9SDmitry Salychev 					error = MEMAC_MDIO_GET_PHY_LOC(
878ba7319e9SDmitry Salychev 					    sc->mac.phy_dev, &sc->mac.phy_loc);
8794cd96614SDmitry Salychev 					if (error == ENODEV) {
880ba7319e9SDmitry Salychev 						error = 0;
8814cd96614SDmitry Salychev 					}
8824cd96614SDmitry Salychev 					if (error != 0) {
883ba7319e9SDmitry Salychev 						device_printf(dev, "%s: failed "
884ba7319e9SDmitry Salychev 						    "to get phy location from "
885ba7319e9SDmitry Salychev 						    "memac mdio dev %s: error=%d\n",
886ba7319e9SDmitry Salychev 						    __func__, device_get_nameunit(
887ba7319e9SDmitry Salychev 						    sc->mac.phy_dev), error);
888ba7319e9SDmitry Salychev 					}
8894cd96614SDmitry Salychev 				}
890ba7319e9SDmitry Salychev 				if (error == 0) {
891ba7319e9SDmitry Salychev 					error = mii_attach(sc->mac.phy_dev,
892ba7319e9SDmitry Salychev 					    &sc->miibus, sc->ifp,
893ba7319e9SDmitry Salychev 					    dpaa2_ni_media_change,
894ba7319e9SDmitry Salychev 					    dpaa2_ni_media_status,
895ba7319e9SDmitry Salychev 					    BMSR_DEFCAPMASK, sc->mac.phy_loc,
896ba7319e9SDmitry Salychev 					    MII_OFFSET_ANY, 0);
8974cd96614SDmitry Salychev 					if (error != 0) {
898ba7319e9SDmitry Salychev 						device_printf(dev, "%s: failed "
899ba7319e9SDmitry Salychev 						    "to attach to miibus: "
900ba7319e9SDmitry Salychev 						    "error=%d\n",
901ba7319e9SDmitry Salychev 						    __func__, error);
902ba7319e9SDmitry Salychev 					}
9034cd96614SDmitry Salychev 				}
9044cd96614SDmitry Salychev 				if (error == 0) {
905ba7319e9SDmitry Salychev 					sc->mii = device_get_softc(sc->miibus);
9064cd96614SDmitry Salychev 				}
907ba7319e9SDmitry Salychev 			} else {
908ba7319e9SDmitry Salychev 				device_printf(dev, "%s: DPMAC link type is not "
909ba7319e9SDmitry Salychev 				    "supported\n", __func__);
910ba7319e9SDmitry Salychev 			}
911ba7319e9SDmitry Salychev 		} else if (ep2_desc.type == DPAA2_DEV_NI ||
912ba7319e9SDmitry Salychev 			   ep2_desc.type == DPAA2_DEV_MUX ||
913ba7319e9SDmitry Salychev 			   ep2_desc.type == DPAA2_DEV_SW) {
914ba7319e9SDmitry Salychev 			dpaa2_ni_setup_fixed_link(sc);
915ba7319e9SDmitry Salychev 		}
916ba7319e9SDmitry Salychev 	}
917ba7319e9SDmitry Salychev 
918ba7319e9SDmitry Salychev 	/* Select mode to enqueue frames. */
919ba7319e9SDmitry Salychev 	/* ... TBD ... */
920ba7319e9SDmitry Salychev 
921ba7319e9SDmitry Salychev 	/*
922ba7319e9SDmitry Salychev 	 * Update link configuration to enable Rx/Tx pause frames support.
923ba7319e9SDmitry Salychev 	 *
924ba7319e9SDmitry Salychev 	 * NOTE: MC may generate an interrupt to the DPMAC and request changes
925ba7319e9SDmitry Salychev 	 *       in link configuration. It might be necessary to attach miibus
926ba7319e9SDmitry Salychev 	 *       and PHY before this point.
927ba7319e9SDmitry Salychev 	 */
9284cd96614SDmitry Salychev 	error = dpaa2_ni_set_pause_frame(dev);
929ba7319e9SDmitry Salychev 	if (error) {
930ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to configure Rx/Tx pause "
931ba7319e9SDmitry Salychev 		    "frames\n", __func__);
9324cd96614SDmitry Salychev 		goto close_ni;
933ba7319e9SDmitry Salychev 	}
934ba7319e9SDmitry Salychev 
935ba7319e9SDmitry Salychev 	/* Configure ingress traffic classification. */
9364cd96614SDmitry Salychev 	error = dpaa2_ni_set_qos_table(dev);
9374cd96614SDmitry Salychev 	if (error) {
938ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to configure QoS table: "
939ba7319e9SDmitry Salychev 		    "error=%d\n", __func__, error);
9404cd96614SDmitry Salychev 		goto close_ni;
9414cd96614SDmitry Salychev 	}
942ba7319e9SDmitry Salychev 
943ba7319e9SDmitry Salychev 	/* Add broadcast physical address to the MAC filtering table. */
944ba7319e9SDmitry Salychev 	memset(eth_bca, 0xff, ETHER_ADDR_LEN);
9454cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_ADD_MAC_ADDR(dev, child, DPAA2_CMD_TK(&cmd,
9464cd96614SDmitry Salychev 	    ni_token), eth_bca);
947ba7319e9SDmitry Salychev 	if (error) {
948ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to add broadcast physical "
949ba7319e9SDmitry Salychev 		    "address to the MAC filtering table\n", __func__);
9504cd96614SDmitry Salychev 		goto close_ni;
951ba7319e9SDmitry Salychev 	}
952ba7319e9SDmitry Salychev 
953ba7319e9SDmitry Salychev 	/* Set the maximum allowed length for received frames. */
9544cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_MFL(dev, child, &cmd, DPAA2_ETH_MFL);
955ba7319e9SDmitry Salychev 	if (error) {
956ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to set maximum length for "
957ba7319e9SDmitry Salychev 		    "received frames\n", __func__);
9584cd96614SDmitry Salychev 		goto close_ni;
959ba7319e9SDmitry Salychev 	}
960ba7319e9SDmitry Salychev 
9614cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
9624cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
963ba7319e9SDmitry Salychev 	return (0);
9644cd96614SDmitry Salychev 
9654cd96614SDmitry Salychev close_ni:
9664cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
9674cd96614SDmitry Salychev close_rc:
9684cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
9694cd96614SDmitry Salychev err_exit:
9704cd96614SDmitry Salychev 	return (error);
971ba7319e9SDmitry Salychev }
972ba7319e9SDmitry Salychev 
973ba7319e9SDmitry Salychev /**
974ba7319e9SDmitry Salychev  * @brief Сonfigure QBMan channels and register data availability notifications.
975ba7319e9SDmitry Salychev  */
976ba7319e9SDmitry Salychev static int
977ba7319e9SDmitry Salychev dpaa2_ni_setup_channels(device_t dev)
978ba7319e9SDmitry Salychev {
97958983e4bSDmitry Salychev 	device_t iodev, condev, bpdev;
980ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
981ba7319e9SDmitry Salychev 	uint32_t i, num_chan;
9824cd96614SDmitry Salychev 	int error;
983ba7319e9SDmitry Salychev 
98458983e4bSDmitry Salychev 	/* Calculate number of the channels based on the allocated resources */
98558983e4bSDmitry Salychev 	for (i = 0; i < DPAA2_NI_IO_RES_NUM; i++) {
98658983e4bSDmitry Salychev 		if (!sc->res[DPAA2_NI_IO_RID(i)]) {
987ba7319e9SDmitry Salychev 			break;
9884cd96614SDmitry Salychev 		}
9894cd96614SDmitry Salychev 	}
990ba7319e9SDmitry Salychev 	num_chan = i;
99158983e4bSDmitry Salychev 	for (i = 0; i < DPAA2_NI_CON_RES_NUM; i++) {
99258983e4bSDmitry Salychev 		if (!sc->res[DPAA2_NI_CON_RID(i)]) {
993ba7319e9SDmitry Salychev 			break;
9944cd96614SDmitry Salychev 		}
9954cd96614SDmitry Salychev 	}
996ba7319e9SDmitry Salychev 	num_chan = i < num_chan ? i : num_chan;
99758983e4bSDmitry Salychev 	sc->chan_n = num_chan > DPAA2_MAX_CHANNELS
99858983e4bSDmitry Salychev 	    ? DPAA2_MAX_CHANNELS : num_chan;
999ba7319e9SDmitry Salychev 	sc->chan_n = sc->chan_n > sc->attr.num.queues
1000ba7319e9SDmitry Salychev 	    ? sc->attr.num.queues : sc->chan_n;
1001ba7319e9SDmitry Salychev 
100258983e4bSDmitry Salychev 	KASSERT(sc->chan_n > 0u, ("%s: positive number of channels expected: "
100358983e4bSDmitry Salychev 	    "chan_n=%d", __func__, sc->chan_n));
100458983e4bSDmitry Salychev 
1005ba7319e9SDmitry Salychev 	device_printf(dev, "channels=%d\n", sc->chan_n);
1006ba7319e9SDmitry Salychev 
100758983e4bSDmitry Salychev 	for (i = 0; i < sc->chan_n; i++) {
100858983e4bSDmitry Salychev 		iodev = (device_t)rman_get_start(sc->res[DPAA2_NI_IO_RID(i)]);
100958983e4bSDmitry Salychev 		condev = (device_t)rman_get_start(sc->res[DPAA2_NI_CON_RID(i)]);
101058983e4bSDmitry Salychev 		/* Only one buffer pool available at the moment */
101158983e4bSDmitry Salychev 		bpdev = (device_t)rman_get_start(sc->res[DPAA2_NI_BP_RID(0)]);
1012ba7319e9SDmitry Salychev 
101358983e4bSDmitry Salychev 		error = dpaa2_chan_setup(dev, iodev, condev, bpdev,
101458983e4bSDmitry Salychev 		    &sc->channels[i], i, dpaa2_ni_cleanup_task);
101558983e4bSDmitry Salychev 		if (error != 0) {
101658983e4bSDmitry Salychev 			device_printf(dev, "%s: dpaa2_chan_setup() failed: "
101758983e4bSDmitry Salychev 			    "error=%d, chan_id=%d\n", __func__, error, i);
10184cd96614SDmitry Salychev 			return (error);
10194cd96614SDmitry Salychev 		}
10204cd96614SDmitry Salychev 	}
10214cd96614SDmitry Salychev 
102258983e4bSDmitry Salychev 	/* There is exactly one Rx error queue per network interface */
102358983e4bSDmitry Salychev 	error = dpaa2_chan_setup_fq(dev, sc->channels[0], DPAA2_NI_QUEUE_RX_ERR);
102458983e4bSDmitry Salychev 	if (error != 0) {
1025ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to prepare RxError queue: "
1026ba7319e9SDmitry Salychev 		    "error=%d\n", __func__, error);
1027ba7319e9SDmitry Salychev 		return (error);
1028ba7319e9SDmitry Salychev 	}
1029ba7319e9SDmitry Salychev 
1030ba7319e9SDmitry Salychev 	return (0);
1031ba7319e9SDmitry Salychev }
1032ba7319e9SDmitry Salychev 
1033ba7319e9SDmitry Salychev /**
1034ba7319e9SDmitry Salychev  * @brief Bind DPNI to DPBPs, DPIOs, frame queues and channels.
1035ba7319e9SDmitry Salychev  */
1036ba7319e9SDmitry Salychev static int
1037ba7319e9SDmitry Salychev dpaa2_ni_bind(device_t dev)
1038ba7319e9SDmitry Salychev {
10394cd96614SDmitry Salychev 	device_t pdev = device_get_parent(dev);
10404cd96614SDmitry Salychev 	device_t child = dev;
10414cd96614SDmitry Salychev 	device_t bp_dev;
1042ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
10434cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
10444cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
1045ba7319e9SDmitry Salychev 	struct dpaa2_devinfo *bp_info;
10464cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
1047ba7319e9SDmitry Salychev 	struct dpaa2_ni_pools_cfg pools_cfg;
1048ba7319e9SDmitry Salychev 	struct dpaa2_ni_err_cfg err_cfg;
104958983e4bSDmitry Salychev 	struct dpaa2_channel *chan;
10504cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
1051ba7319e9SDmitry Salychev 	int error;
1052ba7319e9SDmitry Salychev 
10534cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
10544cd96614SDmitry Salychev 
10554cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
10564cd96614SDmitry Salychev 	if (error) {
10574cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
10584cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
10594cd96614SDmitry Salychev 		goto err_exit;
10604cd96614SDmitry Salychev 	}
10614cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
10624cd96614SDmitry Salychev 	if (error) {
10634cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
10644cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
10654cd96614SDmitry Salychev 		goto close_rc;
10664cd96614SDmitry Salychev 	}
10674cd96614SDmitry Salychev 
1068ba7319e9SDmitry Salychev 	/* Select buffer pool (only one available at the moment). */
106958983e4bSDmitry Salychev 	bp_dev = (device_t) rman_get_start(sc->res[DPAA2_NI_BP_RID(0)]);
1070ba7319e9SDmitry Salychev 	bp_info = device_get_ivars(bp_dev);
1071ba7319e9SDmitry Salychev 
1072ba7319e9SDmitry Salychev 	/* Configure buffers pool. */
1073ba7319e9SDmitry Salychev 	pools_cfg.pools_num = 1;
1074ba7319e9SDmitry Salychev 	pools_cfg.pools[0].bp_obj_id = bp_info->id;
1075ba7319e9SDmitry Salychev 	pools_cfg.pools[0].backup_flag = 0;
1076ba7319e9SDmitry Salychev 	pools_cfg.pools[0].buf_sz = sc->buf_sz;
10774cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_POOLS(dev, child, &cmd, &pools_cfg);
1078ba7319e9SDmitry Salychev 	if (error) {
1079ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to set buffer pools\n", __func__);
10804cd96614SDmitry Salychev 		goto close_ni;
1081ba7319e9SDmitry Salychev 	}
1082ba7319e9SDmitry Salychev 
1083ba7319e9SDmitry Salychev 	/* Setup ingress traffic distribution. */
1084ba7319e9SDmitry Salychev 	error = dpaa2_ni_setup_rx_dist(dev);
1085ba7319e9SDmitry Salychev 	if (error && error != EOPNOTSUPP) {
1086ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to setup ingress traffic "
1087ba7319e9SDmitry Salychev 		    "distribution\n", __func__);
10884cd96614SDmitry Salychev 		goto close_ni;
1089ba7319e9SDmitry Salychev 	}
10904cd96614SDmitry Salychev 	if (bootverbose && error == EOPNOTSUPP) {
1091ba7319e9SDmitry Salychev 		device_printf(dev, "Ingress traffic distribution not "
1092ba7319e9SDmitry Salychev 		    "supported\n");
10934cd96614SDmitry Salychev 	}
1094ba7319e9SDmitry Salychev 
1095ba7319e9SDmitry Salychev 	/* Configure handling of error frames. */
1096ba7319e9SDmitry Salychev 	err_cfg.err_mask = DPAA2_NI_FAS_RX_ERR_MASK;
1097ba7319e9SDmitry Salychev 	err_cfg.set_err_fas = false;
1098ba7319e9SDmitry Salychev 	err_cfg.action = DPAA2_NI_ERR_DISCARD;
10994cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_ERR_BEHAVIOR(dev, child, &cmd, &err_cfg);
1100ba7319e9SDmitry Salychev 	if (error) {
1101ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to set errors behavior\n",
1102ba7319e9SDmitry Salychev 		    __func__);
11034cd96614SDmitry Salychev 		goto close_ni;
1104ba7319e9SDmitry Salychev 	}
1105ba7319e9SDmitry Salychev 
1106ba7319e9SDmitry Salychev 	/* Configure channel queues to generate CDANs. */
1107ba7319e9SDmitry Salychev 	for (uint32_t i = 0; i < sc->chan_n; i++) {
1108ba7319e9SDmitry Salychev 		chan = sc->channels[i];
1109ba7319e9SDmitry Salychev 
1110ba7319e9SDmitry Salychev 		/* Setup Rx flows. */
1111ba7319e9SDmitry Salychev 		for (uint32_t j = 0; j < chan->rxq_n; j++) {
11124cd96614SDmitry Salychev 			error = dpaa2_ni_setup_rx_flow(dev, &chan->rx_queues[j]);
1113ba7319e9SDmitry Salychev 			if (error) {
1114ba7319e9SDmitry Salychev 				device_printf(dev, "%s: failed to setup Rx "
1115ba7319e9SDmitry Salychev 				    "flow: error=%d\n", __func__, error);
11164cd96614SDmitry Salychev 				goto close_ni;
1117ba7319e9SDmitry Salychev 			}
1118ba7319e9SDmitry Salychev 		}
1119ba7319e9SDmitry Salychev 
1120ba7319e9SDmitry Salychev 		/* Setup Tx flow. */
11214cd96614SDmitry Salychev 		error = dpaa2_ni_setup_tx_flow(dev, &chan->txc_queue);
1122ba7319e9SDmitry Salychev 		if (error) {
1123ba7319e9SDmitry Salychev 			device_printf(dev, "%s: failed to setup Tx "
1124ba7319e9SDmitry Salychev 			    "flow: error=%d\n", __func__, error);
11254cd96614SDmitry Salychev 			goto close_ni;
1126ba7319e9SDmitry Salychev 		}
1127ba7319e9SDmitry Salychev 	}
1128ba7319e9SDmitry Salychev 
1129ba7319e9SDmitry Salychev 	/* Configure RxError queue to generate CDAN. */
11304cd96614SDmitry Salychev 	error = dpaa2_ni_setup_rx_err_flow(dev, &sc->rxe_queue);
1131ba7319e9SDmitry Salychev 	if (error) {
1132ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to setup RxError flow: "
1133ba7319e9SDmitry Salychev 		    "error=%d\n", __func__, error);
11344cd96614SDmitry Salychev 		goto close_ni;
1135ba7319e9SDmitry Salychev 	}
1136ba7319e9SDmitry Salychev 
1137ba7319e9SDmitry Salychev 	/*
1138ba7319e9SDmitry Salychev 	 * Get the Queuing Destination ID (QDID) that should be used for frame
1139ba7319e9SDmitry Salychev 	 * enqueue operations.
1140ba7319e9SDmitry Salychev 	 */
11414cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_GET_QDID(dev, child, &cmd, DPAA2_NI_QUEUE_TX,
1142ba7319e9SDmitry Salychev 	    &sc->tx_qdid);
1143ba7319e9SDmitry Salychev 	if (error) {
1144ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to get Tx queuing destination "
1145ba7319e9SDmitry Salychev 		    "ID\n", __func__);
11464cd96614SDmitry Salychev 		goto close_ni;
1147ba7319e9SDmitry Salychev 	}
1148ba7319e9SDmitry Salychev 
11494cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
11504cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
1151ba7319e9SDmitry Salychev 	return (0);
11524cd96614SDmitry Salychev 
11534cd96614SDmitry Salychev close_ni:
11544cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
11554cd96614SDmitry Salychev close_rc:
11564cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
11574cd96614SDmitry Salychev err_exit:
11584cd96614SDmitry Salychev 	return (error);
1159ba7319e9SDmitry Salychev }
1160ba7319e9SDmitry Salychev 
1161ba7319e9SDmitry Salychev /**
1162ba7319e9SDmitry Salychev  * @brief Setup ingress traffic distribution.
1163ba7319e9SDmitry Salychev  *
1164ba7319e9SDmitry Salychev  * NOTE: Ingress traffic distribution is valid only when DPNI_OPT_NO_FS option
1165ba7319e9SDmitry Salychev  *	 hasn't been set for DPNI and a number of DPNI queues > 1.
1166ba7319e9SDmitry Salychev  */
1167ba7319e9SDmitry Salychev static int
1168ba7319e9SDmitry Salychev dpaa2_ni_setup_rx_dist(device_t dev)
1169ba7319e9SDmitry Salychev {
1170ba7319e9SDmitry Salychev 	/*
1171ba7319e9SDmitry Salychev 	 * Have the interface implicitly distribute traffic based on the default
1172ba7319e9SDmitry Salychev 	 * hash key.
1173ba7319e9SDmitry Salychev 	 */
1174ba7319e9SDmitry Salychev 	return (dpaa2_ni_set_hash(dev, DPAA2_RXH_DEFAULT));
1175ba7319e9SDmitry Salychev }
1176ba7319e9SDmitry Salychev 
1177ba7319e9SDmitry Salychev static int
11784cd96614SDmitry Salychev dpaa2_ni_setup_rx_flow(device_t dev, struct dpaa2_ni_fq *fq)
1179ba7319e9SDmitry Salychev {
11804cd96614SDmitry Salychev 	device_t pdev = device_get_parent(dev);
1181ba7319e9SDmitry Salychev 	device_t child = dev;
11824cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
11834cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
1184ba7319e9SDmitry Salychev 	struct dpaa2_devinfo *con_info;
11854cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
1186ba7319e9SDmitry Salychev 	struct dpaa2_ni_queue_cfg queue_cfg = {0};
11874cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
1188ba7319e9SDmitry Salychev 	int error;
1189ba7319e9SDmitry Salychev 
11904cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
11914cd96614SDmitry Salychev 
11924cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
11934cd96614SDmitry Salychev 	if (error) {
11944cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
11954cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
11964cd96614SDmitry Salychev 		goto err_exit;
11974cd96614SDmitry Salychev 	}
11984cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
11994cd96614SDmitry Salychev 	if (error) {
12004cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
12014cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
12024cd96614SDmitry Salychev 		goto close_rc;
12034cd96614SDmitry Salychev 	}
12044cd96614SDmitry Salychev 
1205ba7319e9SDmitry Salychev 	/* Obtain DPCON associated with the FQ's channel. */
1206ba7319e9SDmitry Salychev 	con_info = device_get_ivars(fq->chan->con_dev);
1207ba7319e9SDmitry Salychev 
1208ba7319e9SDmitry Salychev 	queue_cfg.type = DPAA2_NI_QUEUE_RX;
1209ba7319e9SDmitry Salychev 	queue_cfg.tc = fq->tc;
1210ba7319e9SDmitry Salychev 	queue_cfg.idx = fq->flowid;
12114cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_GET_QUEUE(dev, child, &cmd, &queue_cfg);
1212ba7319e9SDmitry Salychev 	if (error) {
1213ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to obtain Rx queue "
1214ba7319e9SDmitry Salychev 		    "configuration: tc=%d, flowid=%d\n", __func__, queue_cfg.tc,
1215ba7319e9SDmitry Salychev 		    queue_cfg.idx);
12164cd96614SDmitry Salychev 		goto close_ni;
1217ba7319e9SDmitry Salychev 	}
1218ba7319e9SDmitry Salychev 
1219ba7319e9SDmitry Salychev 	fq->fqid = queue_cfg.fqid;
1220ba7319e9SDmitry Salychev 
1221ba7319e9SDmitry Salychev 	queue_cfg.dest_id = con_info->id;
1222ba7319e9SDmitry Salychev 	queue_cfg.dest_type = DPAA2_NI_DEST_DPCON;
1223ba7319e9SDmitry Salychev 	queue_cfg.priority = 1;
1224ba7319e9SDmitry Salychev 	queue_cfg.user_ctx = (uint64_t)(uintmax_t) fq;
1225ba7319e9SDmitry Salychev 	queue_cfg.options =
1226ba7319e9SDmitry Salychev 	    DPAA2_NI_QUEUE_OPT_USER_CTX |
1227ba7319e9SDmitry Salychev 	    DPAA2_NI_QUEUE_OPT_DEST;
12284cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_QUEUE(dev, child, &cmd, &queue_cfg);
1229ba7319e9SDmitry Salychev 	if (error) {
1230ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to update Rx queue "
1231ba7319e9SDmitry Salychev 		    "configuration: tc=%d, flowid=%d\n", __func__, queue_cfg.tc,
1232ba7319e9SDmitry Salychev 		    queue_cfg.idx);
12334cd96614SDmitry Salychev 		goto close_ni;
1234ba7319e9SDmitry Salychev 	}
1235ba7319e9SDmitry Salychev 
1236ba7319e9SDmitry Salychev 	if (bootverbose) {
1237ba7319e9SDmitry Salychev 		device_printf(dev, "RX queue idx=%d, tc=%d, chan=%d, fqid=%d, "
1238ba7319e9SDmitry Salychev 		    "user_ctx=%#jx\n", fq->flowid, fq->tc, fq->chan->id,
1239ba7319e9SDmitry Salychev 		    fq->fqid, (uint64_t) fq);
1240ba7319e9SDmitry Salychev 	}
1241ba7319e9SDmitry Salychev 
12424cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, &cmd);
12434cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
1244ba7319e9SDmitry Salychev 	return (0);
12454cd96614SDmitry Salychev 
12464cd96614SDmitry Salychev close_ni:
12474cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
12484cd96614SDmitry Salychev close_rc:
12494cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
12504cd96614SDmitry Salychev err_exit:
12514cd96614SDmitry Salychev 	return (error);
1252ba7319e9SDmitry Salychev }
1253ba7319e9SDmitry Salychev 
1254ba7319e9SDmitry Salychev static int
12554cd96614SDmitry Salychev dpaa2_ni_setup_tx_flow(device_t dev, struct dpaa2_ni_fq *fq)
1256ba7319e9SDmitry Salychev {
12574cd96614SDmitry Salychev 	device_t pdev = device_get_parent(dev);
1258ba7319e9SDmitry Salychev 	device_t child = dev;
1259ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
126058983e4bSDmitry Salychev 	struct dpaa2_channel *ch = fq->chan;
12614cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
12624cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
1263ba7319e9SDmitry Salychev 	struct dpaa2_devinfo *con_info;
1264ba7319e9SDmitry Salychev 	struct dpaa2_ni_queue_cfg queue_cfg = {0};
1265ba7319e9SDmitry Salychev 	struct dpaa2_ni_tx_ring *tx;
1266ba7319e9SDmitry Salychev 	struct dpaa2_buf *buf;
12674cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
1268ba7319e9SDmitry Salychev 	uint32_t tx_rings_n = 0;
12694cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
1270ba7319e9SDmitry Salychev 	int error;
1271ba7319e9SDmitry Salychev 
12724cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
12734cd96614SDmitry Salychev 
12744cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
12754cd96614SDmitry Salychev 	if (error) {
12764cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
12774cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
12784cd96614SDmitry Salychev 		goto err_exit;
12794cd96614SDmitry Salychev 	}
12804cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
12814cd96614SDmitry Salychev 	if (error) {
12824cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
12834cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
12844cd96614SDmitry Salychev 		goto close_rc;
12854cd96614SDmitry Salychev 	}
12864cd96614SDmitry Salychev 
1287ba7319e9SDmitry Salychev 	/* Obtain DPCON associated with the FQ's channel. */
1288ba7319e9SDmitry Salychev 	con_info = device_get_ivars(fq->chan->con_dev);
1289ba7319e9SDmitry Salychev 
129058983e4bSDmitry Salychev 	KASSERT(sc->attr.num.tx_tcs <= DPAA2_MAX_TCS,
1291ba7319e9SDmitry Salychev 	    ("%s: too many Tx traffic classes: tx_tcs=%d\n", __func__,
1292ba7319e9SDmitry Salychev 	    sc->attr.num.tx_tcs));
1293ba7319e9SDmitry Salychev 	KASSERT(DPAA2_NI_BUFS_PER_TX <= DPAA2_NI_MAX_BPTX,
1294ba7319e9SDmitry Salychev 	    ("%s: too many Tx buffers (%d): max=%d\n", __func__,
1295ba7319e9SDmitry Salychev 	    DPAA2_NI_BUFS_PER_TX, DPAA2_NI_MAX_BPTX));
1296ba7319e9SDmitry Salychev 
1297ba7319e9SDmitry Salychev 	/* Setup Tx rings. */
1298ba7319e9SDmitry Salychev 	for (int i = 0; i < sc->attr.num.tx_tcs; i++) {
1299ba7319e9SDmitry Salychev 		queue_cfg.type = DPAA2_NI_QUEUE_TX;
1300ba7319e9SDmitry Salychev 		queue_cfg.tc = i;
1301ba7319e9SDmitry Salychev 		queue_cfg.idx = fq->flowid;
1302ba7319e9SDmitry Salychev 		queue_cfg.chan_id = fq->chan->id;
1303ba7319e9SDmitry Salychev 
13044cd96614SDmitry Salychev 		error = DPAA2_CMD_NI_GET_QUEUE(dev, child, &cmd, &queue_cfg);
1305ba7319e9SDmitry Salychev 		if (error) {
1306ba7319e9SDmitry Salychev 			device_printf(dev, "%s: failed to obtain Tx queue "
1307ba7319e9SDmitry Salychev 			    "configuration: tc=%d, flowid=%d\n", __func__,
1308ba7319e9SDmitry Salychev 			    queue_cfg.tc, queue_cfg.idx);
13094cd96614SDmitry Salychev 			goto close_ni;
1310ba7319e9SDmitry Salychev 		}
1311ba7319e9SDmitry Salychev 
1312ba7319e9SDmitry Salychev 		tx = &fq->tx_rings[i];
1313ba7319e9SDmitry Salychev 		tx->fq = fq;
1314ba7319e9SDmitry Salychev 		tx->fqid = queue_cfg.fqid;
1315ba7319e9SDmitry Salychev 		tx->txid = tx_rings_n;
1316ba7319e9SDmitry Salychev 
1317ba7319e9SDmitry Salychev 		if (bootverbose) {
1318ba7319e9SDmitry Salychev 			device_printf(dev, "TX queue idx=%d, tc=%d, chan=%d, "
1319ba7319e9SDmitry Salychev 			    "fqid=%d\n", fq->flowid, i, fq->chan->id,
1320ba7319e9SDmitry Salychev 			    queue_cfg.fqid);
1321ba7319e9SDmitry Salychev 		}
1322ba7319e9SDmitry Salychev 
1323ba7319e9SDmitry Salychev 		mtx_init(&tx->lock, "dpaa2_tx_ring", NULL, MTX_DEF);
1324ba7319e9SDmitry Salychev 
1325ba7319e9SDmitry Salychev 		/* Allocate Tx ring buffer. */
132658983e4bSDmitry Salychev 		tx->br = buf_ring_alloc(DPAA2_TX_BUFRING_SZ, M_DEVBUF, M_NOWAIT,
132758983e4bSDmitry Salychev 		    &tx->lock);
132858983e4bSDmitry Salychev 		if (tx->br == NULL) {
1329ba7319e9SDmitry Salychev 			device_printf(dev, "%s: failed to setup Tx ring buffer"
1330ba7319e9SDmitry Salychev 			    " (2) fqid=%d\n", __func__, tx->fqid);
13314cd96614SDmitry Salychev 			goto close_ni;
1332ba7319e9SDmitry Salychev 		}
1333ba7319e9SDmitry Salychev 
133458983e4bSDmitry Salychev 		/* Configure Tx buffers */
1335ba7319e9SDmitry Salychev 		for (uint64_t j = 0; j < DPAA2_NI_BUFS_PER_TX; j++) {
133658983e4bSDmitry Salychev 			buf = malloc(sizeof(struct dpaa2_buf), M_DPAA2_TXB,
133758983e4bSDmitry Salychev 			    M_WAITOK);
133858983e4bSDmitry Salychev 			/* Keep DMA tag and Tx ring linked to the buffer */
133958983e4bSDmitry Salychev 			DPAA2_BUF_INIT_TAGOPT(buf, ch->tx_dmat, tx);
1340ba7319e9SDmitry Salychev 
134158983e4bSDmitry Salychev 			buf->sgt = malloc(sizeof(struct dpaa2_buf), M_DPAA2_TXB,
134258983e4bSDmitry Salychev 			    M_WAITOK);
134358983e4bSDmitry Salychev 			/* Link SGT to DMA tag and back to its Tx buffer */
134458983e4bSDmitry Salychev 			DPAA2_BUF_INIT_TAGOPT(buf->sgt, ch->sgt_dmat, buf);
1345ba7319e9SDmitry Salychev 
134658983e4bSDmitry Salychev 			error = dpaa2_buf_seed_txb(dev, buf);
134758983e4bSDmitry Salychev 
134858983e4bSDmitry Salychev 			/* Add Tx buffer to the ring */
134958983e4bSDmitry Salychev 			buf_ring_enqueue(tx->br, buf);
1350ba7319e9SDmitry Salychev 		}
1351ba7319e9SDmitry Salychev 
1352ba7319e9SDmitry Salychev 		tx_rings_n++;
1353ba7319e9SDmitry Salychev 	}
1354ba7319e9SDmitry Salychev 
1355ba7319e9SDmitry Salychev 	/* All Tx queues which belong to the same flowid have the same qdbin. */
1356ba7319e9SDmitry Salychev 	fq->tx_qdbin = queue_cfg.qdbin;
1357ba7319e9SDmitry Salychev 
1358ba7319e9SDmitry Salychev 	queue_cfg.type = DPAA2_NI_QUEUE_TX_CONF;
1359ba7319e9SDmitry Salychev 	queue_cfg.tc = 0; /* ignored for TxConf queue */
1360ba7319e9SDmitry Salychev 	queue_cfg.idx = fq->flowid;
13614cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_GET_QUEUE(dev, child, &cmd, &queue_cfg);
1362ba7319e9SDmitry Salychev 	if (error) {
1363ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to obtain TxConf queue "
1364ba7319e9SDmitry Salychev 		    "configuration: tc=%d, flowid=%d\n", __func__, queue_cfg.tc,
1365ba7319e9SDmitry Salychev 		    queue_cfg.idx);
13664cd96614SDmitry Salychev 		goto close_ni;
1367ba7319e9SDmitry Salychev 	}
1368ba7319e9SDmitry Salychev 
1369ba7319e9SDmitry Salychev 	fq->fqid = queue_cfg.fqid;
1370ba7319e9SDmitry Salychev 
1371ba7319e9SDmitry Salychev 	queue_cfg.dest_id = con_info->id;
1372ba7319e9SDmitry Salychev 	queue_cfg.dest_type = DPAA2_NI_DEST_DPCON;
1373ba7319e9SDmitry Salychev 	queue_cfg.priority = 0;
1374ba7319e9SDmitry Salychev 	queue_cfg.user_ctx = (uint64_t)(uintmax_t) fq;
1375ba7319e9SDmitry Salychev 	queue_cfg.options =
1376ba7319e9SDmitry Salychev 	    DPAA2_NI_QUEUE_OPT_USER_CTX |
1377ba7319e9SDmitry Salychev 	    DPAA2_NI_QUEUE_OPT_DEST;
13784cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_QUEUE(dev, child, &cmd, &queue_cfg);
1379ba7319e9SDmitry Salychev 	if (error) {
1380ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to update TxConf queue "
1381ba7319e9SDmitry Salychev 		    "configuration: tc=%d, flowid=%d\n", __func__, queue_cfg.tc,
1382ba7319e9SDmitry Salychev 		    queue_cfg.idx);
13834cd96614SDmitry Salychev 		goto close_ni;
13844cd96614SDmitry Salychev 	}
13854cd96614SDmitry Salychev 
13864cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
13874cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
13884cd96614SDmitry Salychev 	return (0);
13894cd96614SDmitry Salychev 
13904cd96614SDmitry Salychev close_ni:
13914cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
13924cd96614SDmitry Salychev close_rc:
13934cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
13944cd96614SDmitry Salychev err_exit:
1395ba7319e9SDmitry Salychev 	return (error);
1396ba7319e9SDmitry Salychev }
1397ba7319e9SDmitry Salychev 
1398ba7319e9SDmitry Salychev static int
13994cd96614SDmitry Salychev dpaa2_ni_setup_rx_err_flow(device_t dev, struct dpaa2_ni_fq *fq)
1400ba7319e9SDmitry Salychev {
14014cd96614SDmitry Salychev 	device_t pdev = device_get_parent(dev);
1402ba7319e9SDmitry Salychev 	device_t child = dev;
14034cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
14044cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
1405ba7319e9SDmitry Salychev 	struct dpaa2_devinfo *con_info;
1406ba7319e9SDmitry Salychev 	struct dpaa2_ni_queue_cfg queue_cfg = {0};
14074cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
14084cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
1409ba7319e9SDmitry Salychev 	int error;
1410ba7319e9SDmitry Salychev 
14114cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
14124cd96614SDmitry Salychev 
14134cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
14144cd96614SDmitry Salychev 	if (error) {
14154cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
14164cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
14174cd96614SDmitry Salychev 		goto err_exit;
14184cd96614SDmitry Salychev 	}
14194cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
14204cd96614SDmitry Salychev 	if (error) {
14214cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
14224cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
14234cd96614SDmitry Salychev 		goto close_rc;
14244cd96614SDmitry Salychev 	}
14254cd96614SDmitry Salychev 
1426ba7319e9SDmitry Salychev 	/* Obtain DPCON associated with the FQ's channel. */
1427ba7319e9SDmitry Salychev 	con_info = device_get_ivars(fq->chan->con_dev);
1428ba7319e9SDmitry Salychev 
1429ba7319e9SDmitry Salychev 	queue_cfg.type = DPAA2_NI_QUEUE_RX_ERR;
1430ba7319e9SDmitry Salychev 	queue_cfg.tc = fq->tc; /* ignored */
1431ba7319e9SDmitry Salychev 	queue_cfg.idx = fq->flowid; /* ignored */
14324cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_GET_QUEUE(dev, child, &cmd, &queue_cfg);
1433ba7319e9SDmitry Salychev 	if (error) {
1434ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to obtain RxErr queue "
1435ba7319e9SDmitry Salychev 		    "configuration\n", __func__);
14364cd96614SDmitry Salychev 		goto close_ni;
1437ba7319e9SDmitry Salychev 	}
1438ba7319e9SDmitry Salychev 
1439ba7319e9SDmitry Salychev 	fq->fqid = queue_cfg.fqid;
1440ba7319e9SDmitry Salychev 
1441ba7319e9SDmitry Salychev 	queue_cfg.dest_id = con_info->id;
1442ba7319e9SDmitry Salychev 	queue_cfg.dest_type = DPAA2_NI_DEST_DPCON;
1443ba7319e9SDmitry Salychev 	queue_cfg.priority = 1;
1444ba7319e9SDmitry Salychev 	queue_cfg.user_ctx = (uint64_t)(uintmax_t) fq;
1445ba7319e9SDmitry Salychev 	queue_cfg.options =
1446ba7319e9SDmitry Salychev 	    DPAA2_NI_QUEUE_OPT_USER_CTX |
1447ba7319e9SDmitry Salychev 	    DPAA2_NI_QUEUE_OPT_DEST;
14484cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_QUEUE(dev, child, &cmd, &queue_cfg);
1449ba7319e9SDmitry Salychev 	if (error) {
1450ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to update RxErr queue "
1451ba7319e9SDmitry Salychev 		    "configuration\n", __func__);
14524cd96614SDmitry Salychev 		goto close_ni;
1453ba7319e9SDmitry Salychev 	}
1454ba7319e9SDmitry Salychev 
14554cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
14564cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
1457ba7319e9SDmitry Salychev 	return (0);
14584cd96614SDmitry Salychev 
14594cd96614SDmitry Salychev close_ni:
14604cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
14614cd96614SDmitry Salychev close_rc:
14624cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
14634cd96614SDmitry Salychev err_exit:
14644cd96614SDmitry Salychev 	return (error);
1465ba7319e9SDmitry Salychev }
1466ba7319e9SDmitry Salychev 
1467ba7319e9SDmitry Salychev /**
1468ba7319e9SDmitry Salychev  * @brief Configure DPNI object to generate interrupts.
1469ba7319e9SDmitry Salychev  */
1470ba7319e9SDmitry Salychev static int
1471ba7319e9SDmitry Salychev dpaa2_ni_setup_irqs(device_t dev)
1472ba7319e9SDmitry Salychev {
14734cd96614SDmitry Salychev 	device_t pdev = device_get_parent(dev);
1474ba7319e9SDmitry Salychev 	device_t child = dev;
1475ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
14764cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
14774cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
14784cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
14794cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
1480ba7319e9SDmitry Salychev 	int error;
1481ba7319e9SDmitry Salychev 
14824cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
14834cd96614SDmitry Salychev 
14844cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
14854cd96614SDmitry Salychev 	if (error) {
14864cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
14874cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
14884cd96614SDmitry Salychev 		goto err_exit;
14894cd96614SDmitry Salychev 	}
14904cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
14914cd96614SDmitry Salychev 	if (error) {
14924cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
14934cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
14944cd96614SDmitry Salychev 		goto close_rc;
14954cd96614SDmitry Salychev 	}
14964cd96614SDmitry Salychev 
1497ba7319e9SDmitry Salychev 	/* Configure IRQs. */
1498ba7319e9SDmitry Salychev 	error = dpaa2_ni_setup_msi(sc);
1499ba7319e9SDmitry Salychev 	if (error) {
1500ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to allocate MSI\n", __func__);
15014cd96614SDmitry Salychev 		goto close_ni;
1502ba7319e9SDmitry Salychev 	}
1503ba7319e9SDmitry Salychev 	if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
1504ba7319e9SDmitry Salychev 	    &sc->irq_rid[0], RF_ACTIVE | RF_SHAREABLE)) == NULL) {
1505ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to allocate IRQ resource\n",
1506ba7319e9SDmitry Salychev 		    __func__);
15074cd96614SDmitry Salychev 		goto close_ni;
1508ba7319e9SDmitry Salychev 	}
1509ba7319e9SDmitry Salychev 	if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE,
1510ba7319e9SDmitry Salychev 	    NULL, dpaa2_ni_intr, sc, &sc->intr)) {
1511ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to setup IRQ resource\n",
1512ba7319e9SDmitry Salychev 		    __func__);
15134cd96614SDmitry Salychev 		goto close_ni;
1514ba7319e9SDmitry Salychev 	}
1515ba7319e9SDmitry Salychev 
15164cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_IRQ_MASK(dev, child, &cmd, DPNI_IRQ_INDEX,
1517ba7319e9SDmitry Salychev 	    DPNI_IRQ_LINK_CHANGED | DPNI_IRQ_EP_CHANGED);
1518ba7319e9SDmitry Salychev 	if (error) {
1519ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to set DPNI IRQ mask\n",
1520ba7319e9SDmitry Salychev 		    __func__);
15214cd96614SDmitry Salychev 		goto close_ni;
1522ba7319e9SDmitry Salychev 	}
1523ba7319e9SDmitry Salychev 
15244cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_IRQ_ENABLE(dev, child, &cmd, DPNI_IRQ_INDEX,
1525ba7319e9SDmitry Salychev 	    true);
1526ba7319e9SDmitry Salychev 	if (error) {
1527ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to enable DPNI IRQ\n", __func__);
15284cd96614SDmitry Salychev 		goto close_ni;
1529ba7319e9SDmitry Salychev 	}
1530ba7319e9SDmitry Salychev 
15314cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
15324cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
1533ba7319e9SDmitry Salychev 	return (0);
15344cd96614SDmitry Salychev 
15354cd96614SDmitry Salychev close_ni:
15364cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
15374cd96614SDmitry Salychev close_rc:
15384cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
15394cd96614SDmitry Salychev err_exit:
15404cd96614SDmitry Salychev 	return (error);
1541ba7319e9SDmitry Salychev }
1542ba7319e9SDmitry Salychev 
1543ba7319e9SDmitry Salychev /**
1544ba7319e9SDmitry Salychev  * @brief Allocate MSI interrupts for DPNI.
1545ba7319e9SDmitry Salychev  */
1546ba7319e9SDmitry Salychev static int
1547ba7319e9SDmitry Salychev dpaa2_ni_setup_msi(struct dpaa2_ni_softc *sc)
1548ba7319e9SDmitry Salychev {
1549ba7319e9SDmitry Salychev 	int val;
1550ba7319e9SDmitry Salychev 
1551ba7319e9SDmitry Salychev 	val = pci_msi_count(sc->dev);
1552ba7319e9SDmitry Salychev 	if (val < DPAA2_NI_MSI_COUNT)
1553ba7319e9SDmitry Salychev 		device_printf(sc->dev, "MSI: actual=%d, expected=%d\n", val,
1554ba7319e9SDmitry Salychev 		    DPAA2_IO_MSI_COUNT);
1555ba7319e9SDmitry Salychev 	val = MIN(val, DPAA2_NI_MSI_COUNT);
1556ba7319e9SDmitry Salychev 
1557ba7319e9SDmitry Salychev 	if (pci_alloc_msi(sc->dev, &val) != 0)
1558ba7319e9SDmitry Salychev 		return (EINVAL);
1559ba7319e9SDmitry Salychev 
1560ba7319e9SDmitry Salychev 	for (int i = 0; i < val; i++)
1561ba7319e9SDmitry Salychev 		sc->irq_rid[i] = i + 1;
1562ba7319e9SDmitry Salychev 
1563ba7319e9SDmitry Salychev 	return (0);
1564ba7319e9SDmitry Salychev }
1565ba7319e9SDmitry Salychev 
1566ba7319e9SDmitry Salychev /**
1567ba7319e9SDmitry Salychev  * @brief Update DPNI according to the updated interface capabilities.
1568ba7319e9SDmitry Salychev  */
1569ba7319e9SDmitry Salychev static int
1570ba7319e9SDmitry Salychev dpaa2_ni_setup_if_caps(struct dpaa2_ni_softc *sc)
1571ba7319e9SDmitry Salychev {
1572d936c29eSJustin Hibbits 	const bool en_rxcsum = if_getcapenable(sc->ifp) & IFCAP_RXCSUM;
1573d936c29eSJustin Hibbits 	const bool en_txcsum = if_getcapenable(sc->ifp) & IFCAP_TXCSUM;
15744cd96614SDmitry Salychev 	device_t pdev = device_get_parent(sc->dev);
1575ba7319e9SDmitry Salychev 	device_t dev = sc->dev;
1576ba7319e9SDmitry Salychev 	device_t child = dev;
15774cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
15784cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
15794cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
15804cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
1581ba7319e9SDmitry Salychev 	int error;
1582ba7319e9SDmitry Salychev 
15834cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
15844cd96614SDmitry Salychev 
15854cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
15864cd96614SDmitry Salychev 	if (error) {
15874cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
15884cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
15894cd96614SDmitry Salychev 		goto err_exit;
15904cd96614SDmitry Salychev 	}
15914cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
15924cd96614SDmitry Salychev 	if (error) {
15934cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
15944cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
15954cd96614SDmitry Salychev 		goto close_rc;
15964cd96614SDmitry Salychev 	}
15974cd96614SDmitry Salychev 
1598ba7319e9SDmitry Salychev 	/* Setup checksums validation. */
15994cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_OFFLOAD(dev, child, &cmd,
16004cd96614SDmitry Salychev 	    DPAA2_NI_OFL_RX_L3_CSUM, en_rxcsum);
1601ba7319e9SDmitry Salychev 	if (error) {
1602ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to %s L3 checksum validation\n",
1603ba7319e9SDmitry Salychev 		    __func__, en_rxcsum ? "enable" : "disable");
16044cd96614SDmitry Salychev 		goto close_ni;
1605ba7319e9SDmitry Salychev 	}
16064cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_OFFLOAD(dev, child, &cmd,
1607ba7319e9SDmitry Salychev 	    DPAA2_NI_OFL_RX_L4_CSUM, en_rxcsum);
1608ba7319e9SDmitry Salychev 	if (error) {
1609ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to %s L4 checksum validation\n",
1610ba7319e9SDmitry Salychev 		    __func__, en_rxcsum ? "enable" : "disable");
16114cd96614SDmitry Salychev 		goto close_ni;
1612ba7319e9SDmitry Salychev 	}
1613ba7319e9SDmitry Salychev 
1614ba7319e9SDmitry Salychev 	/* Setup checksums generation. */
16154cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_OFFLOAD(dev, child, &cmd,
1616ba7319e9SDmitry Salychev 	    DPAA2_NI_OFL_TX_L3_CSUM, en_txcsum);
1617ba7319e9SDmitry Salychev 	if (error) {
1618ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to %s L3 checksum generation\n",
1619ba7319e9SDmitry Salychev 		    __func__, en_txcsum ? "enable" : "disable");
16204cd96614SDmitry Salychev 		goto close_ni;
1621ba7319e9SDmitry Salychev 	}
16224cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_OFFLOAD(dev, child, &cmd,
1623ba7319e9SDmitry Salychev 	    DPAA2_NI_OFL_TX_L4_CSUM, en_txcsum);
1624ba7319e9SDmitry Salychev 	if (error) {
1625ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to %s L4 checksum generation\n",
1626ba7319e9SDmitry Salychev 		    __func__, en_txcsum ? "enable" : "disable");
16274cd96614SDmitry Salychev 		goto close_ni;
1628ba7319e9SDmitry Salychev 	}
1629ba7319e9SDmitry Salychev 
16304cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, &cmd);
16314cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
1632ba7319e9SDmitry Salychev 	return (0);
16334cd96614SDmitry Salychev 
16344cd96614SDmitry Salychev close_ni:
16354cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
16364cd96614SDmitry Salychev close_rc:
16374cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
16384cd96614SDmitry Salychev err_exit:
16394cd96614SDmitry Salychev 	return (error);
1640ba7319e9SDmitry Salychev }
1641ba7319e9SDmitry Salychev 
1642ba7319e9SDmitry Salychev /**
1643ba7319e9SDmitry Salychev  * @brief Update DPNI according to the updated interface flags.
1644ba7319e9SDmitry Salychev  */
1645ba7319e9SDmitry Salychev static int
1646ba7319e9SDmitry Salychev dpaa2_ni_setup_if_flags(struct dpaa2_ni_softc *sc)
1647ba7319e9SDmitry Salychev {
1648d936c29eSJustin Hibbits 	const bool en_promisc = if_getflags(sc->ifp) & IFF_PROMISC;
1649d936c29eSJustin Hibbits 	const bool en_allmulti = if_getflags(sc->ifp) & IFF_ALLMULTI;
16504cd96614SDmitry Salychev 	device_t pdev = device_get_parent(sc->dev);
1651ba7319e9SDmitry Salychev 	device_t dev = sc->dev;
1652ba7319e9SDmitry Salychev 	device_t child = dev;
16534cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
16544cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
16554cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
16564cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
1657ba7319e9SDmitry Salychev 	int error;
1658ba7319e9SDmitry Salychev 
16594cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
16604cd96614SDmitry Salychev 
16614cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
16624cd96614SDmitry Salychev 	if (error) {
16634cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
16644cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
16654cd96614SDmitry Salychev 		goto err_exit;
16664cd96614SDmitry Salychev 	}
16674cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
16684cd96614SDmitry Salychev 	if (error) {
16694cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
16704cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
16714cd96614SDmitry Salychev 		goto close_rc;
16724cd96614SDmitry Salychev 	}
16734cd96614SDmitry Salychev 
16744cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_MULTI_PROMISC(dev, child, &cmd,
16754cd96614SDmitry Salychev 	    en_promisc ? true : en_allmulti);
1676ba7319e9SDmitry Salychev 	if (error) {
1677ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to %s multicast promiscuous "
1678ba7319e9SDmitry Salychev 		    "mode\n", __func__, en_allmulti ? "enable" : "disable");
16794cd96614SDmitry Salychev 		goto close_ni;
1680ba7319e9SDmitry Salychev 	}
1681ba7319e9SDmitry Salychev 
16824cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_UNI_PROMISC(dev, child, &cmd, en_promisc);
1683ba7319e9SDmitry Salychev 	if (error) {
1684ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to %s unicast promiscuous mode\n",
1685ba7319e9SDmitry Salychev 		    __func__, en_promisc ? "enable" : "disable");
16864cd96614SDmitry Salychev 		goto close_ni;
1687ba7319e9SDmitry Salychev 	}
1688ba7319e9SDmitry Salychev 
16894cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, &cmd);
16904cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
1691ba7319e9SDmitry Salychev 	return (0);
16924cd96614SDmitry Salychev 
16934cd96614SDmitry Salychev close_ni:
16944cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
16954cd96614SDmitry Salychev close_rc:
16964cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
16974cd96614SDmitry Salychev err_exit:
16984cd96614SDmitry Salychev 	return (error);
1699ba7319e9SDmitry Salychev }
1700ba7319e9SDmitry Salychev 
1701ba7319e9SDmitry Salychev static int
1702ba7319e9SDmitry Salychev dpaa2_ni_setup_sysctls(struct dpaa2_ni_softc *sc)
1703ba7319e9SDmitry Salychev {
1704ba7319e9SDmitry Salychev 	struct sysctl_ctx_list *ctx;
1705ba7319e9SDmitry Salychev 	struct sysctl_oid *node, *node2;
1706ba7319e9SDmitry Salychev 	struct sysctl_oid_list *parent, *parent2;
1707ba7319e9SDmitry Salychev 	char cbuf[128];
1708ba7319e9SDmitry Salychev 	int i;
1709ba7319e9SDmitry Salychev 
1710ba7319e9SDmitry Salychev 	ctx = device_get_sysctl_ctx(sc->dev);
1711ba7319e9SDmitry Salychev 	parent = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
1712ba7319e9SDmitry Salychev 
1713ba7319e9SDmitry Salychev 	/* Add DPNI statistics. */
1714ba7319e9SDmitry Salychev 	node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "stats",
1715ba7319e9SDmitry Salychev 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "DPNI Statistics");
1716ba7319e9SDmitry Salychev 	parent = SYSCTL_CHILDREN(node);
1717ba7319e9SDmitry Salychev 	for (i = 0; i < DPAA2_NI_STAT_SYSCTLS; ++i) {
1718ba7319e9SDmitry Salychev 		SYSCTL_ADD_PROC(ctx, parent, i, dpni_stat_sysctls[i].name,
1719ba7319e9SDmitry Salychev 		    CTLTYPE_U64 | CTLFLAG_RD, sc, 0, dpaa2_ni_collect_stats,
1720ba7319e9SDmitry Salychev 		    "IU", dpni_stat_sysctls[i].desc);
1721ba7319e9SDmitry Salychev 	}
1722ba7319e9SDmitry Salychev 	SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "rx_anomaly_frames",
1723ba7319e9SDmitry Salychev 	    CTLFLAG_RD, &sc->rx_anomaly_frames,
1724ba7319e9SDmitry Salychev 	    "Rx frames in the buffers outside of the buffer pools");
1725ba7319e9SDmitry Salychev 	SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "rx_single_buf_frames",
1726ba7319e9SDmitry Salychev 	    CTLFLAG_RD, &sc->rx_single_buf_frames,
1727ba7319e9SDmitry Salychev 	    "Rx frames in single buffers");
1728ba7319e9SDmitry Salychev 	SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "rx_sg_buf_frames",
1729ba7319e9SDmitry Salychev 	    CTLFLAG_RD, &sc->rx_sg_buf_frames,
1730ba7319e9SDmitry Salychev 	    "Rx frames in scatter/gather list");
1731ba7319e9SDmitry Salychev 	SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "rx_enq_rej_frames",
1732ba7319e9SDmitry Salychev 	    CTLFLAG_RD, &sc->rx_enq_rej_frames,
1733ba7319e9SDmitry Salychev 	    "Enqueue rejected by QMan");
1734ba7319e9SDmitry Salychev 	SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "rx_ieoi_err_frames",
1735ba7319e9SDmitry Salychev 	    CTLFLAG_RD, &sc->rx_ieoi_err_frames,
1736ba7319e9SDmitry Salychev 	    "QMan IEOI error");
1737ba7319e9SDmitry Salychev 	SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "tx_single_buf_frames",
1738ba7319e9SDmitry Salychev 	    CTLFLAG_RD, &sc->tx_single_buf_frames,
1739ba7319e9SDmitry Salychev 	    "Tx single buffer frames");
1740ba7319e9SDmitry Salychev 	SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "tx_sg_frames",
1741ba7319e9SDmitry Salychev 	    CTLFLAG_RD, &sc->tx_sg_frames,
1742ba7319e9SDmitry Salychev 	    "Tx S/G frames");
1743ba7319e9SDmitry Salychev 
1744ba7319e9SDmitry Salychev 	SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, "buf_num",
1745ba7319e9SDmitry Salychev 	    CTLTYPE_U32 | CTLFLAG_RD, sc, 0, dpaa2_ni_collect_buf_num,
1746ba7319e9SDmitry Salychev 	    "IU", "number of Rx buffers in the buffer pool");
1747ba7319e9SDmitry Salychev 	SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, "buf_free",
1748ba7319e9SDmitry Salychev 	    CTLTYPE_U32 | CTLFLAG_RD, sc, 0, dpaa2_ni_collect_buf_free,
1749ba7319e9SDmitry Salychev 	    "IU", "number of free Rx buffers in the buffer pool");
1750ba7319e9SDmitry Salychev 
1751ba7319e9SDmitry Salychev  	parent = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
1752ba7319e9SDmitry Salychev 
1753ba7319e9SDmitry Salychev 	/* Add channels statistics. */
1754ba7319e9SDmitry Salychev 	node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "channels",
1755ba7319e9SDmitry Salychev 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "DPNI Channels");
1756ba7319e9SDmitry Salychev 	parent = SYSCTL_CHILDREN(node);
1757ba7319e9SDmitry Salychev 	for (int i = 0; i < sc->chan_n; i++) {
1758ba7319e9SDmitry Salychev 		snprintf(cbuf, sizeof(cbuf), "%d", i);
1759ba7319e9SDmitry Salychev 
1760ba7319e9SDmitry Salychev 		node2 = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, cbuf,
1761ba7319e9SDmitry Salychev 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "DPNI Channel");
1762ba7319e9SDmitry Salychev 		parent2 = SYSCTL_CHILDREN(node2);
1763ba7319e9SDmitry Salychev 
1764ba7319e9SDmitry Salychev 		SYSCTL_ADD_UQUAD(ctx, parent2, OID_AUTO, "tx_frames",
1765ba7319e9SDmitry Salychev 		    CTLFLAG_RD, &sc->channels[i]->tx_frames,
1766ba7319e9SDmitry Salychev 		    "Tx frames counter");
1767ba7319e9SDmitry Salychev 		SYSCTL_ADD_UQUAD(ctx, parent2, OID_AUTO, "tx_dropped",
1768ba7319e9SDmitry Salychev 		    CTLFLAG_RD, &sc->channels[i]->tx_dropped,
1769ba7319e9SDmitry Salychev 		    "Tx dropped counter");
1770ba7319e9SDmitry Salychev 	}
1771ba7319e9SDmitry Salychev 
1772ba7319e9SDmitry Salychev 	return (0);
1773ba7319e9SDmitry Salychev }
1774ba7319e9SDmitry Salychev 
1775ba7319e9SDmitry Salychev static int
1776ba7319e9SDmitry Salychev dpaa2_ni_setup_dma(struct dpaa2_ni_softc *sc)
1777ba7319e9SDmitry Salychev {
1778ba7319e9SDmitry Salychev 	device_t dev = sc->dev;
1779ba7319e9SDmitry Salychev 	int error;
1780ba7319e9SDmitry Salychev 
1781ba7319e9SDmitry Salychev 	KASSERT((sc->buf_align == BUF_ALIGN) || (sc->buf_align == BUF_ALIGN_V1),
1782ba7319e9SDmitry Salychev 	    ("unexpected buffer alignment: %d\n", sc->buf_align));
1783ba7319e9SDmitry Salychev 
1784ba7319e9SDmitry Salychev 	/* DMA tag for Rx distribution key. */
1785ba7319e9SDmitry Salychev 	error = bus_dma_tag_create(
1786ba7319e9SDmitry Salychev 	    bus_get_dma_tag(dev),
1787ba7319e9SDmitry Salychev 	    PAGE_SIZE, 0,		/* alignment, boundary */
1788718bdb6aSDmitry Salychev 	    BUS_SPACE_MAXADDR,		/* low restricted addr */
1789ba7319e9SDmitry Salychev 	    BUS_SPACE_MAXADDR,		/* high restricted addr */
1790ba7319e9SDmitry Salychev 	    NULL, NULL,			/* filter, filterarg */
1791ba7319e9SDmitry Salychev 	    DPAA2_CLASSIFIER_DMA_SIZE, 1, /* maxsize, nsegments */
1792ba7319e9SDmitry Salychev 	    DPAA2_CLASSIFIER_DMA_SIZE, 0, /* maxsegsize, flags */
1793ba7319e9SDmitry Salychev 	    NULL, NULL,			/* lockfunc, lockarg */
1794ba7319e9SDmitry Salychev 	    &sc->rxd_dmat);
1795ba7319e9SDmitry Salychev 	if (error) {
1796ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to create DMA tag for Rx "
1797ba7319e9SDmitry Salychev 		    "distribution key\n", __func__);
1798ba7319e9SDmitry Salychev 		return (error);
1799ba7319e9SDmitry Salychev 	}
1800ba7319e9SDmitry Salychev 
1801ba7319e9SDmitry Salychev 	error = bus_dma_tag_create(
1802ba7319e9SDmitry Salychev 	    bus_get_dma_tag(dev),
1803ba7319e9SDmitry Salychev 	    PAGE_SIZE, 0,		/* alignment, boundary */
1804718bdb6aSDmitry Salychev 	    BUS_SPACE_MAXADDR,		/* low restricted addr */
1805ba7319e9SDmitry Salychev 	    BUS_SPACE_MAXADDR,		/* high restricted addr */
1806ba7319e9SDmitry Salychev 	    NULL, NULL,			/* filter, filterarg */
1807ba7319e9SDmitry Salychev 	    ETH_QOS_KCFG_BUF_SIZE, 1,	/* maxsize, nsegments */
1808ba7319e9SDmitry Salychev 	    ETH_QOS_KCFG_BUF_SIZE, 0,	/* maxsegsize, flags */
1809ba7319e9SDmitry Salychev 	    NULL, NULL,			/* lockfunc, lockarg */
1810ba7319e9SDmitry Salychev 	    &sc->qos_dmat);
1811ba7319e9SDmitry Salychev 	if (error) {
1812ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to create DMA tag for QoS key\n",
1813ba7319e9SDmitry Salychev 		    __func__);
1814ba7319e9SDmitry Salychev 		return (error);
1815ba7319e9SDmitry Salychev 	}
1816ba7319e9SDmitry Salychev 
1817ba7319e9SDmitry Salychev 	return (0);
1818ba7319e9SDmitry Salychev }
1819ba7319e9SDmitry Salychev 
1820ba7319e9SDmitry Salychev /**
1821ba7319e9SDmitry Salychev  * @brief Configure buffer layouts of the different DPNI queues.
1822ba7319e9SDmitry Salychev  */
1823ba7319e9SDmitry Salychev static int
18244cd96614SDmitry Salychev dpaa2_ni_set_buf_layout(device_t dev)
1825ba7319e9SDmitry Salychev {
18264cd96614SDmitry Salychev 	device_t pdev = device_get_parent(dev);
1827ba7319e9SDmitry Salychev 	device_t child = dev;
18284cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
18294cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
1830ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
1831ba7319e9SDmitry Salychev 	struct dpaa2_ni_buf_layout buf_layout = {0};
18324cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
18334cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
1834ba7319e9SDmitry Salychev 	int error;
1835ba7319e9SDmitry Salychev 
18364cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
18374cd96614SDmitry Salychev 
18384cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
18394cd96614SDmitry Salychev 	if (error) {
18404cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
18414cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
18424cd96614SDmitry Salychev 		goto err_exit;
18434cd96614SDmitry Salychev 	}
18444cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
18454cd96614SDmitry Salychev 	if (error) {
18464cd96614SDmitry Salychev 		device_printf(sc->dev, "%s: failed to open DPMAC: id=%d, "
18474cd96614SDmitry Salychev 		    "error=%d\n", __func__, dinfo->id, error);
18484cd96614SDmitry Salychev 		goto close_rc;
18494cd96614SDmitry Salychev 	}
18504cd96614SDmitry Salychev 
1851ba7319e9SDmitry Salychev 	/*
1852ba7319e9SDmitry Salychev 	 * Select Rx/Tx buffer alignment. It's necessary to ensure that the
1853ba7319e9SDmitry Salychev 	 * buffer size seen by WRIOP is a multiple of 64 or 256 bytes depending
1854ba7319e9SDmitry Salychev 	 * on the WRIOP version.
1855ba7319e9SDmitry Salychev 	 */
1856ba7319e9SDmitry Salychev 	sc->buf_align = (sc->attr.wriop_ver == WRIOP_VERSION(0, 0, 0) ||
1857ba7319e9SDmitry Salychev 	    sc->attr.wriop_ver == WRIOP_VERSION(1, 0, 0))
1858ba7319e9SDmitry Salychev 	    ? BUF_ALIGN_V1 : BUF_ALIGN;
1859ba7319e9SDmitry Salychev 
1860ba7319e9SDmitry Salychev 	/*
1861ba7319e9SDmitry Salychev 	 * We need to ensure that the buffer size seen by WRIOP is a multiple
1862ba7319e9SDmitry Salychev 	 * of 64 or 256 bytes depending on the WRIOP version.
1863ba7319e9SDmitry Salychev 	 */
186458983e4bSDmitry Salychev 	sc->buf_sz = ALIGN_DOWN(DPAA2_RX_BUF_SIZE, sc->buf_align);
1865ba7319e9SDmitry Salychev 
18664cd96614SDmitry Salychev 	if (bootverbose) {
1867ba7319e9SDmitry Salychev 		device_printf(dev, "Rx/Tx buffers: size=%d, alignment=%d\n",
1868ba7319e9SDmitry Salychev 		    sc->buf_sz, sc->buf_align);
18694cd96614SDmitry Salychev 	}
1870ba7319e9SDmitry Salychev 
1871ba7319e9SDmitry Salychev 	/*
1872ba7319e9SDmitry Salychev 	 *    Frame Descriptor       Tx buffer layout
1873ba7319e9SDmitry Salychev 	 *
1874ba7319e9SDmitry Salychev 	 *                ADDR -> |---------------------|
1875ba7319e9SDmitry Salychev 	 *                        | SW FRAME ANNOTATION | BUF_SWA_SIZE bytes
1876ba7319e9SDmitry Salychev 	 *                        |---------------------|
1877ba7319e9SDmitry Salychev 	 *                        | HW FRAME ANNOTATION | BUF_TX_HWA_SIZE bytes
1878ba7319e9SDmitry Salychev 	 *                        |---------------------|
1879ba7319e9SDmitry Salychev 	 *                        |    DATA HEADROOM    |
1880ba7319e9SDmitry Salychev 	 *       ADDR + OFFSET -> |---------------------|
1881ba7319e9SDmitry Salychev 	 *                        |                     |
1882ba7319e9SDmitry Salychev 	 *                        |                     |
1883ba7319e9SDmitry Salychev 	 *                        |     FRAME DATA      |
1884ba7319e9SDmitry Salychev 	 *                        |                     |
1885ba7319e9SDmitry Salychev 	 *                        |                     |
1886ba7319e9SDmitry Salychev 	 *                        |---------------------|
1887ba7319e9SDmitry Salychev 	 *                        |    DATA TAILROOM    |
1888ba7319e9SDmitry Salychev 	 *                        |---------------------|
1889ba7319e9SDmitry Salychev 	 *
1890ba7319e9SDmitry Salychev 	 * NOTE: It's for a single buffer frame only.
1891ba7319e9SDmitry Salychev 	 */
1892ba7319e9SDmitry Salychev 	buf_layout.queue_type = DPAA2_NI_QUEUE_TX;
1893ba7319e9SDmitry Salychev 	buf_layout.pd_size = BUF_SWA_SIZE;
1894ba7319e9SDmitry Salychev 	buf_layout.pass_timestamp = true;
1895ba7319e9SDmitry Salychev 	buf_layout.pass_frame_status = true;
1896ba7319e9SDmitry Salychev 	buf_layout.options =
1897ba7319e9SDmitry Salychev 	    BUF_LOPT_PRIV_DATA_SZ |
1898ba7319e9SDmitry Salychev 	    BUF_LOPT_TIMESTAMP | /* requires 128 bytes in HWA */
1899ba7319e9SDmitry Salychev 	    BUF_LOPT_FRAME_STATUS;
19004cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_BUF_LAYOUT(dev, child, &cmd, &buf_layout);
1901ba7319e9SDmitry Salychev 	if (error) {
1902ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to set Tx buffer layout\n",
1903ba7319e9SDmitry Salychev 		    __func__);
19044cd96614SDmitry Salychev 		goto close_ni;
1905ba7319e9SDmitry Salychev 	}
1906ba7319e9SDmitry Salychev 
1907ba7319e9SDmitry Salychev 	/* Tx-confirmation buffer layout */
1908ba7319e9SDmitry Salychev 	buf_layout.queue_type = DPAA2_NI_QUEUE_TX_CONF;
1909ba7319e9SDmitry Salychev 	buf_layout.options =
1910ba7319e9SDmitry Salychev 	    BUF_LOPT_TIMESTAMP |
1911ba7319e9SDmitry Salychev 	    BUF_LOPT_FRAME_STATUS;
19124cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_BUF_LAYOUT(dev, child, &cmd, &buf_layout);
1913ba7319e9SDmitry Salychev 	if (error) {
1914ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to set TxConf buffer layout\n",
1915ba7319e9SDmitry Salychev 		    __func__);
19164cd96614SDmitry Salychev 		goto close_ni;
1917ba7319e9SDmitry Salychev 	}
1918ba7319e9SDmitry Salychev 
1919ba7319e9SDmitry Salychev 	/*
1920ba7319e9SDmitry Salychev 	 * Driver should reserve the amount of space indicated by this command
1921ba7319e9SDmitry Salychev 	 * as headroom in all Tx frames.
1922ba7319e9SDmitry Salychev 	 */
19234cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_GET_TX_DATA_OFF(dev, child, &cmd, &sc->tx_data_off);
1924ba7319e9SDmitry Salychev 	if (error) {
1925ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to obtain Tx data offset\n",
1926ba7319e9SDmitry Salychev 		    __func__);
19274cd96614SDmitry Salychev 		goto close_ni;
1928ba7319e9SDmitry Salychev 	}
1929ba7319e9SDmitry Salychev 
19304cd96614SDmitry Salychev 	if (bootverbose) {
1931ba7319e9SDmitry Salychev 		device_printf(dev, "Tx data offset=%d\n", sc->tx_data_off);
19324cd96614SDmitry Salychev 	}
19334cd96614SDmitry Salychev 	if ((sc->tx_data_off % 64) != 0) {
1934ba7319e9SDmitry Salychev 		device_printf(dev, "Tx data offset (%d) is not a multiplication "
1935ba7319e9SDmitry Salychev 		    "of 64 bytes\n", sc->tx_data_off);
19364cd96614SDmitry Salychev 	}
1937ba7319e9SDmitry Salychev 
1938ba7319e9SDmitry Salychev 	/*
1939ba7319e9SDmitry Salychev 	 *    Frame Descriptor       Rx buffer layout
1940ba7319e9SDmitry Salychev 	 *
1941ba7319e9SDmitry Salychev 	 *                ADDR -> |---------------------|
1942718bdb6aSDmitry Salychev 	 *                        | SW FRAME ANNOTATION | BUF_SWA_SIZE bytes
1943ba7319e9SDmitry Salychev 	 *                        |---------------------|
1944ba7319e9SDmitry Salychev 	 *                        | HW FRAME ANNOTATION | BUF_RX_HWA_SIZE bytes
1945ba7319e9SDmitry Salychev 	 *                        |---------------------|
1946ba7319e9SDmitry Salychev 	 *                        |    DATA HEADROOM    | OFFSET-BUF_RX_HWA_SIZE
1947ba7319e9SDmitry Salychev 	 *       ADDR + OFFSET -> |---------------------|
1948ba7319e9SDmitry Salychev 	 *                        |                     |
1949ba7319e9SDmitry Salychev 	 *                        |                     |
1950ba7319e9SDmitry Salychev 	 *                        |     FRAME DATA      |
1951ba7319e9SDmitry Salychev 	 *                        |                     |
1952ba7319e9SDmitry Salychev 	 *                        |                     |
1953ba7319e9SDmitry Salychev 	 *                        |---------------------|
1954ba7319e9SDmitry Salychev 	 *                        |    DATA TAILROOM    | 0 bytes
1955ba7319e9SDmitry Salychev 	 *                        |---------------------|
1956ba7319e9SDmitry Salychev 	 *
1957ba7319e9SDmitry Salychev 	 * NOTE: It's for a single buffer frame only.
1958ba7319e9SDmitry Salychev 	 */
1959ba7319e9SDmitry Salychev 	buf_layout.queue_type = DPAA2_NI_QUEUE_RX;
1960718bdb6aSDmitry Salychev 	buf_layout.pd_size = BUF_SWA_SIZE;
1961ba7319e9SDmitry Salychev 	buf_layout.fd_align = sc->buf_align;
1962718bdb6aSDmitry Salychev 	buf_layout.head_size = sc->tx_data_off - BUF_RX_HWA_SIZE - BUF_SWA_SIZE;
1963ba7319e9SDmitry Salychev 	buf_layout.tail_size = 0;
1964ba7319e9SDmitry Salychev 	buf_layout.pass_frame_status = true;
1965ba7319e9SDmitry Salychev 	buf_layout.pass_parser_result = true;
1966ba7319e9SDmitry Salychev 	buf_layout.pass_timestamp = true;
1967ba7319e9SDmitry Salychev 	buf_layout.options =
1968ba7319e9SDmitry Salychev 	    BUF_LOPT_PRIV_DATA_SZ |
1969ba7319e9SDmitry Salychev 	    BUF_LOPT_DATA_ALIGN |
1970ba7319e9SDmitry Salychev 	    BUF_LOPT_DATA_HEAD_ROOM |
1971ba7319e9SDmitry Salychev 	    BUF_LOPT_DATA_TAIL_ROOM |
1972ba7319e9SDmitry Salychev 	    BUF_LOPT_FRAME_STATUS |
1973ba7319e9SDmitry Salychev 	    BUF_LOPT_PARSER_RESULT |
1974ba7319e9SDmitry Salychev 	    BUF_LOPT_TIMESTAMP;
19754cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_BUF_LAYOUT(dev, child, &cmd, &buf_layout);
1976ba7319e9SDmitry Salychev 	if (error) {
1977ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to set Rx buffer layout\n",
1978ba7319e9SDmitry Salychev 		    __func__);
19794cd96614SDmitry Salychev 		goto close_ni;
1980ba7319e9SDmitry Salychev 	}
1981ba7319e9SDmitry Salychev 
19824cd96614SDmitry Salychev 	error = 0;
19834cd96614SDmitry Salychev close_ni:
19844cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
19854cd96614SDmitry Salychev close_rc:
19864cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
19874cd96614SDmitry Salychev err_exit:
19884cd96614SDmitry Salychev 	return (error);
1989ba7319e9SDmitry Salychev }
1990ba7319e9SDmitry Salychev 
1991ba7319e9SDmitry Salychev /**
1992ba7319e9SDmitry Salychev  * @brief Enable Rx/Tx pause frames.
1993ba7319e9SDmitry Salychev  *
1994ba7319e9SDmitry Salychev  * NOTE: DPNI stops sending when a pause frame is received (Rx frame) or DPNI
1995ba7319e9SDmitry Salychev  *       itself generates pause frames (Tx frame).
1996ba7319e9SDmitry Salychev  */
1997ba7319e9SDmitry Salychev static int
19984cd96614SDmitry Salychev dpaa2_ni_set_pause_frame(device_t dev)
1999ba7319e9SDmitry Salychev {
20004cd96614SDmitry Salychev 	device_t pdev = device_get_parent(dev);
2001ba7319e9SDmitry Salychev 	device_t child = dev;
20024cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
20034cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
2004ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
2005ba7319e9SDmitry Salychev 	struct dpaa2_ni_link_cfg link_cfg = {0};
20064cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
20074cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
2008ba7319e9SDmitry Salychev 	int error;
2009ba7319e9SDmitry Salychev 
20104cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
20114cd96614SDmitry Salychev 
20124cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
20134cd96614SDmitry Salychev 	if (error) {
20144cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
20154cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
20164cd96614SDmitry Salychev 		goto err_exit;
20174cd96614SDmitry Salychev 	}
20184cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
20194cd96614SDmitry Salychev 	if (error) {
20204cd96614SDmitry Salychev 		device_printf(sc->dev, "%s: failed to open DPMAC: id=%d, "
20214cd96614SDmitry Salychev 		    "error=%d\n", __func__, dinfo->id, error);
20224cd96614SDmitry Salychev 		goto close_rc;
20234cd96614SDmitry Salychev 	}
20244cd96614SDmitry Salychev 
20254cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_GET_LINK_CFG(dev, child, &cmd, &link_cfg);
2026ba7319e9SDmitry Salychev 	if (error) {
2027ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to obtain link configuration: "
2028ba7319e9SDmitry Salychev 		    "error=%d\n", __func__, error);
20294cd96614SDmitry Salychev 		goto close_ni;
2030ba7319e9SDmitry Salychev 	}
2031ba7319e9SDmitry Salychev 
2032ba7319e9SDmitry Salychev 	/* Enable both Rx and Tx pause frames by default. */
2033ba7319e9SDmitry Salychev 	link_cfg.options |= DPAA2_NI_LINK_OPT_PAUSE;
2034ba7319e9SDmitry Salychev 	link_cfg.options &= ~DPAA2_NI_LINK_OPT_ASYM_PAUSE;
2035ba7319e9SDmitry Salychev 
20364cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_LINK_CFG(dev, child, &cmd, &link_cfg);
2037ba7319e9SDmitry Salychev 	if (error) {
2038ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to set link configuration: "
2039ba7319e9SDmitry Salychev 		    "error=%d\n", __func__, error);
20404cd96614SDmitry Salychev 		goto close_ni;
2041ba7319e9SDmitry Salychev 	}
2042ba7319e9SDmitry Salychev 
2043ba7319e9SDmitry Salychev 	sc->link_options = link_cfg.options;
20444cd96614SDmitry Salychev 	error = 0;
20454cd96614SDmitry Salychev close_ni:
20464cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
20474cd96614SDmitry Salychev close_rc:
20484cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
20494cd96614SDmitry Salychev err_exit:
20504cd96614SDmitry Salychev 	return (error);
2051ba7319e9SDmitry Salychev }
2052ba7319e9SDmitry Salychev 
2053ba7319e9SDmitry Salychev /**
2054ba7319e9SDmitry Salychev  * @brief Configure QoS table to determine the traffic class for the received
2055ba7319e9SDmitry Salychev  * frame.
2056ba7319e9SDmitry Salychev  */
2057ba7319e9SDmitry Salychev static int
20584cd96614SDmitry Salychev dpaa2_ni_set_qos_table(device_t dev)
2059ba7319e9SDmitry Salychev {
20604cd96614SDmitry Salychev 	device_t pdev = device_get_parent(dev);
2061ba7319e9SDmitry Salychev 	device_t child = dev;
20624cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
20634cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
2064ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
2065ba7319e9SDmitry Salychev 	struct dpaa2_ni_qos_table tbl;
2066ba7319e9SDmitry Salychev 	struct dpaa2_buf *buf = &sc->qos_kcfg;
20674cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
20684cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
2069ba7319e9SDmitry Salychev 	int error;
2070ba7319e9SDmitry Salychev 
2071ba7319e9SDmitry Salychev 	if (sc->attr.num.rx_tcs == 1 ||
2072ba7319e9SDmitry Salychev 	    !(sc->attr.options & DPNI_OPT_HAS_KEY_MASKING)) {
20734cd96614SDmitry Salychev 		if (bootverbose) {
2074ba7319e9SDmitry Salychev 			device_printf(dev, "Ingress traffic classification is "
2075ba7319e9SDmitry Salychev 			    "not supported\n");
20764cd96614SDmitry Salychev 		}
2077ba7319e9SDmitry Salychev 		return (0);
2078ba7319e9SDmitry Salychev 	}
2079ba7319e9SDmitry Salychev 
2080ba7319e9SDmitry Salychev 	/*
2081ba7319e9SDmitry Salychev 	 * Allocate a buffer visible to the device to hold the QoS table key
2082ba7319e9SDmitry Salychev 	 * configuration.
2083ba7319e9SDmitry Salychev 	 */
208458983e4bSDmitry Salychev 
208558983e4bSDmitry Salychev 	if (__predict_true(buf->dmat == NULL)) {
208658983e4bSDmitry Salychev 		buf->dmat = sc->qos_dmat;
20874cd96614SDmitry Salychev 	}
2088ba7319e9SDmitry Salychev 
208958983e4bSDmitry Salychev 	error = bus_dmamem_alloc(buf->dmat, (void **)&buf->vaddr,
209058983e4bSDmitry Salychev 	    BUS_DMA_ZERO | BUS_DMA_COHERENT, &buf->dmap);
2091ba7319e9SDmitry Salychev 	if (error) {
2092ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to allocate a buffer for QoS key "
2093ba7319e9SDmitry Salychev 		    "configuration\n", __func__);
20944cd96614SDmitry Salychev 		goto err_exit;
2095ba7319e9SDmitry Salychev 	}
2096ba7319e9SDmitry Salychev 
209758983e4bSDmitry Salychev 	error = bus_dmamap_load(buf->dmat, buf->dmap, buf->vaddr,
209858983e4bSDmitry Salychev 	    ETH_QOS_KCFG_BUF_SIZE, dpaa2_dmamap_oneseg_cb, &buf->paddr,
209958983e4bSDmitry Salychev 	    BUS_DMA_NOWAIT);
2100ba7319e9SDmitry Salychev 	if (error) {
2101ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to map QoS key configuration "
2102ba7319e9SDmitry Salychev 		    "buffer into bus space\n", __func__);
21034cd96614SDmitry Salychev 		goto err_exit;
21044cd96614SDmitry Salychev 	}
21054cd96614SDmitry Salychev 
21064cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
21074cd96614SDmitry Salychev 
21084cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
21094cd96614SDmitry Salychev 	if (error) {
21104cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
21114cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
21124cd96614SDmitry Salychev 		goto err_exit;
21134cd96614SDmitry Salychev 	}
21144cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
21154cd96614SDmitry Salychev 	if (error) {
21164cd96614SDmitry Salychev 		device_printf(sc->dev, "%s: failed to open DPMAC: id=%d, "
21174cd96614SDmitry Salychev 		    "error=%d\n", __func__, dinfo->id, error);
21184cd96614SDmitry Salychev 		goto close_rc;
2119ba7319e9SDmitry Salychev 	}
2120ba7319e9SDmitry Salychev 
2121ba7319e9SDmitry Salychev 	tbl.default_tc = 0;
2122ba7319e9SDmitry Salychev 	tbl.discard_on_miss = false;
2123ba7319e9SDmitry Salychev 	tbl.keep_entries = false;
212458983e4bSDmitry Salychev 	tbl.kcfg_busaddr = buf->paddr;
21254cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_SET_QOS_TABLE(dev, child, &cmd, &tbl);
2126ba7319e9SDmitry Salychev 	if (error) {
2127ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to set QoS table\n", __func__);
21284cd96614SDmitry Salychev 		goto close_ni;
2129ba7319e9SDmitry Salychev 	}
2130ba7319e9SDmitry Salychev 
21314cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_CLEAR_QOS_TABLE(dev, child, &cmd);
2132ba7319e9SDmitry Salychev 	if (error) {
2133ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to clear QoS table\n", __func__);
21344cd96614SDmitry Salychev 		goto close_ni;
2135ba7319e9SDmitry Salychev 	}
2136ba7319e9SDmitry Salychev 
21374cd96614SDmitry Salychev 	error = 0;
21384cd96614SDmitry Salychev close_ni:
21394cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
21404cd96614SDmitry Salychev close_rc:
21414cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
21424cd96614SDmitry Salychev err_exit:
21434cd96614SDmitry Salychev 	return (error);
2144ba7319e9SDmitry Salychev }
2145ba7319e9SDmitry Salychev 
2146ba7319e9SDmitry Salychev static int
21474cd96614SDmitry Salychev dpaa2_ni_set_mac_addr(device_t dev)
2148ba7319e9SDmitry Salychev {
21494cd96614SDmitry Salychev 	device_t pdev = device_get_parent(dev);
2150ba7319e9SDmitry Salychev 	device_t child = dev;
2151ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
2152d936c29eSJustin Hibbits 	if_t ifp = sc->ifp;
21534cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
21544cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
21554cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
2156ba7319e9SDmitry Salychev 	struct ether_addr rnd_mac_addr;
21574cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
2158ba7319e9SDmitry Salychev 	uint8_t mac_addr[ETHER_ADDR_LEN];
2159ba7319e9SDmitry Salychev 	uint8_t dpni_mac_addr[ETHER_ADDR_LEN];
2160ba7319e9SDmitry Salychev 	int error;
2161ba7319e9SDmitry Salychev 
21624cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
21634cd96614SDmitry Salychev 
21644cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
21654cd96614SDmitry Salychev 	if (error) {
21664cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
21674cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
21684cd96614SDmitry Salychev 		goto err_exit;
21694cd96614SDmitry Salychev 	}
21704cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
21714cd96614SDmitry Salychev 	if (error) {
21724cd96614SDmitry Salychev 		device_printf(sc->dev, "%s: failed to open DPMAC: id=%d, "
21734cd96614SDmitry Salychev 		    "error=%d\n", __func__, dinfo->id, error);
21744cd96614SDmitry Salychev 		goto close_rc;
21754cd96614SDmitry Salychev 	}
21764cd96614SDmitry Salychev 
2177ba7319e9SDmitry Salychev 	/*
2178ba7319e9SDmitry Salychev 	 * Get the MAC address associated with the physical port, if the DPNI is
2179ba7319e9SDmitry Salychev 	 * connected to a DPMAC directly associated with one of the physical
2180ba7319e9SDmitry Salychev 	 * ports.
2181ba7319e9SDmitry Salychev 	 */
21824cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_GET_PORT_MAC_ADDR(dev, child, &cmd, mac_addr);
2183ba7319e9SDmitry Salychev 	if (error) {
2184ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to obtain the MAC address "
2185ba7319e9SDmitry Salychev 		    "associated with the physical port\n", __func__);
21864cd96614SDmitry Salychev 		goto close_ni;
2187ba7319e9SDmitry Salychev 	}
2188ba7319e9SDmitry Salychev 
2189ba7319e9SDmitry Salychev 	/* Get primary MAC address from the DPNI attributes. */
21904cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_GET_PRIM_MAC_ADDR(dev, child, &cmd, dpni_mac_addr);
2191ba7319e9SDmitry Salychev 	if (error) {
2192ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to obtain primary MAC address\n",
2193ba7319e9SDmitry Salychev 		    __func__);
21944cd96614SDmitry Salychev 		goto close_ni;
2195ba7319e9SDmitry Salychev 	}
2196ba7319e9SDmitry Salychev 
2197ba7319e9SDmitry Salychev 	if (!ETHER_IS_ZERO(mac_addr)) {
2198ba7319e9SDmitry Salychev 		/* Set MAC address of the physical port as DPNI's primary one. */
21994cd96614SDmitry Salychev 		error = DPAA2_CMD_NI_SET_PRIM_MAC_ADDR(dev, child, &cmd,
2200ba7319e9SDmitry Salychev 		    mac_addr);
2201ba7319e9SDmitry Salychev 		if (error) {
2202ba7319e9SDmitry Salychev 			device_printf(dev, "%s: failed to set primary MAC "
2203ba7319e9SDmitry Salychev 			    "address\n", __func__);
22044cd96614SDmitry Salychev 			goto close_ni;
2205ba7319e9SDmitry Salychev 		}
22064cd96614SDmitry Salychev 		for (int i = 0; i < ETHER_ADDR_LEN; i++) {
2207ba7319e9SDmitry Salychev 			sc->mac.addr[i] = mac_addr[i];
22084cd96614SDmitry Salychev 		}
2209ba7319e9SDmitry Salychev 	} else if (ETHER_IS_ZERO(dpni_mac_addr)) {
2210ba7319e9SDmitry Salychev 		/* Generate random MAC address as DPNI's primary one. */
2211ba7319e9SDmitry Salychev 		ether_gen_addr(ifp, &rnd_mac_addr);
22124cd96614SDmitry Salychev 		for (int i = 0; i < ETHER_ADDR_LEN; i++) {
2213ba7319e9SDmitry Salychev 			mac_addr[i] = rnd_mac_addr.octet[i];
22144cd96614SDmitry Salychev 		}
2215ba7319e9SDmitry Salychev 
22164cd96614SDmitry Salychev 		error = DPAA2_CMD_NI_SET_PRIM_MAC_ADDR(dev, child, &cmd,
2217ba7319e9SDmitry Salychev 		    mac_addr);
2218ba7319e9SDmitry Salychev 		if (error) {
2219ba7319e9SDmitry Salychev 			device_printf(dev, "%s: failed to set random primary "
2220ba7319e9SDmitry Salychev 			    "MAC address\n", __func__);
22214cd96614SDmitry Salychev 			goto close_ni;
2222ba7319e9SDmitry Salychev 		}
22234cd96614SDmitry Salychev 		for (int i = 0; i < ETHER_ADDR_LEN; i++) {
2224ba7319e9SDmitry Salychev 			sc->mac.addr[i] = mac_addr[i];
22254cd96614SDmitry Salychev 		}
2226ba7319e9SDmitry Salychev 	} else {
22274cd96614SDmitry Salychev 		for (int i = 0; i < ETHER_ADDR_LEN; i++) {
2228ba7319e9SDmitry Salychev 			sc->mac.addr[i] = dpni_mac_addr[i];
2229ba7319e9SDmitry Salychev 		}
22304cd96614SDmitry Salychev 	}
2231ba7319e9SDmitry Salychev 
22324cd96614SDmitry Salychev 	error = 0;
22334cd96614SDmitry Salychev close_ni:
22344cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
22354cd96614SDmitry Salychev close_rc:
22364cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
22374cd96614SDmitry Salychev err_exit:
22384cd96614SDmitry Salychev 	return (error);
2239ba7319e9SDmitry Salychev }
2240ba7319e9SDmitry Salychev 
2241ba7319e9SDmitry Salychev static void
2242ba7319e9SDmitry Salychev dpaa2_ni_miibus_statchg(device_t dev)
2243ba7319e9SDmitry Salychev {
22444cd96614SDmitry Salychev 	device_t pdev = device_get_parent(dev);
22454cd96614SDmitry Salychev 	device_t child = dev;
22464cd96614SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
2247ba7319e9SDmitry Salychev 	struct dpaa2_mac_link_state mac_link = { 0 };
22484cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
22494cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
22504cd96614SDmitry Salychev 	uint16_t rc_token, mac_token;
2251ba7319e9SDmitry Salychev 	int error, link_state;
2252ba7319e9SDmitry Salychev 
22534cd96614SDmitry Salychev 	if (sc->fixed_link || sc->mii == NULL) {
2254ba7319e9SDmitry Salychev 		return;
22554cd96614SDmitry Salychev 	}
2256964b3408SBjoern A. Zeeb 	if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) == 0) {
2257964b3408SBjoern A. Zeeb 		/*
2258964b3408SBjoern A. Zeeb 		 * We will receive calls and adjust the changes but
2259964b3408SBjoern A. Zeeb 		 * not have setup everything (called before dpaa2_ni_init()
2260964b3408SBjoern A. Zeeb 		 * really).  This will then setup the link and internal
2261964b3408SBjoern A. Zeeb 		 * sc->link_state and not trigger the update once needed,
2262964b3408SBjoern A. Zeeb 		 * so basically dpmac never knows about it.
2263964b3408SBjoern A. Zeeb 		 */
2264964b3408SBjoern A. Zeeb 		return;
2265964b3408SBjoern A. Zeeb 	}
2266ba7319e9SDmitry Salychev 
2267ba7319e9SDmitry Salychev 	/*
2268ba7319e9SDmitry Salychev 	 * Note: ifp link state will only be changed AFTER we are called so we
2269ba7319e9SDmitry Salychev 	 * cannot rely on ifp->if_linkstate here.
2270ba7319e9SDmitry Salychev 	 */
2271ba7319e9SDmitry Salychev 	if (sc->mii->mii_media_status & IFM_AVALID) {
22724cd96614SDmitry Salychev 		if (sc->mii->mii_media_status & IFM_ACTIVE) {
2273ba7319e9SDmitry Salychev 			link_state = LINK_STATE_UP;
22744cd96614SDmitry Salychev 		} else {
2275ba7319e9SDmitry Salychev 			link_state = LINK_STATE_DOWN;
22764cd96614SDmitry Salychev 		}
22774cd96614SDmitry Salychev 	} else {
2278ba7319e9SDmitry Salychev 		link_state = LINK_STATE_UNKNOWN;
22794cd96614SDmitry Salychev 	}
2280ba7319e9SDmitry Salychev 
2281ba7319e9SDmitry Salychev 	if (link_state != sc->link_state) {
2282ba7319e9SDmitry Salychev 		sc->link_state = link_state;
2283ba7319e9SDmitry Salychev 
22844cd96614SDmitry Salychev 		DPAA2_CMD_INIT(&cmd);
22854cd96614SDmitry Salychev 
22864cd96614SDmitry Salychev 		error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id,
22874cd96614SDmitry Salychev 		    &rc_token);
22884cd96614SDmitry Salychev 		if (error) {
22894cd96614SDmitry Salychev 			device_printf(dev, "%s: failed to open resource "
22904cd96614SDmitry Salychev 			    "container: id=%d, error=%d\n", __func__, rcinfo->id,
22914cd96614SDmitry Salychev 			    error);
22924cd96614SDmitry Salychev 			goto err_exit;
22934cd96614SDmitry Salychev 		}
22944cd96614SDmitry Salychev 		error = DPAA2_CMD_MAC_OPEN(dev, child, &cmd, sc->mac.dpmac_id,
22954cd96614SDmitry Salychev 		    &mac_token);
2296ba7319e9SDmitry Salychev 		if (error) {
2297ba7319e9SDmitry Salychev 			device_printf(sc->dev, "%s: failed to open DPMAC: "
2298ba7319e9SDmitry Salychev 			    "id=%d, error=%d\n", __func__, sc->mac.dpmac_id,
2299ba7319e9SDmitry Salychev 			    error);
23004cd96614SDmitry Salychev 			goto close_rc;
2301ba7319e9SDmitry Salychev 		}
2302ba7319e9SDmitry Salychev 
2303ba7319e9SDmitry Salychev 		if (link_state == LINK_STATE_UP ||
2304ba7319e9SDmitry Salychev 		    link_state == LINK_STATE_DOWN) {
2305ba7319e9SDmitry Salychev 			/* Update DPMAC link state. */
2306ba7319e9SDmitry Salychev 			mac_link.supported = sc->mii->mii_media.ifm_media;
2307ba7319e9SDmitry Salychev 			mac_link.advert = sc->mii->mii_media.ifm_media;
2308ba7319e9SDmitry Salychev 			mac_link.rate = 1000; /* TODO: Where to get from? */	/* ifmedia_baudrate? */
2309ba7319e9SDmitry Salychev 			mac_link.options =
2310ba7319e9SDmitry Salychev 			    DPAA2_MAC_LINK_OPT_AUTONEG |
2311ba7319e9SDmitry Salychev 			    DPAA2_MAC_LINK_OPT_PAUSE;
2312ba7319e9SDmitry Salychev 			mac_link.up = (link_state == LINK_STATE_UP) ? true : false;
2313ba7319e9SDmitry Salychev 			mac_link.state_valid = true;
2314ba7319e9SDmitry Salychev 
2315ba7319e9SDmitry Salychev 			/* Inform DPMAC about link state. */
23164cd96614SDmitry Salychev 			error = DPAA2_CMD_MAC_SET_LINK_STATE(dev, child, &cmd,
23174cd96614SDmitry Salychev 			    &mac_link);
23184cd96614SDmitry Salychev 			if (error) {
2319ba7319e9SDmitry Salychev 				device_printf(sc->dev, "%s: failed to set DPMAC "
2320ba7319e9SDmitry Salychev 				    "link state: id=%d, error=%d\n", __func__,
2321ba7319e9SDmitry Salychev 				    sc->mac.dpmac_id, error);
2322ba7319e9SDmitry Salychev 			}
2323ba7319e9SDmitry Salychev 		}
23244cd96614SDmitry Salychev 		(void)DPAA2_CMD_MAC_CLOSE(dev, child, &cmd);
23254cd96614SDmitry Salychev 		(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd,
23264cd96614SDmitry Salychev 		    rc_token));
23274cd96614SDmitry Salychev 	}
23284cd96614SDmitry Salychev 
23294cd96614SDmitry Salychev 	return;
23304cd96614SDmitry Salychev 
23314cd96614SDmitry Salychev close_rc:
23324cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
23334cd96614SDmitry Salychev err_exit:
23344cd96614SDmitry Salychev 	return;
2335ba7319e9SDmitry Salychev }
2336ba7319e9SDmitry Salychev 
2337ba7319e9SDmitry Salychev /**
2338ba7319e9SDmitry Salychev  * @brief Callback function to process media change request.
2339ba7319e9SDmitry Salychev  */
2340ba7319e9SDmitry Salychev static int
2341964b3408SBjoern A. Zeeb dpaa2_ni_media_change_locked(struct dpaa2_ni_softc *sc)
2342ba7319e9SDmitry Salychev {
2343ba7319e9SDmitry Salychev 
2344964b3408SBjoern A. Zeeb 	DPNI_LOCK_ASSERT(sc);
2345ba7319e9SDmitry Salychev 	if (sc->mii) {
2346ba7319e9SDmitry Salychev 		mii_mediachg(sc->mii);
2347ba7319e9SDmitry Salychev 		sc->media_status = sc->mii->mii_media.ifm_media;
2348ba7319e9SDmitry Salychev 	} else if (sc->fixed_link) {
2349964b3408SBjoern A. Zeeb 		if_printf(sc->ifp, "%s: can't change media in fixed mode\n",
2350ba7319e9SDmitry Salychev 		    __func__);
2351ba7319e9SDmitry Salychev 	}
2352ba7319e9SDmitry Salychev 
2353ba7319e9SDmitry Salychev 	return (0);
2354ba7319e9SDmitry Salychev }
2355ba7319e9SDmitry Salychev 
2356964b3408SBjoern A. Zeeb static int
2357964b3408SBjoern A. Zeeb dpaa2_ni_media_change(if_t ifp)
2358964b3408SBjoern A. Zeeb {
2359964b3408SBjoern A. Zeeb 	struct dpaa2_ni_softc *sc = if_getsoftc(ifp);
2360964b3408SBjoern A. Zeeb 	int error;
2361964b3408SBjoern A. Zeeb 
2362964b3408SBjoern A. Zeeb 	DPNI_LOCK(sc);
2363964b3408SBjoern A. Zeeb 	error = dpaa2_ni_media_change_locked(sc);
2364964b3408SBjoern A. Zeeb 	DPNI_UNLOCK(sc);
2365964b3408SBjoern A. Zeeb 	return (error);
2366964b3408SBjoern A. Zeeb }
2367964b3408SBjoern A. Zeeb 
2368ba7319e9SDmitry Salychev /**
2369ba7319e9SDmitry Salychev  * @brief Callback function to process media status request.
2370ba7319e9SDmitry Salychev  */
2371ba7319e9SDmitry Salychev static void
2372d936c29eSJustin Hibbits dpaa2_ni_media_status(if_t ifp, struct ifmediareq *ifmr)
2373ba7319e9SDmitry Salychev {
2374d936c29eSJustin Hibbits 	struct dpaa2_ni_softc *sc = if_getsoftc(ifp);
2375ba7319e9SDmitry Salychev 
2376ba7319e9SDmitry Salychev 	DPNI_LOCK(sc);
2377ba7319e9SDmitry Salychev 	if (sc->mii) {
2378ba7319e9SDmitry Salychev 		mii_pollstat(sc->mii);
2379ba7319e9SDmitry Salychev 		ifmr->ifm_active = sc->mii->mii_media_active;
2380ba7319e9SDmitry Salychev 		ifmr->ifm_status = sc->mii->mii_media_status;
2381ba7319e9SDmitry Salychev 	}
2382ba7319e9SDmitry Salychev 	DPNI_UNLOCK(sc);
2383ba7319e9SDmitry Salychev }
2384ba7319e9SDmitry Salychev 
2385ba7319e9SDmitry Salychev /**
2386ba7319e9SDmitry Salychev  * @brief Callout function to check and update media status.
2387ba7319e9SDmitry Salychev  */
2388ba7319e9SDmitry Salychev static void
2389ba7319e9SDmitry Salychev dpaa2_ni_media_tick(void *arg)
2390ba7319e9SDmitry Salychev {
2391ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = (struct dpaa2_ni_softc *) arg;
2392ba7319e9SDmitry Salychev 
2393ba7319e9SDmitry Salychev 	/* Check for media type change */
2394ba7319e9SDmitry Salychev 	if (sc->mii) {
2395ba7319e9SDmitry Salychev 		mii_tick(sc->mii);
2396ba7319e9SDmitry Salychev 		if (sc->media_status != sc->mii->mii_media.ifm_media) {
2397ba7319e9SDmitry Salychev 			printf("%s: media type changed (ifm_media=%x)\n",
2398ba7319e9SDmitry Salychev 			    __func__, sc->mii->mii_media.ifm_media);
2399ba7319e9SDmitry Salychev 			dpaa2_ni_media_change(sc->ifp);
2400ba7319e9SDmitry Salychev 		}
2401ba7319e9SDmitry Salychev 	}
2402ba7319e9SDmitry Salychev 
2403ba7319e9SDmitry Salychev 	/* Schedule another timeout one second from now */
2404ba7319e9SDmitry Salychev 	callout_reset(&sc->mii_callout, hz, dpaa2_ni_media_tick, sc);
2405ba7319e9SDmitry Salychev }
2406ba7319e9SDmitry Salychev 
2407ba7319e9SDmitry Salychev static void
2408ba7319e9SDmitry Salychev dpaa2_ni_init(void *arg)
2409ba7319e9SDmitry Salychev {
2410ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = (struct dpaa2_ni_softc *) arg;
2411d936c29eSJustin Hibbits 	if_t ifp = sc->ifp;
24124cd96614SDmitry Salychev 	device_t pdev = device_get_parent(sc->dev);
2413ba7319e9SDmitry Salychev 	device_t dev = sc->dev;
2414ba7319e9SDmitry Salychev 	device_t child = dev;
24154cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
24164cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
24174cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
24184cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
2419ba7319e9SDmitry Salychev 	int error;
2420ba7319e9SDmitry Salychev 
2421ba7319e9SDmitry Salychev 	DPNI_LOCK(sc);
2422d936c29eSJustin Hibbits 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) {
2423ba7319e9SDmitry Salychev 		DPNI_UNLOCK(sc);
2424ba7319e9SDmitry Salychev 		return;
2425ba7319e9SDmitry Salychev 	}
2426ba7319e9SDmitry Salychev 	DPNI_UNLOCK(sc);
2427ba7319e9SDmitry Salychev 
24284cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
24294cd96614SDmitry Salychev 
24304cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
24314cd96614SDmitry Salychev 	if (error) {
24324cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
24334cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
24344cd96614SDmitry Salychev 		goto err_exit;
24354cd96614SDmitry Salychev 	}
24364cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
24374cd96614SDmitry Salychev 	if (error) {
24384cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
24394cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
24404cd96614SDmitry Salychev 		goto close_rc;
24414cd96614SDmitry Salychev 	}
24424cd96614SDmitry Salychev 
24434cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_ENABLE(dev, child, &cmd);
24444cd96614SDmitry Salychev 	if (error) {
2445ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to enable DPNI: error=%d\n",
2446ba7319e9SDmitry Salychev 		    __func__, error);
24474cd96614SDmitry Salychev 	}
2448ba7319e9SDmitry Salychev 
2449ba7319e9SDmitry Salychev 	DPNI_LOCK(sc);
2450964b3408SBjoern A. Zeeb 	/* Announce we are up and running and can queue packets. */
2451964b3408SBjoern A. Zeeb 	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
2452964b3408SBjoern A. Zeeb 
24534cd96614SDmitry Salychev 	if (sc->mii) {
2454964b3408SBjoern A. Zeeb 		/*
2455964b3408SBjoern A. Zeeb 		 * mii_mediachg() will trigger a call into
2456964b3408SBjoern A. Zeeb 		 * dpaa2_ni_miibus_statchg() to setup link state.
2457964b3408SBjoern A. Zeeb 		 */
2458964b3408SBjoern A. Zeeb 		dpaa2_ni_media_change_locked(sc);
24594cd96614SDmitry Salychev 	}
2460ba7319e9SDmitry Salychev 	callout_reset(&sc->mii_callout, hz, dpaa2_ni_media_tick, sc);
2461ba7319e9SDmitry Salychev 
2462ba7319e9SDmitry Salychev 	DPNI_UNLOCK(sc);
2463ba7319e9SDmitry Salychev 
24644cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
24654cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
24664cd96614SDmitry Salychev 	return;
24674cd96614SDmitry Salychev 
24684cd96614SDmitry Salychev close_rc:
24694cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
24704cd96614SDmitry Salychev err_exit:
2471ba7319e9SDmitry Salychev 	return;
2472ba7319e9SDmitry Salychev }
2473ba7319e9SDmitry Salychev 
2474ba7319e9SDmitry Salychev static int
2475d936c29eSJustin Hibbits dpaa2_ni_transmit(if_t ifp, struct mbuf *m)
2476ba7319e9SDmitry Salychev {
2477d936c29eSJustin Hibbits 	struct dpaa2_ni_softc *sc = if_getsoftc(ifp);
247858983e4bSDmitry Salychev 	struct dpaa2_channel *ch;
2479ba7319e9SDmitry Salychev 	uint32_t fqid;
24801efae8a2SJohn Baldwin 	bool found = false;
248158983e4bSDmitry Salychev 	int chidx = 0, error;
2482ba7319e9SDmitry Salychev 
248358983e4bSDmitry Salychev 	if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))) {
2484ba7319e9SDmitry Salychev 		return (0);
248558983e4bSDmitry Salychev 	}
2486ba7319e9SDmitry Salychev 
2487ba7319e9SDmitry Salychev 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
2488ba7319e9SDmitry Salychev 		fqid = m->m_pkthdr.flowid;
2489ba7319e9SDmitry Salychev 		for (int i = 0; i < sc->chan_n; i++) {
249058983e4bSDmitry Salychev 			ch = sc->channels[i];
249158983e4bSDmitry Salychev 			for (int j = 0; j < ch->rxq_n; j++) {
249258983e4bSDmitry Salychev 				if (fqid == ch->rx_queues[j].fqid) {
249358983e4bSDmitry Salychev 					chidx = ch->flowid;
2494ba7319e9SDmitry Salychev 					found = true;
2495ba7319e9SDmitry Salychev 					break;
2496ba7319e9SDmitry Salychev 				}
2497ba7319e9SDmitry Salychev 			}
2498ba7319e9SDmitry Salychev 			if (found) {
2499ba7319e9SDmitry Salychev 				break;
2500ba7319e9SDmitry Salychev 			}
2501ba7319e9SDmitry Salychev 		}
2502ba7319e9SDmitry Salychev 	}
2503ba7319e9SDmitry Salychev 
250458983e4bSDmitry Salychev 	ch = sc->channels[chidx];
250558983e4bSDmitry Salychev 	error = buf_ring_enqueue(ch->xmit_br, m);
250658983e4bSDmitry Salychev 	if (__predict_false(error != 0)) {
250758983e4bSDmitry Salychev 		m_freem(m);
250858983e4bSDmitry Salychev 	} else {
250958983e4bSDmitry Salychev 		taskqueue_enqueue(ch->cleanup_tq, &ch->cleanup_task);
251058983e4bSDmitry Salychev 	}
2511ba7319e9SDmitry Salychev 
251258983e4bSDmitry Salychev 	return (error);
2513ba7319e9SDmitry Salychev }
2514ba7319e9SDmitry Salychev 
2515ba7319e9SDmitry Salychev static void
2516d936c29eSJustin Hibbits dpaa2_ni_qflush(if_t ifp)
2517ba7319e9SDmitry Salychev {
2518ba7319e9SDmitry Salychev 	/* TODO: Find a way to drain Tx queues in QBMan. */
2519ba7319e9SDmitry Salychev 	if_qflush(ifp);
2520ba7319e9SDmitry Salychev }
2521ba7319e9SDmitry Salychev 
2522ba7319e9SDmitry Salychev static int
25234cd96614SDmitry Salychev dpaa2_ni_ioctl(if_t ifp, u_long c, caddr_t data)
2524ba7319e9SDmitry Salychev {
2525d936c29eSJustin Hibbits 	struct dpaa2_ni_softc *sc = if_getsoftc(ifp);
2526ba7319e9SDmitry Salychev 	struct ifreq *ifr = (struct ifreq *) data;
25274cd96614SDmitry Salychev 	device_t pdev = device_get_parent(sc->dev);
25284cd96614SDmitry Salychev 	device_t dev = sc->dev;
25294cd96614SDmitry Salychev 	device_t child = dev;
25304cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
25314cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
25324cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
2533ba7319e9SDmitry Salychev 	uint32_t changed = 0;
25344cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
2535ba7319e9SDmitry Salychev 	int mtu, error, rc = 0;
2536ba7319e9SDmitry Salychev 
25374cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
2538ba7319e9SDmitry Salychev 
25394cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
25404cd96614SDmitry Salychev 	if (error) {
25414cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
25424cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
25434cd96614SDmitry Salychev 		goto err_exit;
25444cd96614SDmitry Salychev 	}
25454cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
25464cd96614SDmitry Salychev 	if (error) {
25474cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
25484cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
25494cd96614SDmitry Salychev 		goto close_rc;
25504cd96614SDmitry Salychev 	}
25514cd96614SDmitry Salychev 
25524cd96614SDmitry Salychev 	switch (c) {
2553ba7319e9SDmitry Salychev 	case SIOCSIFMTU:
2554ba7319e9SDmitry Salychev 		DPNI_LOCK(sc);
2555ba7319e9SDmitry Salychev 		mtu = ifr->ifr_mtu;
2556ba7319e9SDmitry Salychev 		if (mtu < ETHERMIN || mtu > ETHERMTU_JUMBO) {
2557ba7319e9SDmitry Salychev 			DPNI_UNLOCK(sc);
25584cd96614SDmitry Salychev 			error = EINVAL;
25594cd96614SDmitry Salychev 			goto close_ni;
2560ba7319e9SDmitry Salychev 		}
2561d936c29eSJustin Hibbits 		if_setmtu(ifp, mtu);
2562ba7319e9SDmitry Salychev 		DPNI_UNLOCK(sc);
2563ba7319e9SDmitry Salychev 
2564ba7319e9SDmitry Salychev 		/* Update maximum frame length. */
2565fa3dfeffSBjoern A. Zeeb 		mtu += ETHER_HDR_LEN;
2566fa3dfeffSBjoern A. Zeeb 		if (if_getcapenable(ifp) & IFCAP_VLAN_MTU)
2567fa3dfeffSBjoern A. Zeeb 			mtu += ETHER_VLAN_ENCAP_LEN;
2568fa3dfeffSBjoern A. Zeeb 		error = DPAA2_CMD_NI_SET_MFL(dev, child, &cmd, mtu);
2569ba7319e9SDmitry Salychev 		if (error) {
2570ba7319e9SDmitry Salychev 			device_printf(dev, "%s: failed to update maximum frame "
2571ba7319e9SDmitry Salychev 			    "length: error=%d\n", __func__, error);
25724cd96614SDmitry Salychev 			goto close_ni;
2573ba7319e9SDmitry Salychev 		}
2574ba7319e9SDmitry Salychev 		break;
2575ba7319e9SDmitry Salychev 	case SIOCSIFCAP:
2576d936c29eSJustin Hibbits 		changed = if_getcapenable(ifp) ^ ifr->ifr_reqcap;
2577ba7319e9SDmitry Salychev 		if (changed & IFCAP_HWCSUM) {
25784cd96614SDmitry Salychev 			if ((ifr->ifr_reqcap & changed) & IFCAP_HWCSUM) {
2579d936c29eSJustin Hibbits 				if_setcapenablebit(ifp, IFCAP_HWCSUM, 0);
25804cd96614SDmitry Salychev 			} else {
2581d936c29eSJustin Hibbits 				if_setcapenablebit(ifp, 0, IFCAP_HWCSUM);
2582ba7319e9SDmitry Salychev 			}
25834cd96614SDmitry Salychev 		}
2584ba7319e9SDmitry Salychev 		rc = dpaa2_ni_setup_if_caps(sc);
2585ba7319e9SDmitry Salychev 		if (rc) {
2586ba7319e9SDmitry Salychev 			printf("%s: failed to update iface capabilities: "
2587ba7319e9SDmitry Salychev 			    "error=%d\n", __func__, rc);
2588ba7319e9SDmitry Salychev 			rc = ENXIO;
2589ba7319e9SDmitry Salychev 		}
2590ba7319e9SDmitry Salychev 		break;
2591ba7319e9SDmitry Salychev 	case SIOCSIFFLAGS:
2592ba7319e9SDmitry Salychev 		DPNI_LOCK(sc);
2593d936c29eSJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
2594d936c29eSJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
2595d936c29eSJustin Hibbits 				changed = if_getflags(ifp) ^ sc->if_flags;
2596ba7319e9SDmitry Salychev 				if (changed & IFF_PROMISC ||
2597ba7319e9SDmitry Salychev 				    changed & IFF_ALLMULTI) {
2598ba7319e9SDmitry Salychev 					rc = dpaa2_ni_setup_if_flags(sc);
2599ba7319e9SDmitry Salychev 				}
2600ba7319e9SDmitry Salychev 			} else {
2601ba7319e9SDmitry Salychev 				DPNI_UNLOCK(sc);
2602ba7319e9SDmitry Salychev 				dpaa2_ni_init(sc);
2603ba7319e9SDmitry Salychev 				DPNI_LOCK(sc);
2604ba7319e9SDmitry Salychev 			}
2605d936c29eSJustin Hibbits 		} else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
26064cd96614SDmitry Salychev 			/* FIXME: Disable DPNI. See dpaa2_ni_init(). */
2607ba7319e9SDmitry Salychev 		}
2608ba7319e9SDmitry Salychev 
2609d936c29eSJustin Hibbits 		sc->if_flags = if_getflags(ifp);
2610ba7319e9SDmitry Salychev 		DPNI_UNLOCK(sc);
2611ba7319e9SDmitry Salychev 		break;
2612ba7319e9SDmitry Salychev 	case SIOCADDMULTI:
2613ba7319e9SDmitry Salychev 	case SIOCDELMULTI:
2614ba7319e9SDmitry Salychev 		DPNI_LOCK(sc);
2615d936c29eSJustin Hibbits 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
2616ba7319e9SDmitry Salychev 			DPNI_UNLOCK(sc);
2617ba7319e9SDmitry Salychev 			rc = dpaa2_ni_update_mac_filters(ifp);
26184cd96614SDmitry Salychev 			if (rc) {
2619ba7319e9SDmitry Salychev 				device_printf(dev, "%s: failed to update MAC "
2620ba7319e9SDmitry Salychev 				    "filters: error=%d\n", __func__, rc);
26214cd96614SDmitry Salychev 			}
2622ba7319e9SDmitry Salychev 			DPNI_LOCK(sc);
2623ba7319e9SDmitry Salychev 		}
2624ba7319e9SDmitry Salychev 		DPNI_UNLOCK(sc);
2625ba7319e9SDmitry Salychev 		break;
2626ba7319e9SDmitry Salychev 	case SIOCGIFMEDIA:
2627ba7319e9SDmitry Salychev 	case SIOCSIFMEDIA:
2628ba7319e9SDmitry Salychev 		if (sc->mii)
26294cd96614SDmitry Salychev 			rc = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, c);
2630ba7319e9SDmitry Salychev 		else if(sc->fixed_link) {
26314cd96614SDmitry Salychev 			rc = ifmedia_ioctl(ifp, ifr, &sc->fixed_ifmedia, c);
2632ba7319e9SDmitry Salychev 		}
2633ba7319e9SDmitry Salychev 		break;
2634ba7319e9SDmitry Salychev 	default:
26354cd96614SDmitry Salychev 		rc = ether_ioctl(ifp, c, data);
26364cd96614SDmitry Salychev 		break;
2637ba7319e9SDmitry Salychev 	}
2638ba7319e9SDmitry Salychev 
26394cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
26404cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
2641ba7319e9SDmitry Salychev 	return (rc);
26424cd96614SDmitry Salychev 
26434cd96614SDmitry Salychev close_ni:
26444cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
26454cd96614SDmitry Salychev close_rc:
26464cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
26474cd96614SDmitry Salychev err_exit:
26484cd96614SDmitry Salychev 	return (error);
2649ba7319e9SDmitry Salychev }
2650ba7319e9SDmitry Salychev 
2651ba7319e9SDmitry Salychev static int
2652d936c29eSJustin Hibbits dpaa2_ni_update_mac_filters(if_t ifp)
2653ba7319e9SDmitry Salychev {
2654d936c29eSJustin Hibbits 	struct dpaa2_ni_softc *sc = if_getsoftc(ifp);
2655ba7319e9SDmitry Salychev 	struct dpaa2_ni_mcaddr_ctx ctx;
26564cd96614SDmitry Salychev 	device_t pdev = device_get_parent(sc->dev);
26574cd96614SDmitry Salychev 	device_t dev = sc->dev;
26584cd96614SDmitry Salychev 	device_t child = dev;
26594cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
26604cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
26614cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
26624cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
2663ba7319e9SDmitry Salychev 	int error;
2664ba7319e9SDmitry Salychev 
26654cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
26664cd96614SDmitry Salychev 
26674cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
26684cd96614SDmitry Salychev 	if (error) {
26694cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
26704cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
26714cd96614SDmitry Salychev 		goto err_exit;
26724cd96614SDmitry Salychev 	}
26734cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
26744cd96614SDmitry Salychev 	if (error) {
26754cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
26764cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
26774cd96614SDmitry Salychev 		goto close_rc;
26784cd96614SDmitry Salychev 	}
2679ba7319e9SDmitry Salychev 
2680ba7319e9SDmitry Salychev 	/* Remove all multicast MAC filters. */
26814cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_CLEAR_MAC_FILTERS(dev, child, &cmd, false, true);
2682ba7319e9SDmitry Salychev 	if (error) {
2683ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to clear multicast MAC filters: "
2684ba7319e9SDmitry Salychev 		    "error=%d\n", __func__, error);
26854cd96614SDmitry Salychev 		goto close_ni;
2686ba7319e9SDmitry Salychev 	}
2687ba7319e9SDmitry Salychev 
2688ba7319e9SDmitry Salychev 	ctx.ifp = ifp;
2689ba7319e9SDmitry Salychev 	ctx.error = 0;
2690ba7319e9SDmitry Salychev 	ctx.nent = 0;
2691ba7319e9SDmitry Salychev 
2692ba7319e9SDmitry Salychev 	if_foreach_llmaddr(ifp, dpaa2_ni_add_maddr, &ctx);
2693ba7319e9SDmitry Salychev 
26944cd96614SDmitry Salychev 	error = ctx.error;
26954cd96614SDmitry Salychev close_ni:
26964cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
26974cd96614SDmitry Salychev close_rc:
26984cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
26994cd96614SDmitry Salychev err_exit:
27004cd96614SDmitry Salychev 	return (error);
2701ba7319e9SDmitry Salychev }
2702ba7319e9SDmitry Salychev 
2703ba7319e9SDmitry Salychev static u_int
2704ba7319e9SDmitry Salychev dpaa2_ni_add_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
2705ba7319e9SDmitry Salychev {
2706ba7319e9SDmitry Salychev 	struct dpaa2_ni_mcaddr_ctx *ctx = arg;
2707d936c29eSJustin Hibbits 	struct dpaa2_ni_softc *sc = if_getsoftc(ctx->ifp);
27084cd96614SDmitry Salychev 	device_t pdev = device_get_parent(sc->dev);
27094cd96614SDmitry Salychev 	device_t dev = sc->dev;
27104cd96614SDmitry Salychev 	device_t child = dev;
27114cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
27124cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
27134cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
27144cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
27154cd96614SDmitry Salychev 	int error;
2716ba7319e9SDmitry Salychev 
27174cd96614SDmitry Salychev 	if (ctx->error != 0) {
2718ba7319e9SDmitry Salychev 		return (0);
27194cd96614SDmitry Salychev 	}
2720ba7319e9SDmitry Salychev 
2721ba7319e9SDmitry Salychev 	if (ETHER_IS_MULTICAST(LLADDR(sdl))) {
27224cd96614SDmitry Salychev 		DPAA2_CMD_INIT(&cmd);
27234cd96614SDmitry Salychev 
27244cd96614SDmitry Salychev 		error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id,
27254cd96614SDmitry Salychev 		    &rc_token);
27264cd96614SDmitry Salychev 		if (error) {
27274cd96614SDmitry Salychev 			device_printf(dev, "%s: failed to open resource "
27284cd96614SDmitry Salychev 			    "container: id=%d, error=%d\n", __func__, rcinfo->id,
27294cd96614SDmitry Salychev 			    error);
27304cd96614SDmitry Salychev 			return (0);
27314cd96614SDmitry Salychev 		}
27324cd96614SDmitry Salychev 		error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id,
27334cd96614SDmitry Salychev 		    &ni_token);
27344cd96614SDmitry Salychev 		if (error) {
27354cd96614SDmitry Salychev 			device_printf(dev, "%s: failed to open network interface: "
27364cd96614SDmitry Salychev 			    "id=%d, error=%d\n", __func__, dinfo->id, error);
27374cd96614SDmitry Salychev 			(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd,
27384cd96614SDmitry Salychev 			    rc_token));
27394cd96614SDmitry Salychev 			return (0);
27404cd96614SDmitry Salychev 		}
27414cd96614SDmitry Salychev 
27424cd96614SDmitry Salychev 		ctx->error = DPAA2_CMD_NI_ADD_MAC_ADDR(dev, child, &cmd,
27434cd96614SDmitry Salychev 		    LLADDR(sdl));
27444cd96614SDmitry Salychev 
27454cd96614SDmitry Salychev 		(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd,
27464cd96614SDmitry Salychev 		    ni_token));
27474cd96614SDmitry Salychev 		(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd,
27484cd96614SDmitry Salychev 		    rc_token));
27494cd96614SDmitry Salychev 
2750ba7319e9SDmitry Salychev 		if (ctx->error != 0) {
2751ba7319e9SDmitry Salychev 			device_printf(dev, "%s: can't add more then %d MAC "
2752ba7319e9SDmitry Salychev 			    "addresses, switching to the multicast promiscuous "
2753ba7319e9SDmitry Salychev 			    "mode\n", __func__, ctx->nent);
2754ba7319e9SDmitry Salychev 
2755ba7319e9SDmitry Salychev 			/* Enable multicast promiscuous mode. */
2756ba7319e9SDmitry Salychev 			DPNI_LOCK(sc);
2757d936c29eSJustin Hibbits 			if_setflagbits(ctx->ifp, IFF_ALLMULTI, 0);
2758ba7319e9SDmitry Salychev 			sc->if_flags |= IFF_ALLMULTI;
2759ba7319e9SDmitry Salychev 			ctx->error = dpaa2_ni_setup_if_flags(sc);
2760ba7319e9SDmitry Salychev 			DPNI_UNLOCK(sc);
2761ba7319e9SDmitry Salychev 
2762ba7319e9SDmitry Salychev 			return (0);
2763ba7319e9SDmitry Salychev 		}
2764ba7319e9SDmitry Salychev 		ctx->nent++;
2765ba7319e9SDmitry Salychev 	}
2766ba7319e9SDmitry Salychev 
2767ba7319e9SDmitry Salychev 	return (1);
2768ba7319e9SDmitry Salychev }
2769ba7319e9SDmitry Salychev 
2770ba7319e9SDmitry Salychev static void
2771ba7319e9SDmitry Salychev dpaa2_ni_intr(void *arg)
2772ba7319e9SDmitry Salychev {
2773ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = (struct dpaa2_ni_softc *) arg;
27744cd96614SDmitry Salychev 	device_t pdev = device_get_parent(sc->dev);
27754cd96614SDmitry Salychev 	device_t dev = sc->dev;
27764cd96614SDmitry Salychev 	device_t child = dev;
27774cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
27784cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
27794cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
2780ba7319e9SDmitry Salychev 	uint32_t status = ~0u; /* clear all IRQ status bits */
27814cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
2782ba7319e9SDmitry Salychev 	int error;
2783ba7319e9SDmitry Salychev 
27844cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
27854cd96614SDmitry Salychev 
27864cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
27874cd96614SDmitry Salychev 	if (error) {
27884cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
27894cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
27904cd96614SDmitry Salychev 		goto err_exit;
27914cd96614SDmitry Salychev 	}
27924cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
27934cd96614SDmitry Salychev 	if (error) {
27944cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
27954cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
27964cd96614SDmitry Salychev 		goto close_rc;
27974cd96614SDmitry Salychev 	}
27984cd96614SDmitry Salychev 
27994cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_GET_IRQ_STATUS(dev, child, &cmd, DPNI_IRQ_INDEX,
28004cd96614SDmitry Salychev 	    &status);
28014cd96614SDmitry Salychev 	if (error) {
2802ba7319e9SDmitry Salychev 		device_printf(sc->dev, "%s: failed to obtain IRQ status: "
2803ba7319e9SDmitry Salychev 		    "error=%d\n", __func__, error);
2804ba7319e9SDmitry Salychev 	}
2805ba7319e9SDmitry Salychev 
28064cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
28074cd96614SDmitry Salychev close_rc:
28084cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
28094cd96614SDmitry Salychev err_exit:
28104cd96614SDmitry Salychev 	return;
28114cd96614SDmitry Salychev }
28124cd96614SDmitry Salychev 
2813ba7319e9SDmitry Salychev /**
281458983e4bSDmitry Salychev  * @brief Execute channel's Rx/Tx routines.
281558983e4bSDmitry Salychev  *
281658983e4bSDmitry Salychev  * NOTE: Should not be re-entrant for the same channel. It is achieved by
281758983e4bSDmitry Salychev  *       enqueuing the cleanup routine on a single-threaded taskqueue.
2818ba7319e9SDmitry Salychev  */
2819ba7319e9SDmitry Salychev static void
282058983e4bSDmitry Salychev dpaa2_ni_cleanup_task(void *arg, int count)
2821ba7319e9SDmitry Salychev {
282258983e4bSDmitry Salychev 	struct dpaa2_channel *ch = (struct dpaa2_channel *)arg;
282358983e4bSDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(ch->ni_dev);
282458983e4bSDmitry Salychev 	int error, rxc, txc;
2825ba7319e9SDmitry Salychev 
282658983e4bSDmitry Salychev 	for (int i = 0; i < DPAA2_CLEAN_BUDGET; i++) {
282758983e4bSDmitry Salychev 		rxc  = dpaa2_ni_rx_cleanup(ch);
282858983e4bSDmitry Salychev 		txc  = dpaa2_ni_tx_cleanup(ch);
2829ba7319e9SDmitry Salychev 
283058983e4bSDmitry Salychev 		if (__predict_false((if_getdrvflags(sc->ifp) &
283158983e4bSDmitry Salychev 		    IFF_DRV_RUNNING) == 0)) {
2832ba7319e9SDmitry Salychev 			return;
2833ba7319e9SDmitry Salychev 		}
2834ba7319e9SDmitry Salychev 
283558983e4bSDmitry Salychev 		if ((txc != DPAA2_TX_BUDGET) && (rxc != DPAA2_RX_BUDGET)) {
283658983e4bSDmitry Salychev 			break;
283758983e4bSDmitry Salychev 		}
283858983e4bSDmitry Salychev 	}
283958983e4bSDmitry Salychev 
284058983e4bSDmitry Salychev 	/* Re-arm channel to generate CDAN */
284158983e4bSDmitry Salychev 	error = DPAA2_SWP_CONF_WQ_CHANNEL(ch->io_dev, &ch->ctx);
284258983e4bSDmitry Salychev 	if (error != 0) {
284358983e4bSDmitry Salychev 		panic("%s: failed to rearm channel: chan_id=%d, error=%d\n",
284458983e4bSDmitry Salychev 		    __func__, ch->id, error);
2845ba7319e9SDmitry Salychev 	}
2846ba7319e9SDmitry Salychev }
2847ba7319e9SDmitry Salychev 
2848ba7319e9SDmitry Salychev /**
2849ba7319e9SDmitry Salychev  * @brief Poll frames from a specific channel when CDAN is received.
2850ba7319e9SDmitry Salychev  */
285158983e4bSDmitry Salychev static int
285258983e4bSDmitry Salychev dpaa2_ni_rx_cleanup(struct dpaa2_channel *ch)
2853ba7319e9SDmitry Salychev {
285458983e4bSDmitry Salychev 	struct dpaa2_io_softc *iosc = device_get_softc(ch->io_dev);
285558983e4bSDmitry Salychev 	struct dpaa2_swp *swp = iosc->swp;
2856ba7319e9SDmitry Salychev 	struct dpaa2_ni_fq *fq;
285758983e4bSDmitry Salychev 	struct dpaa2_buf *buf = &ch->store;
285858983e4bSDmitry Salychev 	int budget = DPAA2_RX_BUDGET;
2859ba7319e9SDmitry Salychev 	int error, consumed = 0;
2860ba7319e9SDmitry Salychev 
2861ba7319e9SDmitry Salychev 	do {
286258983e4bSDmitry Salychev 		error = dpaa2_swp_pull(swp, ch->id, buf, DPAA2_ETH_STORE_FRAMES);
2863ba7319e9SDmitry Salychev 		if (error) {
286458983e4bSDmitry Salychev 			device_printf(ch->ni_dev, "%s: failed to pull frames: "
286558983e4bSDmitry Salychev 			    "chan_id=%d, error=%d\n", __func__, ch->id, error);
2866ba7319e9SDmitry Salychev 			break;
2867ba7319e9SDmitry Salychev 		}
286858983e4bSDmitry Salychev 		error = dpaa2_ni_consume_frames(ch, &fq, &consumed);
286958983e4bSDmitry Salychev 		if (error == ENOENT || error == EALREADY) {
2870ba7319e9SDmitry Salychev 			break;
2871ba7319e9SDmitry Salychev 		}
2872ba7319e9SDmitry Salychev 		if (error == ETIMEDOUT) {
287358983e4bSDmitry Salychev 			device_printf(ch->ni_dev, "%s: timeout to consume "
287458983e4bSDmitry Salychev 			    "frames: chan_id=%d\n", __func__, ch->id);
2875ba7319e9SDmitry Salychev 		}
287658983e4bSDmitry Salychev 	} while (--budget);
2877ba7319e9SDmitry Salychev 
287858983e4bSDmitry Salychev 	return (DPAA2_RX_BUDGET - budget);
2879ba7319e9SDmitry Salychev }
2880ba7319e9SDmitry Salychev 
288158983e4bSDmitry Salychev static int
288258983e4bSDmitry Salychev dpaa2_ni_tx_cleanup(struct dpaa2_channel *ch)
2883ba7319e9SDmitry Salychev {
288458983e4bSDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(ch->ni_dev);
288558983e4bSDmitry Salychev 	struct dpaa2_ni_tx_ring *tx = &ch->txc_queue.tx_rings[0];
288658983e4bSDmitry Salychev 	struct mbuf *m = NULL;
288758983e4bSDmitry Salychev 	int budget = DPAA2_TX_BUDGET;
2888ba7319e9SDmitry Salychev 
288958983e4bSDmitry Salychev 	do {
289058983e4bSDmitry Salychev 		mtx_assert(&ch->xmit_mtx, MA_NOTOWNED);
289158983e4bSDmitry Salychev 		mtx_lock(&ch->xmit_mtx);
289258983e4bSDmitry Salychev 		m = buf_ring_dequeue_sc(ch->xmit_br);
289358983e4bSDmitry Salychev 		mtx_unlock(&ch->xmit_mtx);
289458983e4bSDmitry Salychev 
289558983e4bSDmitry Salychev 		if (__predict_false(m == NULL)) {
289658983e4bSDmitry Salychev 			/* TODO: Do not give up easily */
289758983e4bSDmitry Salychev 			break;
289858983e4bSDmitry Salychev 		} else {
289958983e4bSDmitry Salychev 			dpaa2_ni_tx(sc, ch, tx, m);
290058983e4bSDmitry Salychev 		}
290158983e4bSDmitry Salychev 	} while (--budget);
290258983e4bSDmitry Salychev 
290358983e4bSDmitry Salychev 	return (DPAA2_TX_BUDGET - budget);
290458983e4bSDmitry Salychev }
290558983e4bSDmitry Salychev 
290658983e4bSDmitry Salychev static void
290758983e4bSDmitry Salychev dpaa2_ni_tx(struct dpaa2_ni_softc *sc, struct dpaa2_channel *ch,
290858983e4bSDmitry Salychev     struct dpaa2_ni_tx_ring *tx, struct mbuf *m)
290958983e4bSDmitry Salychev {
291058983e4bSDmitry Salychev 	device_t dev = sc->dev;
291158983e4bSDmitry Salychev 	struct dpaa2_ni_fq *fq = tx->fq;
291258983e4bSDmitry Salychev 	struct dpaa2_buf *buf, *sgt;
291358983e4bSDmitry Salychev 	struct dpaa2_fd fd;
291458983e4bSDmitry Salychev 	struct mbuf *md;
291558983e4bSDmitry Salychev 	bus_dma_segment_t segs[DPAA2_TX_SEGLIMIT];
291658983e4bSDmitry Salychev 	int rc, nsegs;
291758983e4bSDmitry Salychev 	int error;
291858983e4bSDmitry Salychev 
291958983e4bSDmitry Salychev 	mtx_assert(&tx->lock, MA_NOTOWNED);
292058983e4bSDmitry Salychev 	mtx_lock(&tx->lock);
292158983e4bSDmitry Salychev 	buf = buf_ring_dequeue_sc(tx->br);
292258983e4bSDmitry Salychev 	mtx_unlock(&tx->lock);
292358983e4bSDmitry Salychev 	if (__predict_false(buf == NULL)) {
292458983e4bSDmitry Salychev 		/* TODO: Do not give up easily */
2925ba7319e9SDmitry Salychev 		m_freem(m);
2926ba7319e9SDmitry Salychev 		return;
2927ba7319e9SDmitry Salychev 	} else {
292858983e4bSDmitry Salychev 		DPAA2_BUF_ASSERT_TXREADY(buf);
292958983e4bSDmitry Salychev 		buf->m = m;
293058983e4bSDmitry Salychev 		sgt = buf->sgt;
2931ba7319e9SDmitry Salychev 	}
2932ba7319e9SDmitry Salychev 
293358983e4bSDmitry Salychev #if defined(INVARIANTS)
293458983e4bSDmitry Salychev 	struct dpaa2_ni_tx_ring *btx = (struct dpaa2_ni_tx_ring *)buf->opt;
293558983e4bSDmitry Salychev 	KASSERT(buf->opt == tx, ("%s: unexpected Tx ring", __func__));
293658983e4bSDmitry Salychev 	KASSERT(btx->fq->chan == ch, ("%s: unexpected channel", __func__));
293758983e4bSDmitry Salychev #endif /* INVARIANTS */
293858983e4bSDmitry Salychev 
2939*e69e172dSBjoern A. Zeeb 	BPF_MTAP(sc->ifp, m);
2940*e69e172dSBjoern A. Zeeb 
294158983e4bSDmitry Salychev 	error = bus_dmamap_load_mbuf_sg(buf->dmat, buf->dmap, m, segs, &nsegs,
294258983e4bSDmitry Salychev 	    BUS_DMA_NOWAIT);
2943ba7319e9SDmitry Salychev 	if (__predict_false(error != 0)) {
2944ba7319e9SDmitry Salychev 		/* Too many fragments, trying to defragment... */
294558983e4bSDmitry Salychev 		md = m_collapse(m, M_NOWAIT, DPAA2_TX_SEGLIMIT);
294658983e4bSDmitry Salychev 		if (md == NULL) {
294758983e4bSDmitry Salychev 			device_printf(dev, "%s: m_collapse() failed\n", __func__);
2948ba7319e9SDmitry Salychev 			fq->chan->tx_dropped++;
2949ba7319e9SDmitry Salychev 			goto err;
2950ba7319e9SDmitry Salychev 		}
2951ba7319e9SDmitry Salychev 
295258983e4bSDmitry Salychev 		buf->m = m = md;
295358983e4bSDmitry Salychev 		error = bus_dmamap_load_mbuf_sg(buf->dmat, buf->dmap, m, segs,
295458983e4bSDmitry Salychev 		    &nsegs, BUS_DMA_NOWAIT);
2955ba7319e9SDmitry Salychev 		if (__predict_false(error != 0)) {
295658983e4bSDmitry Salychev 			device_printf(dev, "%s: bus_dmamap_load_mbuf_sg() "
295758983e4bSDmitry Salychev 			    "failed: error=%d\n", __func__, error);
2958ba7319e9SDmitry Salychev 			fq->chan->tx_dropped++;
2959ba7319e9SDmitry Salychev 			goto err;
2960ba7319e9SDmitry Salychev 		}
2961ba7319e9SDmitry Salychev 	}
2962ba7319e9SDmitry Salychev 
296358983e4bSDmitry Salychev 	error = dpaa2_ni_build_fd(sc, tx, buf, segs, nsegs, &fd);
2964ba7319e9SDmitry Salychev 	if (__predict_false(error != 0)) {
296558983e4bSDmitry Salychev 		device_printf(dev, "%s: failed to build frame descriptor: "
296658983e4bSDmitry Salychev 		    "error=%d\n", __func__, error);
2967ba7319e9SDmitry Salychev 		fq->chan->tx_dropped++;
2968ba7319e9SDmitry Salychev 		goto err_unload;
2969ba7319e9SDmitry Salychev 	}
2970ba7319e9SDmitry Salychev 
297158983e4bSDmitry Salychev 	/* TODO: Enqueue several frames in a single command */
2972ba7319e9SDmitry Salychev 	for (int i = 0; i < DPAA2_NI_ENQUEUE_RETRIES; i++) {
297358983e4bSDmitry Salychev 		/* TODO: Return error codes instead of # of frames */
297458983e4bSDmitry Salychev 		rc = DPAA2_SWP_ENQ_MULTIPLE_FQ(fq->chan->io_dev, tx->fqid, &fd, 1);
2975ba7319e9SDmitry Salychev 		if (rc == 1) {
2976ba7319e9SDmitry Salychev 			break;
2977ba7319e9SDmitry Salychev 		}
2978ba7319e9SDmitry Salychev 	}
2979ba7319e9SDmitry Salychev 
298058983e4bSDmitry Salychev 	bus_dmamap_sync(buf->dmat, buf->dmap, BUS_DMASYNC_PREWRITE);
298158983e4bSDmitry Salychev 	bus_dmamap_sync(sgt->dmat, sgt->dmap, BUS_DMASYNC_PREWRITE);
2982ba7319e9SDmitry Salychev 
2983ba7319e9SDmitry Salychev 	if (rc != 1) {
2984ba7319e9SDmitry Salychev 		fq->chan->tx_dropped++;
2985ba7319e9SDmitry Salychev 		goto err_unload;
2986ba7319e9SDmitry Salychev 	} else {
2987ba7319e9SDmitry Salychev 		fq->chan->tx_frames++;
2988ba7319e9SDmitry Salychev 	}
2989ba7319e9SDmitry Salychev 	return;
2990ba7319e9SDmitry Salychev 
2991ba7319e9SDmitry Salychev err_unload:
299258983e4bSDmitry Salychev 	bus_dmamap_unload(buf->dmat, buf->dmap);
299358983e4bSDmitry Salychev 	if (sgt->paddr != 0) {
299458983e4bSDmitry Salychev 		bus_dmamap_unload(sgt->dmat, sgt->dmap);
2995ba7319e9SDmitry Salychev 	}
2996ba7319e9SDmitry Salychev err:
299758983e4bSDmitry Salychev 	m_freem(buf->m);
299858983e4bSDmitry Salychev 	buf_ring_enqueue(tx->br, buf);
2999ba7319e9SDmitry Salychev }
3000ba7319e9SDmitry Salychev 
3001ba7319e9SDmitry Salychev static int
300258983e4bSDmitry Salychev dpaa2_ni_consume_frames(struct dpaa2_channel *chan, struct dpaa2_ni_fq **src,
3003ba7319e9SDmitry Salychev     uint32_t *consumed)
3004ba7319e9SDmitry Salychev {
3005ba7319e9SDmitry Salychev 	struct dpaa2_ni_fq *fq = NULL;
3006ba7319e9SDmitry Salychev 	struct dpaa2_dq *dq;
3007ba7319e9SDmitry Salychev 	struct dpaa2_fd *fd;
300858983e4bSDmitry Salychev 	struct dpaa2_ni_rx_ctx ctx = {
300958983e4bSDmitry Salychev 		.head = NULL,
301058983e4bSDmitry Salychev 		.tail = NULL,
301158983e4bSDmitry Salychev 		.cnt = 0,
301258983e4bSDmitry Salychev 		.last = false
301358983e4bSDmitry Salychev 	};
3014ba7319e9SDmitry Salychev 	int rc, frames = 0;
3015ba7319e9SDmitry Salychev 
3016ba7319e9SDmitry Salychev 	do {
301758983e4bSDmitry Salychev 		rc = dpaa2_chan_next_frame(chan, &dq);
3018ba7319e9SDmitry Salychev 		if (rc == EINPROGRESS) {
3019ba7319e9SDmitry Salychev 			if (dq != NULL && !IS_NULL_RESPONSE(dq->fdr.desc.stat)) {
3020ba7319e9SDmitry Salychev 				fd = &dq->fdr.fd;
3021ba7319e9SDmitry Salychev 				fq = (struct dpaa2_ni_fq *) dq->fdr.desc.fqd_ctx;
302258983e4bSDmitry Salychev 
302358983e4bSDmitry Salychev 				switch (fq->type) {
302458983e4bSDmitry Salychev 				case DPAA2_NI_QUEUE_RX:
302558983e4bSDmitry Salychev 					(void)dpaa2_ni_rx(chan, fq, fd, &ctx);
302658983e4bSDmitry Salychev 					break;
302758983e4bSDmitry Salychev 				case DPAA2_NI_QUEUE_RX_ERR:
302858983e4bSDmitry Salychev 					(void)dpaa2_ni_rx_err(chan, fq, fd);
302958983e4bSDmitry Salychev 					break;
303058983e4bSDmitry Salychev 				case DPAA2_NI_QUEUE_TX_CONF:
303158983e4bSDmitry Salychev 					(void)dpaa2_ni_tx_conf(chan, fq, fd);
303258983e4bSDmitry Salychev 					break;
303358983e4bSDmitry Salychev 				default:
303458983e4bSDmitry Salychev 					panic("%s: unknown queue type (1)",
303558983e4bSDmitry Salychev 					    __func__);
303658983e4bSDmitry Salychev 				}
3037ba7319e9SDmitry Salychev 				frames++;
3038ba7319e9SDmitry Salychev 			}
3039ba7319e9SDmitry Salychev 		} else if (rc == EALREADY || rc == ENOENT) {
3040ba7319e9SDmitry Salychev 			if (dq != NULL && !IS_NULL_RESPONSE(dq->fdr.desc.stat)) {
3041ba7319e9SDmitry Salychev 				fd = &dq->fdr.fd;
3042ba7319e9SDmitry Salychev 				fq = (struct dpaa2_ni_fq *) dq->fdr.desc.fqd_ctx;
304358983e4bSDmitry Salychev 
304458983e4bSDmitry Salychev 				switch (fq->type) {
304558983e4bSDmitry Salychev 				case DPAA2_NI_QUEUE_RX:
304658983e4bSDmitry Salychev 					/*
304758983e4bSDmitry Salychev 					 * Last VDQ response (mbuf) in a chain
304858983e4bSDmitry Salychev 					 * obtained from the Rx queue.
304958983e4bSDmitry Salychev 					 */
305058983e4bSDmitry Salychev 					ctx.last = true;
305158983e4bSDmitry Salychev 					(void)dpaa2_ni_rx(chan, fq, fd, &ctx);
305258983e4bSDmitry Salychev 					break;
305358983e4bSDmitry Salychev 				case DPAA2_NI_QUEUE_RX_ERR:
305458983e4bSDmitry Salychev 					(void)dpaa2_ni_rx_err(chan, fq, fd);
305558983e4bSDmitry Salychev 					break;
305658983e4bSDmitry Salychev 				case DPAA2_NI_QUEUE_TX_CONF:
305758983e4bSDmitry Salychev 					(void)dpaa2_ni_tx_conf(chan, fq, fd);
305858983e4bSDmitry Salychev 					break;
305958983e4bSDmitry Salychev 				default:
306058983e4bSDmitry Salychev 					panic("%s: unknown queue type (2)",
306158983e4bSDmitry Salychev 					    __func__);
306258983e4bSDmitry Salychev 				}
3063ba7319e9SDmitry Salychev 				frames++;
3064ba7319e9SDmitry Salychev 			}
3065ba7319e9SDmitry Salychev 			break;
3066ba7319e9SDmitry Salychev 		} else {
306758983e4bSDmitry Salychev 			panic("%s: should not reach here: rc=%d", __func__, rc);
3068ba7319e9SDmitry Salychev 		}
3069ba7319e9SDmitry Salychev 	} while (true);
3070ba7319e9SDmitry Salychev 
307158983e4bSDmitry Salychev 	KASSERT(chan->store_idx < chan->store_sz, ("%s: store_idx(%d) >= "
307258983e4bSDmitry Salychev 	    "store_sz(%d)", __func__, chan->store_idx, chan->store_sz));
3073ba7319e9SDmitry Salychev 
3074ba7319e9SDmitry Salychev 	/*
307558983e4bSDmitry Salychev 	 * VDQ operation pulls frames from a single queue into the store.
3076ba7319e9SDmitry Salychev 	 * Return the frame queue and a number of consumed frames as an output.
3077ba7319e9SDmitry Salychev 	 */
307858983e4bSDmitry Salychev 	if (src != NULL) {
3079ba7319e9SDmitry Salychev 		*src = fq;
308058983e4bSDmitry Salychev 	}
308158983e4bSDmitry Salychev 	if (consumed != NULL) {
3082ba7319e9SDmitry Salychev 		*consumed = frames;
308358983e4bSDmitry Salychev 	}
3084ba7319e9SDmitry Salychev 
3085ba7319e9SDmitry Salychev 	return (rc);
3086ba7319e9SDmitry Salychev }
3087ba7319e9SDmitry Salychev 
3088ba7319e9SDmitry Salychev /**
3089ba7319e9SDmitry Salychev  * @brief Receive frames.
3090ba7319e9SDmitry Salychev  */
3091ba7319e9SDmitry Salychev static int
309258983e4bSDmitry Salychev dpaa2_ni_rx(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq, struct dpaa2_fd *fd,
309358983e4bSDmitry Salychev     struct dpaa2_ni_rx_ctx *ctx)
3094ba7319e9SDmitry Salychev {
3095ba7319e9SDmitry Salychev 	bus_addr_t paddr = (bus_addr_t)fd->addr;
309658983e4bSDmitry Salychev 	struct dpaa2_fa *fa = (struct dpaa2_fa *)PHYS_TO_DMAP(paddr);
309758983e4bSDmitry Salychev 	struct dpaa2_buf *buf = fa->buf;
309858983e4bSDmitry Salychev 	struct dpaa2_channel *bch = (struct dpaa2_channel *)buf->opt;
309958983e4bSDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(bch->ni_dev);
310058983e4bSDmitry Salychev 	struct dpaa2_bp_softc *bpsc;
310158983e4bSDmitry Salychev 	struct mbuf *m;
310258983e4bSDmitry Salychev 	device_t bpdev;
3103ba7319e9SDmitry Salychev 	bus_addr_t released[DPAA2_SWP_BUFS_PER_CMD];
3104ba7319e9SDmitry Salychev 	void *buf_data;
3105718bdb6aSDmitry Salychev 	int buf_len, error, released_n = 0;
3106ba7319e9SDmitry Salychev 
3107718bdb6aSDmitry Salychev 	KASSERT(fa->magic == DPAA2_MAGIC, ("%s: wrong magic", __func__));
310858983e4bSDmitry Salychev 	/*
310958983e4bSDmitry Salychev 	 * NOTE: Current channel might not be the same as the "buffer" channel
311058983e4bSDmitry Salychev 	 * and it's fine. It must not be NULL though.
311158983e4bSDmitry Salychev 	 */
311258983e4bSDmitry Salychev 	KASSERT(bch != NULL, ("%s: buffer channel is NULL", __func__));
311358983e4bSDmitry Salychev 
311458983e4bSDmitry Salychev 	if (__predict_false(paddr != buf->paddr)) {
3115ba7319e9SDmitry Salychev 		panic("%s: unexpected physical address: fd(%#jx) != buf(%#jx)",
311658983e4bSDmitry Salychev 		    __func__, paddr, buf->paddr);
3117ba7319e9SDmitry Salychev 	}
3118ba7319e9SDmitry Salychev 
3119ba7319e9SDmitry Salychev 	switch (dpaa2_ni_fd_err(fd)) {
3120ba7319e9SDmitry Salychev 	case 1: /* Enqueue rejected by QMan */
3121ba7319e9SDmitry Salychev 		sc->rx_enq_rej_frames++;
3122ba7319e9SDmitry Salychev 		break;
3123ba7319e9SDmitry Salychev 	case 2: /* QMan IEOI error */
3124ba7319e9SDmitry Salychev 		sc->rx_ieoi_err_frames++;
3125ba7319e9SDmitry Salychev 		break;
3126ba7319e9SDmitry Salychev 	default:
3127ba7319e9SDmitry Salychev 		break;
3128ba7319e9SDmitry Salychev 	}
3129ba7319e9SDmitry Salychev 	switch (dpaa2_ni_fd_format(fd)) {
3130ba7319e9SDmitry Salychev 	case DPAA2_FD_SINGLE:
3131ba7319e9SDmitry Salychev 		sc->rx_single_buf_frames++;
3132ba7319e9SDmitry Salychev 		break;
3133ba7319e9SDmitry Salychev 	case DPAA2_FD_SG:
3134ba7319e9SDmitry Salychev 		sc->rx_sg_buf_frames++;
3135ba7319e9SDmitry Salychev 		break;
3136ba7319e9SDmitry Salychev 	default:
3137ba7319e9SDmitry Salychev 		break;
3138ba7319e9SDmitry Salychev 	}
3139ba7319e9SDmitry Salychev 
314058983e4bSDmitry Salychev 	mtx_assert(&bch->dma_mtx, MA_NOTOWNED);
314158983e4bSDmitry Salychev 	mtx_lock(&bch->dma_mtx);
3142ba7319e9SDmitry Salychev 
314358983e4bSDmitry Salychev 	bus_dmamap_sync(buf->dmat, buf->dmap, BUS_DMASYNC_POSTREAD);
314458983e4bSDmitry Salychev 	bus_dmamap_unload(buf->dmat, buf->dmap);
314558983e4bSDmitry Salychev 	m = buf->m;
3146ba7319e9SDmitry Salychev 	buf_len = dpaa2_ni_fd_data_len(fd);
314758983e4bSDmitry Salychev 	buf_data = (uint8_t *)buf->vaddr + dpaa2_ni_fd_offset(fd);
314858983e4bSDmitry Salychev 	/* Prepare buffer to be re-cycled */
314958983e4bSDmitry Salychev 	buf->m = NULL;
315058983e4bSDmitry Salychev 	buf->paddr = 0;
315158983e4bSDmitry Salychev 	buf->vaddr = NULL;
315258983e4bSDmitry Salychev 	buf->seg.ds_addr = 0;
315358983e4bSDmitry Salychev 	buf->seg.ds_len = 0;
315458983e4bSDmitry Salychev 	buf->nseg = 0;
3155ba7319e9SDmitry Salychev 
315658983e4bSDmitry Salychev 	mtx_unlock(&bch->dma_mtx);
3157ba7319e9SDmitry Salychev 
3158ba7319e9SDmitry Salychev 	m->m_flags |= M_PKTHDR;
3159ba7319e9SDmitry Salychev 	m->m_data = buf_data;
3160ba7319e9SDmitry Salychev 	m->m_len = buf_len;
3161ba7319e9SDmitry Salychev 	m->m_pkthdr.len = buf_len;
316258983e4bSDmitry Salychev 	m->m_pkthdr.rcvif = sc->ifp;
3163ba7319e9SDmitry Salychev 	m->m_pkthdr.flowid = fq->fqid;
3164ba7319e9SDmitry Salychev 	M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
3165ba7319e9SDmitry Salychev 
316658983e4bSDmitry Salychev 	if (ctx->head == NULL) {
316758983e4bSDmitry Salychev 		KASSERT(ctx->tail == NULL, ("%s: tail already given?", __func__));
316858983e4bSDmitry Salychev 		ctx->head = m;
316958983e4bSDmitry Salychev 		ctx->tail = m;
317058983e4bSDmitry Salychev 	} else {
317158983e4bSDmitry Salychev 		KASSERT(ctx->head != NULL, ("%s: head is NULL", __func__));
317258983e4bSDmitry Salychev 		ctx->tail->m_nextpkt = m;
317358983e4bSDmitry Salychev 		ctx->tail = m;
317458983e4bSDmitry Salychev 	}
317558983e4bSDmitry Salychev 	ctx->cnt++;
3176ba7319e9SDmitry Salychev 
317758983e4bSDmitry Salychev 	if (ctx->last) {
317858983e4bSDmitry Salychev 		ctx->tail->m_nextpkt = NULL;
317958983e4bSDmitry Salychev 		if_input(sc->ifp, ctx->head);
318058983e4bSDmitry Salychev 	}
3181ba7319e9SDmitry Salychev 
318258983e4bSDmitry Salychev 	/* Keep the buffer to be recycled */
318358983e4bSDmitry Salychev 	ch->recycled[ch->recycled_n++] = buf;
3184ba7319e9SDmitry Salychev 
318558983e4bSDmitry Salychev 	/* Re-seed and release recycled buffers back to the pool */
318658983e4bSDmitry Salychev 	if (ch->recycled_n == DPAA2_SWP_BUFS_PER_CMD) {
318758983e4bSDmitry Salychev 		/* Release new buffers to the pool if needed */
318858983e4bSDmitry Salychev 		taskqueue_enqueue(sc->bp_taskq, &ch->bp_task);
3189ba7319e9SDmitry Salychev 
319058983e4bSDmitry Salychev 		for (int i = 0; i < ch->recycled_n; i++) {
319158983e4bSDmitry Salychev 			buf = ch->recycled[i];
319258983e4bSDmitry Salychev 			bch = (struct dpaa2_channel *)buf->opt;
319358983e4bSDmitry Salychev 
319458983e4bSDmitry Salychev 			mtx_assert(&bch->dma_mtx, MA_NOTOWNED);
319558983e4bSDmitry Salychev 			mtx_lock(&bch->dma_mtx);
319658983e4bSDmitry Salychev 			error = dpaa2_buf_seed_rxb(sc->dev, buf,
319758983e4bSDmitry Salychev 			    DPAA2_RX_BUF_SIZE, &bch->dma_mtx);
319858983e4bSDmitry Salychev 			mtx_unlock(&bch->dma_mtx);
319958983e4bSDmitry Salychev 
3200ba7319e9SDmitry Salychev 			if (__predict_false(error != 0)) {
320158983e4bSDmitry Salychev 				/* TODO: What else to do with the buffer? */
320258983e4bSDmitry Salychev 				panic("%s: failed to recycle buffer: error=%d",
320358983e4bSDmitry Salychev 				    __func__, error);
3204ba7319e9SDmitry Salychev 			}
3205ba7319e9SDmitry Salychev 
320658983e4bSDmitry Salychev 			/* Prepare buffer to be released in a single command */
320758983e4bSDmitry Salychev 			released[released_n++] = buf->paddr;
3208ba7319e9SDmitry Salychev 		}
3209ba7319e9SDmitry Salychev 
321058983e4bSDmitry Salychev 		/* There's only one buffer pool for now */
321158983e4bSDmitry Salychev 		bpdev = (device_t)rman_get_start(sc->res[DPAA2_NI_BP_RID(0)]);
321258983e4bSDmitry Salychev 		bpsc = device_get_softc(bpdev);
3213ba7319e9SDmitry Salychev 
321458983e4bSDmitry Salychev 		error = DPAA2_SWP_RELEASE_BUFS(ch->io_dev, bpsc->attr.bpid,
3215ba7319e9SDmitry Salychev 		    released, released_n);
3216ba7319e9SDmitry Salychev 		if (__predict_false(error != 0)) {
3217ba7319e9SDmitry Salychev 			device_printf(sc->dev, "%s: failed to release buffers "
3218ba7319e9SDmitry Salychev 			    "to the pool: error=%d\n", __func__, error);
3219ba7319e9SDmitry Salychev 			return (error);
3220ba7319e9SDmitry Salychev 		}
322158983e4bSDmitry Salychev 		ch->recycled_n = 0;
3222ba7319e9SDmitry Salychev 	}
3223ba7319e9SDmitry Salychev 
3224ba7319e9SDmitry Salychev 	return (0);
3225ba7319e9SDmitry Salychev }
3226ba7319e9SDmitry Salychev 
3227ba7319e9SDmitry Salychev /**
3228ba7319e9SDmitry Salychev  * @brief Receive Rx error frames.
3229ba7319e9SDmitry Salychev  */
3230ba7319e9SDmitry Salychev static int
323158983e4bSDmitry Salychev dpaa2_ni_rx_err(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq,
3232ba7319e9SDmitry Salychev     struct dpaa2_fd *fd)
3233ba7319e9SDmitry Salychev {
3234ba7319e9SDmitry Salychev 	bus_addr_t paddr = (bus_addr_t)fd->addr;
323558983e4bSDmitry Salychev 	struct dpaa2_fa *fa = (struct dpaa2_fa *)PHYS_TO_DMAP(paddr);
323658983e4bSDmitry Salychev 	struct dpaa2_buf *buf = fa->buf;
323758983e4bSDmitry Salychev 	struct dpaa2_channel *bch = (struct dpaa2_channel *)buf->opt;
323858983e4bSDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(bch->ni_dev);
323958983e4bSDmitry Salychev 	device_t bpdev;
324058983e4bSDmitry Salychev 	struct dpaa2_bp_softc *bpsc;
3241718bdb6aSDmitry Salychev 	int error;
3242ba7319e9SDmitry Salychev 
3243718bdb6aSDmitry Salychev 	KASSERT(fa->magic == DPAA2_MAGIC, ("%s: wrong magic", __func__));
324458983e4bSDmitry Salychev 	/*
324558983e4bSDmitry Salychev 	 * NOTE: Current channel might not be the same as the "buffer" channel
324658983e4bSDmitry Salychev 	 * and it's fine. It must not be NULL though.
324758983e4bSDmitry Salychev 	 */
324858983e4bSDmitry Salychev 	KASSERT(bch != NULL, ("%s: buffer channel is NULL", __func__));
324958983e4bSDmitry Salychev 
325058983e4bSDmitry Salychev 	if (__predict_false(paddr != buf->paddr)) {
3251ba7319e9SDmitry Salychev 		panic("%s: unexpected physical address: fd(%#jx) != buf(%#jx)",
325258983e4bSDmitry Salychev 		    __func__, paddr, buf->paddr);
3253ba7319e9SDmitry Salychev 	}
3254ba7319e9SDmitry Salychev 
325558983e4bSDmitry Salychev 	/* There's only one buffer pool for now */
325658983e4bSDmitry Salychev 	bpdev = (device_t)rman_get_start(sc->res[DPAA2_NI_BP_RID(0)]);
325758983e4bSDmitry Salychev 	bpsc = device_get_softc(bpdev);
3258ba7319e9SDmitry Salychev 
325958983e4bSDmitry Salychev 	/* Release buffer to QBMan buffer pool */
326058983e4bSDmitry Salychev 	error = DPAA2_SWP_RELEASE_BUFS(ch->io_dev, bpsc->attr.bpid, &paddr, 1);
3261ba7319e9SDmitry Salychev 	if (error != 0) {
3262ba7319e9SDmitry Salychev 		device_printf(sc->dev, "%s: failed to release frame buffer to "
3263ba7319e9SDmitry Salychev 		    "the pool: error=%d\n", __func__, error);
3264ba7319e9SDmitry Salychev 		return (error);
3265ba7319e9SDmitry Salychev 	}
3266ba7319e9SDmitry Salychev 
3267ba7319e9SDmitry Salychev 	return (0);
3268ba7319e9SDmitry Salychev }
3269ba7319e9SDmitry Salychev 
3270ba7319e9SDmitry Salychev /**
3271ba7319e9SDmitry Salychev  * @brief Receive Tx confirmation frames.
3272ba7319e9SDmitry Salychev  */
3273ba7319e9SDmitry Salychev static int
327458983e4bSDmitry Salychev dpaa2_ni_tx_conf(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq,
3275ba7319e9SDmitry Salychev     struct dpaa2_fd *fd)
3276ba7319e9SDmitry Salychev {
3277718bdb6aSDmitry Salychev 	bus_addr_t paddr = (bus_addr_t)fd->addr;
327858983e4bSDmitry Salychev 	struct dpaa2_fa *fa = (struct dpaa2_fa *)PHYS_TO_DMAP(paddr);
327958983e4bSDmitry Salychev 	struct dpaa2_buf *buf = fa->buf;
328058983e4bSDmitry Salychev 	struct dpaa2_buf *sgt = buf->sgt;
328158983e4bSDmitry Salychev 	struct dpaa2_ni_tx_ring *tx = (struct dpaa2_ni_tx_ring *)buf->opt;
328258983e4bSDmitry Salychev 	struct dpaa2_channel *bch = tx->fq->chan;
3283ba7319e9SDmitry Salychev 
3284718bdb6aSDmitry Salychev 	KASSERT(fa->magic == DPAA2_MAGIC, ("%s: wrong magic", __func__));
328558983e4bSDmitry Salychev 	KASSERT(tx != NULL, ("%s: Tx ring is NULL", __func__));
328658983e4bSDmitry Salychev 	KASSERT(sgt != NULL, ("%s: S/G table is NULL", __func__));
328758983e4bSDmitry Salychev 	/*
328858983e4bSDmitry Salychev 	 * NOTE: Current channel might not be the same as the "buffer" channel
328958983e4bSDmitry Salychev 	 * and it's fine. It must not be NULL though.
329058983e4bSDmitry Salychev 	 */
329158983e4bSDmitry Salychev 	KASSERT(bch != NULL, ("%s: buffer channel is NULL", __func__));
329258983e4bSDmitry Salychev 
329358983e4bSDmitry Salychev 	if (paddr != buf->paddr) {
3294ba7319e9SDmitry Salychev 		panic("%s: unexpected physical address: fd(%#jx) != buf(%#jx)",
329558983e4bSDmitry Salychev 		    __func__, paddr, buf->paddr);
3296ba7319e9SDmitry Salychev 	}
3297ba7319e9SDmitry Salychev 
329858983e4bSDmitry Salychev 	mtx_assert(&bch->dma_mtx, MA_NOTOWNED);
329958983e4bSDmitry Salychev 	mtx_lock(&bch->dma_mtx);
3300ba7319e9SDmitry Salychev 
330158983e4bSDmitry Salychev 	bus_dmamap_sync(buf->dmat, buf->dmap, BUS_DMASYNC_POSTWRITE);
330258983e4bSDmitry Salychev 	bus_dmamap_sync(sgt->dmat, sgt->dmap, BUS_DMASYNC_POSTWRITE);
330358983e4bSDmitry Salychev 	bus_dmamap_unload(buf->dmat, buf->dmap);
330458983e4bSDmitry Salychev 	bus_dmamap_unload(sgt->dmat, sgt->dmap);
330558983e4bSDmitry Salychev 	m_freem(buf->m);
330658983e4bSDmitry Salychev 	buf->m = NULL;
330758983e4bSDmitry Salychev 	buf->paddr = 0;
330858983e4bSDmitry Salychev 	buf->vaddr = NULL;
330958983e4bSDmitry Salychev 	sgt->paddr = 0;
331058983e4bSDmitry Salychev 
331158983e4bSDmitry Salychev 	mtx_unlock(&bch->dma_mtx);
331258983e4bSDmitry Salychev 
331358983e4bSDmitry Salychev 	/* Return Tx buffer back to the ring */
331458983e4bSDmitry Salychev 	buf_ring_enqueue(tx->br, buf);
3315ba7319e9SDmitry Salychev 
3316ba7319e9SDmitry Salychev 	return (0);
3317ba7319e9SDmitry Salychev }
3318ba7319e9SDmitry Salychev 
3319ba7319e9SDmitry Salychev /**
3320ba7319e9SDmitry Salychev  * @brief Compare versions of the DPAA2 network interface API.
3321ba7319e9SDmitry Salychev  */
3322ba7319e9SDmitry Salychev static int
3323ba7319e9SDmitry Salychev dpaa2_ni_cmp_api_version(struct dpaa2_ni_softc *sc, uint16_t major,
3324ba7319e9SDmitry Salychev     uint16_t minor)
3325ba7319e9SDmitry Salychev {
332658983e4bSDmitry Salychev 	if (sc->api_major == major) {
3327ba7319e9SDmitry Salychev 		return sc->api_minor - minor;
332858983e4bSDmitry Salychev 	}
3329ba7319e9SDmitry Salychev 	return sc->api_major - major;
3330ba7319e9SDmitry Salychev }
3331ba7319e9SDmitry Salychev 
3332ba7319e9SDmitry Salychev /**
3333ba7319e9SDmitry Salychev  * @brief Build a DPAA2 frame descriptor.
3334ba7319e9SDmitry Salychev  */
3335ba7319e9SDmitry Salychev static int
3336ba7319e9SDmitry Salychev dpaa2_ni_build_fd(struct dpaa2_ni_softc *sc, struct dpaa2_ni_tx_ring *tx,
333758983e4bSDmitry Salychev     struct dpaa2_buf *buf, bus_dma_segment_t *segs, int nsegs, struct dpaa2_fd *fd)
3338ba7319e9SDmitry Salychev {
333958983e4bSDmitry Salychev 	struct dpaa2_buf *sgt = buf->sgt;
334058983e4bSDmitry Salychev 	struct dpaa2_sg_entry *sge;
3341718bdb6aSDmitry Salychev 	struct dpaa2_fa *fa;
3342ba7319e9SDmitry Salychev 	int i, error;
3343ba7319e9SDmitry Salychev 
334458983e4bSDmitry Salychev 	KASSERT(nsegs <= DPAA2_TX_SEGLIMIT, ("%s: too many segments", __func__));
334558983e4bSDmitry Salychev 	KASSERT(buf->opt != NULL, ("%s: no Tx ring?", __func__));
334658983e4bSDmitry Salychev 	KASSERT(sgt != NULL, ("%s: no S/G table?", __func__));
334758983e4bSDmitry Salychev 	KASSERT(sgt->vaddr != NULL, ("%s: no S/G vaddr?", __func__));
3348ba7319e9SDmitry Salychev 
3349ba7319e9SDmitry Salychev 	memset(fd, 0, sizeof(*fd));
3350ba7319e9SDmitry Salychev 
335158983e4bSDmitry Salychev 	/* Populate and map S/G table */
335258983e4bSDmitry Salychev 	if (__predict_true(nsegs <= DPAA2_TX_SEGLIMIT)) {
335358983e4bSDmitry Salychev 		sge = (struct dpaa2_sg_entry *)sgt->vaddr + sc->tx_data_off;
335458983e4bSDmitry Salychev 		for (i = 0; i < nsegs; i++) {
335558983e4bSDmitry Salychev 			sge[i].addr = (uint64_t)segs[i].ds_addr;
335658983e4bSDmitry Salychev 			sge[i].len = (uint32_t)segs[i].ds_len;
335758983e4bSDmitry Salychev 			sge[i].offset_fmt = 0u;
3358ba7319e9SDmitry Salychev 		}
335958983e4bSDmitry Salychev 		sge[i-1].offset_fmt |= 0x8000u; /* set final entry flag */
3360ba7319e9SDmitry Salychev 
336158983e4bSDmitry Salychev 		KASSERT(sgt->paddr == 0, ("%s: paddr(%#jx) != 0", __func__,
336258983e4bSDmitry Salychev 		    sgt->paddr));
3363ba7319e9SDmitry Salychev 
336458983e4bSDmitry Salychev 		error = bus_dmamap_load(sgt->dmat, sgt->dmap, sgt->vaddr,
336558983e4bSDmitry Salychev 		    DPAA2_TX_SGT_SZ, dpaa2_dmamap_oneseg_cb, &sgt->paddr,
336658983e4bSDmitry Salychev 		    BUS_DMA_NOWAIT);
3367ba7319e9SDmitry Salychev 		if (__predict_false(error != 0)) {
336858983e4bSDmitry Salychev 			device_printf(sc->dev, "%s: bus_dmamap_load() failed: "
3369ba7319e9SDmitry Salychev 			    "error=%d\n", __func__, error);
3370ba7319e9SDmitry Salychev 			return (error);
3371ba7319e9SDmitry Salychev 		}
3372718bdb6aSDmitry Salychev 
337358983e4bSDmitry Salychev 		buf->paddr = sgt->paddr;
337458983e4bSDmitry Salychev 		buf->vaddr = sgt->vaddr;
3375ba7319e9SDmitry Salychev 		sc->tx_sg_frames++; /* for sysctl(9) */
3376ba7319e9SDmitry Salychev 	} else {
3377ba7319e9SDmitry Salychev 		return (EINVAL);
3378ba7319e9SDmitry Salychev 	}
3379ba7319e9SDmitry Salychev 
338058983e4bSDmitry Salychev 	fa = (struct dpaa2_fa *)sgt->vaddr;
3381718bdb6aSDmitry Salychev 	fa->magic = DPAA2_MAGIC;
3382718bdb6aSDmitry Salychev 	fa->buf = buf;
3383ba7319e9SDmitry Salychev 
338458983e4bSDmitry Salychev 	fd->addr = buf->paddr;
338558983e4bSDmitry Salychev 	fd->data_length = (uint32_t)buf->m->m_pkthdr.len;
3386ba7319e9SDmitry Salychev 	fd->bpid_ivp_bmt = 0;
3387ba7319e9SDmitry Salychev 	fd->offset_fmt_sl = 0x2000u | sc->tx_data_off;
3388ba7319e9SDmitry Salychev 	fd->ctrl = 0x00800000u;
3389ba7319e9SDmitry Salychev 
3390ba7319e9SDmitry Salychev 	return (0);
3391ba7319e9SDmitry Salychev }
3392ba7319e9SDmitry Salychev 
3393ba7319e9SDmitry Salychev static int
3394ba7319e9SDmitry Salychev dpaa2_ni_fd_err(struct dpaa2_fd *fd)
3395ba7319e9SDmitry Salychev {
3396ba7319e9SDmitry Salychev 	return ((fd->ctrl >> DPAA2_NI_FD_ERR_SHIFT) & DPAA2_NI_FD_ERR_MASK);
3397ba7319e9SDmitry Salychev }
3398ba7319e9SDmitry Salychev 
3399ba7319e9SDmitry Salychev static uint32_t
3400ba7319e9SDmitry Salychev dpaa2_ni_fd_data_len(struct dpaa2_fd *fd)
3401ba7319e9SDmitry Salychev {
340258983e4bSDmitry Salychev 	if (dpaa2_ni_fd_short_len(fd)) {
3403ba7319e9SDmitry Salychev 		return (fd->data_length & DPAA2_NI_FD_LEN_MASK);
340458983e4bSDmitry Salychev 	}
3405ba7319e9SDmitry Salychev 	return (fd->data_length);
3406ba7319e9SDmitry Salychev }
3407ba7319e9SDmitry Salychev 
3408ba7319e9SDmitry Salychev static int
3409ba7319e9SDmitry Salychev dpaa2_ni_fd_format(struct dpaa2_fd *fd)
3410ba7319e9SDmitry Salychev {
3411ba7319e9SDmitry Salychev 	return ((enum dpaa2_fd_format)((fd->offset_fmt_sl >>
3412ba7319e9SDmitry Salychev 	    DPAA2_NI_FD_FMT_SHIFT) & DPAA2_NI_FD_FMT_MASK));
3413ba7319e9SDmitry Salychev }
3414ba7319e9SDmitry Salychev 
3415ba7319e9SDmitry Salychev static bool
3416ba7319e9SDmitry Salychev dpaa2_ni_fd_short_len(struct dpaa2_fd *fd)
3417ba7319e9SDmitry Salychev {
3418ba7319e9SDmitry Salychev 	return (((fd->offset_fmt_sl >> DPAA2_NI_FD_SL_SHIFT)
3419ba7319e9SDmitry Salychev 	    & DPAA2_NI_FD_SL_MASK) == 1);
3420ba7319e9SDmitry Salychev }
3421ba7319e9SDmitry Salychev 
3422ba7319e9SDmitry Salychev static int
3423ba7319e9SDmitry Salychev dpaa2_ni_fd_offset(struct dpaa2_fd *fd)
3424ba7319e9SDmitry Salychev {
3425ba7319e9SDmitry Salychev 	return (fd->offset_fmt_sl & DPAA2_NI_FD_OFFSET_MASK);
3426ba7319e9SDmitry Salychev }
3427ba7319e9SDmitry Salychev 
3428ba7319e9SDmitry Salychev /**
3429ba7319e9SDmitry Salychev  * @brief Collect statistics of the network interface.
3430ba7319e9SDmitry Salychev  */
3431ba7319e9SDmitry Salychev static int
3432ba7319e9SDmitry Salychev dpaa2_ni_collect_stats(SYSCTL_HANDLER_ARGS)
3433ba7319e9SDmitry Salychev {
3434ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = (struct dpaa2_ni_softc *) arg1;
3435ba7319e9SDmitry Salychev 	struct dpni_stat *stat = &dpni_stat_sysctls[oidp->oid_number];
34364cd96614SDmitry Salychev 	device_t pdev = device_get_parent(sc->dev);
34374cd96614SDmitry Salychev 	device_t dev = sc->dev;
34384cd96614SDmitry Salychev 	device_t child = dev;
34394cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
34404cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
34414cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
3442ba7319e9SDmitry Salychev 	uint64_t cnt[DPAA2_NI_STAT_COUNTERS];
3443ba7319e9SDmitry Salychev 	uint64_t result = 0;
34444cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
3445ba7319e9SDmitry Salychev 	int error;
3446ba7319e9SDmitry Salychev 
34474cd96614SDmitry Salychev 	DPAA2_CMD_INIT(&cmd);
3448ba7319e9SDmitry Salychev 
34494cd96614SDmitry Salychev 	error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
34504cd96614SDmitry Salychev 	if (error) {
34514cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open resource container: "
34524cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, rcinfo->id, error);
34534cd96614SDmitry Salychev 		goto exit;
34544cd96614SDmitry Salychev 	}
34554cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
34564cd96614SDmitry Salychev 	if (error) {
34574cd96614SDmitry Salychev 		device_printf(dev, "%s: failed to open network interface: "
34584cd96614SDmitry Salychev 		    "id=%d, error=%d\n", __func__, dinfo->id, error);
34594cd96614SDmitry Salychev 		goto close_rc;
34604cd96614SDmitry Salychev 	}
34614cd96614SDmitry Salychev 
34624cd96614SDmitry Salychev 	error = DPAA2_CMD_NI_GET_STATISTICS(dev, child, &cmd, stat->page, 0, cnt);
34634cd96614SDmitry Salychev 	if (!error) {
34644cd96614SDmitry Salychev 		result = cnt[stat->cnt];
34654cd96614SDmitry Salychev 	}
34664cd96614SDmitry Salychev 
34674cd96614SDmitry Salychev 	(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
34684cd96614SDmitry Salychev close_rc:
34694cd96614SDmitry Salychev 	(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
34704cd96614SDmitry Salychev exit:
3471ba7319e9SDmitry Salychev 	return (sysctl_handle_64(oidp, &result, 0, req));
3472ba7319e9SDmitry Salychev }
3473ba7319e9SDmitry Salychev 
3474ba7319e9SDmitry Salychev static int
3475ba7319e9SDmitry Salychev dpaa2_ni_collect_buf_num(SYSCTL_HANDLER_ARGS)
3476ba7319e9SDmitry Salychev {
3477ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = (struct dpaa2_ni_softc *) arg1;
3478ba7319e9SDmitry Salychev 	uint32_t buf_num = DPAA2_ATOMIC_READ(&sc->buf_num);
3479ba7319e9SDmitry Salychev 
3480ba7319e9SDmitry Salychev 	return (sysctl_handle_32(oidp, &buf_num, 0, req));
3481ba7319e9SDmitry Salychev }
3482ba7319e9SDmitry Salychev 
3483ba7319e9SDmitry Salychev static int
3484ba7319e9SDmitry Salychev dpaa2_ni_collect_buf_free(SYSCTL_HANDLER_ARGS)
3485ba7319e9SDmitry Salychev {
3486ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = (struct dpaa2_ni_softc *) arg1;
3487ba7319e9SDmitry Salychev 	uint32_t buf_free = DPAA2_ATOMIC_READ(&sc->buf_free);
3488ba7319e9SDmitry Salychev 
3489ba7319e9SDmitry Salychev 	return (sysctl_handle_32(oidp, &buf_free, 0, req));
3490ba7319e9SDmitry Salychev }
3491ba7319e9SDmitry Salychev 
3492ba7319e9SDmitry Salychev static int
3493ba7319e9SDmitry Salychev dpaa2_ni_set_hash(device_t dev, uint64_t flags)
3494ba7319e9SDmitry Salychev {
3495ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
3496ba7319e9SDmitry Salychev 	uint64_t key = 0;
3497ba7319e9SDmitry Salychev 	int i;
3498ba7319e9SDmitry Salychev 
3499ba7319e9SDmitry Salychev 	if (!(sc->attr.num.queues > 1)) {
3500ba7319e9SDmitry Salychev 		return (EOPNOTSUPP);
3501ba7319e9SDmitry Salychev 	}
3502ba7319e9SDmitry Salychev 
3503ba7319e9SDmitry Salychev 	for (i = 0; i < ARRAY_SIZE(dist_fields); i++) {
3504ba7319e9SDmitry Salychev 		if (dist_fields[i].rxnfc_field & flags) {
3505ba7319e9SDmitry Salychev 			key |= dist_fields[i].id;
3506ba7319e9SDmitry Salychev 		}
3507ba7319e9SDmitry Salychev 	}
3508ba7319e9SDmitry Salychev 
3509ba7319e9SDmitry Salychev 	return (dpaa2_ni_set_dist_key(dev, DPAA2_NI_DIST_MODE_HASH, key));
3510ba7319e9SDmitry Salychev }
3511ba7319e9SDmitry Salychev 
3512ba7319e9SDmitry Salychev /**
3513ba7319e9SDmitry Salychev  * @brief Set Rx distribution (hash or flow classification) key flags is a
3514ba7319e9SDmitry Salychev  * combination of RXH_ bits.
3515ba7319e9SDmitry Salychev  */
3516ba7319e9SDmitry Salychev static int
3517ba7319e9SDmitry Salychev dpaa2_ni_set_dist_key(device_t dev, enum dpaa2_ni_dist_mode type, uint64_t flags)
3518ba7319e9SDmitry Salychev {
35194cd96614SDmitry Salychev 	device_t pdev = device_get_parent(dev);
3520ba7319e9SDmitry Salychev 	device_t child = dev;
3521ba7319e9SDmitry Salychev 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
35224cd96614SDmitry Salychev 	struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
35234cd96614SDmitry Salychev 	struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
3524ba7319e9SDmitry Salychev 	struct dpkg_profile_cfg cls_cfg;
3525ba7319e9SDmitry Salychev 	struct dpkg_extract *key;
3526ba7319e9SDmitry Salychev 	struct dpaa2_buf *buf = &sc->rxd_kcfg;
35274cd96614SDmitry Salychev 	struct dpaa2_cmd cmd;
35284cd96614SDmitry Salychev 	uint16_t rc_token, ni_token;
3529ba7319e9SDmitry Salychev 	int i, error = 0;
3530ba7319e9SDmitry Salychev 
353158983e4bSDmitry Salychev 	if (__predict_true(buf->dmat == NULL)) {
353258983e4bSDmitry Salychev 		buf->dmat = sc->rxd_dmat;
35334cd96614SDmitry Salychev 	}
3534ba7319e9SDmitry Salychev 
3535ba7319e9SDmitry Salychev 	memset(&cls_cfg, 0, sizeof(cls_cfg));
3536ba7319e9SDmitry Salychev 
3537ba7319e9SDmitry Salychev 	/* Configure extracts according to the given flags. */
3538ba7319e9SDmitry Salychev 	for (i = 0; i < ARRAY_SIZE(dist_fields); i++) {
3539ba7319e9SDmitry Salychev 		key = &cls_cfg.extracts[cls_cfg.num_extracts];
3540ba7319e9SDmitry Salychev 
35414cd96614SDmitry Salychev 		if (!(flags & dist_fields[i].id)) {
3542ba7319e9SDmitry Salychev 			continue;
35434cd96614SDmitry Salychev 		}
3544ba7319e9SDmitry Salychev 
3545ba7319e9SDmitry Salychev 		if (cls_cfg.num_extracts >= DPKG_MAX_NUM_OF_EXTRACTS) {
3546ba7319e9SDmitry Salychev 			device_printf(dev, "%s: failed to add key extraction "
3547ba7319e9SDmitry Salychev 			    "rule\n", __func__);
3548ba7319e9SDmitry Salychev 			return (E2BIG);
3549ba7319e9SDmitry Salychev 		}
3550ba7319e9SDmitry Salychev 
3551ba7319e9SDmitry Salychev 		key->type = DPKG_EXTRACT_FROM_HDR;
3552ba7319e9SDmitry Salychev 		key->extract.from_hdr.prot = dist_fields[i].cls_prot;
3553ba7319e9SDmitry Salychev 		key->extract.from_hdr.type = DPKG_FULL_FIELD;
3554ba7319e9SDmitry Salychev 		key->extract.from_hdr.field = dist_fields[i].cls_field;
3555ba7319e9SDmitry Salychev 		cls_cfg.num_extracts++;
3556ba7319e9SDmitry Salychev 	}
3557ba7319e9SDmitry Salychev 
355858983e4bSDmitry Salychev 	error = bus_dmamem_alloc(buf->dmat, (void **)&buf->vaddr,
355958983e4bSDmitry Salychev 	    BUS_DMA_ZERO | BUS_DMA_COHERENT, &buf->dmap);
3560ba7319e9SDmitry Salychev 	if (error != 0) {
3561ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to allocate a buffer for Rx "
3562ba7319e9SDmitry Salychev 		    "traffic distribution key configuration\n", __func__);
3563ba7319e9SDmitry Salychev 		return (error);
3564ba7319e9SDmitry Salychev 	}
3565ba7319e9SDmitry Salychev 
356658983e4bSDmitry Salychev 	error = dpaa2_ni_prepare_key_cfg(&cls_cfg, (uint8_t *)buf->vaddr);
3567ba7319e9SDmitry Salychev 	if (error != 0) {
3568ba7319e9SDmitry Salychev 		device_printf(dev, "%s: failed to prepare key configuration: "
3569ba7319e9SDmitry Salychev 		    "error=%d\n", __func__, error);
3570ba7319e9SDmitry Salychev 		return (error);
3571ba7319e9SDmitry Salychev 	}
3572ba7319e9SDmitry Salychev 
3573ba7319e9SDmitry Salychev 	/* Prepare for setting the Rx dist. */
357458983e4bSDmitry Salychev 	error = bus_dmamap_load(buf->dmat, buf->dmap, buf->vaddr,
357558983e4bSDmitry Salychev 	    DPAA2_CLASSIFIER_DMA_SIZE, dpaa2_dmamap_oneseg_cb, &buf->paddr,
357658983e4bSDmitry Salychev 	    BUS_DMA_NOWAIT);
3577ba7319e9SDmitry Salychev 	if (error != 0) {
3578ba7319e9SDmitry Salychev 		device_printf(sc->dev, "%s: failed to map a buffer for Rx "
3579ba7319e9SDmitry Salychev 		    "traffic distribution key configuration\n", __func__);
3580ba7319e9SDmitry Salychev 		return (error);
3581ba7319e9SDmitry Salychev 	}
3582ba7319e9SDmitry Salychev 
3583ba7319e9SDmitry Salychev 	if (type == DPAA2_NI_DIST_MODE_HASH) {
35844cd96614SDmitry Salychev 		DPAA2_CMD_INIT(&cmd);
35854cd96614SDmitry Salychev 
35864cd96614SDmitry Salychev 		error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id,
35874cd96614SDmitry Salychev 		    &rc_token);
35884cd96614SDmitry Salychev 		if (error) {
35894cd96614SDmitry Salychev 			device_printf(dev, "%s: failed to open resource "
35904cd96614SDmitry Salychev 			    "container: id=%d, error=%d\n", __func__, rcinfo->id,
35914cd96614SDmitry Salychev 			    error);
35924cd96614SDmitry Salychev 			goto err_exit;
35934cd96614SDmitry Salychev 		}
35944cd96614SDmitry Salychev 		error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id,
35954cd96614SDmitry Salychev 		    &ni_token);
35964cd96614SDmitry Salychev 		if (error) {
35974cd96614SDmitry Salychev 			device_printf(dev, "%s: failed to open network "
35984cd96614SDmitry Salychev 			    "interface: id=%d, error=%d\n", __func__, dinfo->id,
35994cd96614SDmitry Salychev 			    error);
36004cd96614SDmitry Salychev 			goto close_rc;
36014cd96614SDmitry Salychev 		}
36024cd96614SDmitry Salychev 
36034cd96614SDmitry Salychev 		error = DPAA2_CMD_NI_SET_RX_TC_DIST(dev, child, &cmd,
360458983e4bSDmitry Salychev 		    sc->attr.num.queues, 0, DPAA2_NI_DIST_MODE_HASH, buf->paddr);
36054cd96614SDmitry Salychev 		if (error != 0) {
3606ba7319e9SDmitry Salychev 			device_printf(dev, "%s: failed to set distribution mode "
3607ba7319e9SDmitry Salychev 			    "and size for the traffic class\n", __func__);
3608ba7319e9SDmitry Salychev 		}
3609ba7319e9SDmitry Salychev 
36104cd96614SDmitry Salychev 		(void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd,
36114cd96614SDmitry Salychev 		    ni_token));
36124cd96614SDmitry Salychev close_rc:
36134cd96614SDmitry Salychev 		(void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd,
36144cd96614SDmitry Salychev 		    rc_token));
36154cd96614SDmitry Salychev 	}
36164cd96614SDmitry Salychev 
36174cd96614SDmitry Salychev err_exit:
3618ba7319e9SDmitry Salychev 	return (error);
3619ba7319e9SDmitry Salychev }
3620ba7319e9SDmitry Salychev 
3621ba7319e9SDmitry Salychev /**
3622ba7319e9SDmitry Salychev  * @brief Prepares extract parameters.
3623ba7319e9SDmitry Salychev  *
3624ba7319e9SDmitry Salychev  * cfg:		Defining a full Key Generation profile.
3625ba7319e9SDmitry Salychev  * key_cfg_buf:	Zeroed 256 bytes of memory before mapping it to DMA.
3626ba7319e9SDmitry Salychev  */
3627ba7319e9SDmitry Salychev static int
3628ba7319e9SDmitry Salychev dpaa2_ni_prepare_key_cfg(struct dpkg_profile_cfg *cfg, uint8_t *key_cfg_buf)
3629ba7319e9SDmitry Salychev {
3630ba7319e9SDmitry Salychev 	struct dpni_ext_set_rx_tc_dist *dpni_ext;
3631ba7319e9SDmitry Salychev 	struct dpni_dist_extract *extr;
3632ba7319e9SDmitry Salychev 	int i, j;
3633ba7319e9SDmitry Salychev 
3634ba7319e9SDmitry Salychev 	if (cfg->num_extracts > DPKG_MAX_NUM_OF_EXTRACTS)
3635ba7319e9SDmitry Salychev 		return (EINVAL);
3636ba7319e9SDmitry Salychev 
3637ba7319e9SDmitry Salychev 	dpni_ext = (struct dpni_ext_set_rx_tc_dist *) key_cfg_buf;
3638ba7319e9SDmitry Salychev 	dpni_ext->num_extracts = cfg->num_extracts;
3639ba7319e9SDmitry Salychev 
3640ba7319e9SDmitry Salychev 	for (i = 0; i < cfg->num_extracts; i++) {
3641ba7319e9SDmitry Salychev 		extr = &dpni_ext->extracts[i];
3642ba7319e9SDmitry Salychev 
3643ba7319e9SDmitry Salychev 		switch (cfg->extracts[i].type) {
3644ba7319e9SDmitry Salychev 		case DPKG_EXTRACT_FROM_HDR:
3645ba7319e9SDmitry Salychev 			extr->prot = cfg->extracts[i].extract.from_hdr.prot;
3646ba7319e9SDmitry Salychev 			extr->efh_type =
3647ba7319e9SDmitry Salychev 			    cfg->extracts[i].extract.from_hdr.type & 0x0Fu;
3648ba7319e9SDmitry Salychev 			extr->size = cfg->extracts[i].extract.from_hdr.size;
3649ba7319e9SDmitry Salychev 			extr->offset = cfg->extracts[i].extract.from_hdr.offset;
3650ba7319e9SDmitry Salychev 			extr->field = cfg->extracts[i].extract.from_hdr.field;
3651ba7319e9SDmitry Salychev 			extr->hdr_index =
3652ba7319e9SDmitry Salychev 				cfg->extracts[i].extract.from_hdr.hdr_index;
3653ba7319e9SDmitry Salychev 			break;
3654ba7319e9SDmitry Salychev 		case DPKG_EXTRACT_FROM_DATA:
3655ba7319e9SDmitry Salychev 			extr->size = cfg->extracts[i].extract.from_data.size;
3656ba7319e9SDmitry Salychev 			extr->offset =
3657ba7319e9SDmitry Salychev 				cfg->extracts[i].extract.from_data.offset;
3658ba7319e9SDmitry Salychev 			break;
3659ba7319e9SDmitry Salychev 		case DPKG_EXTRACT_FROM_PARSE:
3660ba7319e9SDmitry Salychev 			extr->size = cfg->extracts[i].extract.from_parse.size;
3661ba7319e9SDmitry Salychev 			extr->offset =
3662ba7319e9SDmitry Salychev 				cfg->extracts[i].extract.from_parse.offset;
3663ba7319e9SDmitry Salychev 			break;
3664ba7319e9SDmitry Salychev 		default:
3665ba7319e9SDmitry Salychev 			return (EINVAL);
3666ba7319e9SDmitry Salychev 		}
3667ba7319e9SDmitry Salychev 
3668ba7319e9SDmitry Salychev 		extr->num_of_byte_masks = cfg->extracts[i].num_of_byte_masks;
3669ba7319e9SDmitry Salychev 		extr->extract_type = cfg->extracts[i].type & 0x0Fu;
3670ba7319e9SDmitry Salychev 
3671ba7319e9SDmitry Salychev 		for (j = 0; j < DPKG_NUM_OF_MASKS; j++) {
3672ba7319e9SDmitry Salychev 			extr->masks[j].mask = cfg->extracts[i].masks[j].mask;
3673ba7319e9SDmitry Salychev 			extr->masks[j].offset =
3674ba7319e9SDmitry Salychev 				cfg->extracts[i].masks[j].offset;
3675ba7319e9SDmitry Salychev 		}
3676ba7319e9SDmitry Salychev 	}
3677ba7319e9SDmitry Salychev 
3678ba7319e9SDmitry Salychev 	return (0);
3679ba7319e9SDmitry Salychev }
3680ba7319e9SDmitry Salychev 
3681ba7319e9SDmitry Salychev static device_method_t dpaa2_ni_methods[] = {
3682ba7319e9SDmitry Salychev 	/* Device interface */
3683ba7319e9SDmitry Salychev 	DEVMETHOD(device_probe,		dpaa2_ni_probe),
3684ba7319e9SDmitry Salychev 	DEVMETHOD(device_attach,	dpaa2_ni_attach),
3685ba7319e9SDmitry Salychev 	DEVMETHOD(device_detach,	dpaa2_ni_detach),
3686ba7319e9SDmitry Salychev 
3687ba7319e9SDmitry Salychev 	/* mii via memac_mdio */
3688ba7319e9SDmitry Salychev 	DEVMETHOD(miibus_statchg,	dpaa2_ni_miibus_statchg),
3689ba7319e9SDmitry Salychev 
3690ba7319e9SDmitry Salychev 	DEVMETHOD_END
3691ba7319e9SDmitry Salychev };
3692ba7319e9SDmitry Salychev 
3693ba7319e9SDmitry Salychev static driver_t dpaa2_ni_driver = {
3694ba7319e9SDmitry Salychev 	"dpaa2_ni",
3695ba7319e9SDmitry Salychev 	dpaa2_ni_methods,
3696ba7319e9SDmitry Salychev 	sizeof(struct dpaa2_ni_softc),
3697ba7319e9SDmitry Salychev };
3698ba7319e9SDmitry Salychev 
3699ba7319e9SDmitry Salychev DRIVER_MODULE(miibus, dpaa2_ni, miibus_driver, 0, 0);
3700ba7319e9SDmitry Salychev DRIVER_MODULE(dpaa2_ni, dpaa2_rc, dpaa2_ni_driver, 0, 0);
3701ba7319e9SDmitry Salychev 
3702ba7319e9SDmitry Salychev MODULE_DEPEND(dpaa2_ni, miibus, 1, 1, 1);
3703ba7319e9SDmitry Salychev #ifdef DEV_ACPI
3704ba7319e9SDmitry Salychev MODULE_DEPEND(dpaa2_ni, memac_mdio_acpi, 1, 1, 1);
3705ba7319e9SDmitry Salychev #endif
3706ba7319e9SDmitry Salychev #ifdef FDT
3707ba7319e9SDmitry Salychev MODULE_DEPEND(dpaa2_ni, memac_mdio_fdt, 1, 1, 1);
3708ba7319e9SDmitry Salychev #endif
3709