xref: /openbsd/sys/dev/pci/if_ixl.c (revision 0f9891f1)
1*0f9891f1Sjsg /*	$OpenBSD: if_ixl.c,v 1.101 2024/05/24 06:02:53 jsg Exp $ */
2ccb96312Sdlg 
3ccb96312Sdlg /*
4ccb96312Sdlg  * Copyright (c) 2013-2015, Intel Corporation
5ccb96312Sdlg  * All rights reserved.
6ccb96312Sdlg 
7ccb96312Sdlg  * Redistribution and use in source and binary forms, with or without
8ccb96312Sdlg  * modification, are permitted provided that the following conditions are met:
9ccb96312Sdlg  *
10ccb96312Sdlg  *  1. Redistributions of source code must retain the above copyright notice,
11ccb96312Sdlg  *     this list of conditions and the following disclaimer.
12ccb96312Sdlg  *
13ccb96312Sdlg  *  2. Redistributions in binary form must reproduce the above copyright
14ccb96312Sdlg  *     notice, this list of conditions and the following disclaimer in the
15ccb96312Sdlg  *     documentation and/or other materials provided with the distribution.
16ccb96312Sdlg  *
17ccb96312Sdlg  *  3. Neither the name of the Intel Corporation nor the names of its
18ccb96312Sdlg  *     contributors may be used to endorse or promote products derived from
19ccb96312Sdlg  *     this software without specific prior written permission.
20ccb96312Sdlg  *
21ccb96312Sdlg  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22ccb96312Sdlg  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23ccb96312Sdlg  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24ccb96312Sdlg  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25ccb96312Sdlg  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26ccb96312Sdlg  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27ccb96312Sdlg  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28ccb96312Sdlg  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29ccb96312Sdlg  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30ccb96312Sdlg  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31ccb96312Sdlg  * POSSIBILITY OF SUCH DAMAGE.
32ccb96312Sdlg  */
33ccb96312Sdlg 
34ccb96312Sdlg /*
35ccb96312Sdlg  * Copyright (c) 2016,2017 David Gwynne <dlg@openbsd.org>
36ccb96312Sdlg  *
37ccb96312Sdlg  * Permission to use, copy, modify, and distribute this software for any
38ccb96312Sdlg  * purpose with or without fee is hereby granted, provided that the above
39ccb96312Sdlg  * copyright notice and this permission notice appear in all copies.
40ccb96312Sdlg  *
41ccb96312Sdlg  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
42ccb96312Sdlg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
43ccb96312Sdlg  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
44ccb96312Sdlg  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
45ccb96312Sdlg  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
46ccb96312Sdlg  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
47ccb96312Sdlg  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
48ccb96312Sdlg  */
49ccb96312Sdlg 
50ccb96312Sdlg #include "bpfilter.h"
512ee1fcb3Sdlg #include "kstat.h"
52ccb96312Sdlg 
53ccb96312Sdlg #include <sys/param.h>
54ccb96312Sdlg #include <sys/systm.h>
55b661852cSdlg #include <sys/proc.h>
56ccb96312Sdlg #include <sys/sockio.h>
57ccb96312Sdlg #include <sys/mbuf.h>
58ccb96312Sdlg #include <sys/socket.h>
59ccb96312Sdlg #include <sys/device.h>
60ccb96312Sdlg #include <sys/pool.h>
61ccb96312Sdlg #include <sys/queue.h>
62ccb96312Sdlg #include <sys/timeout.h>
63ccb96312Sdlg #include <sys/task.h>
64d3ac7020Sdlg #include <sys/syslog.h>
65e01adc04Sdlg #include <sys/intrmap.h>
66ccb96312Sdlg 
67ccb96312Sdlg #include <machine/bus.h>
68ccb96312Sdlg #include <machine/intr.h>
69ccb96312Sdlg 
70ccb96312Sdlg #include <net/if.h>
71ccb96312Sdlg #include <net/if_media.h>
72f77c9c95Sjan #include <net/route.h>
73819ac441Sdlg #include <net/toeplitz.h>
74ccb96312Sdlg 
75ccb96312Sdlg #if NBPFILTER > 0
76ccb96312Sdlg #include <net/bpf.h>
77ccb96312Sdlg #endif
78ccb96312Sdlg 
792ee1fcb3Sdlg #if NKSTAT > 0
802ee1fcb3Sdlg #include <sys/kstat.h>
812ee1fcb3Sdlg #endif
822ee1fcb3Sdlg 
83ccb96312Sdlg #include <netinet/in.h>
8438ec96dbSjan #include <netinet/if_ether.h>
8504206048Sdlg #include <netinet/tcp.h>
86f77c9c95Sjan #include <netinet/tcp_timer.h>
87f77c9c95Sjan #include <netinet/tcp_var.h>
8804206048Sdlg #include <netinet/udp.h>
89ccb96312Sdlg 
90ccb96312Sdlg #include <dev/pci/pcireg.h>
91ccb96312Sdlg #include <dev/pci/pcivar.h>
92ccb96312Sdlg #include <dev/pci/pcidevs.h>
93ccb96312Sdlg 
9412b3627cSjmatthew #ifdef __sparc64__
9512b3627cSjmatthew #include <dev/ofw/openfirm.h>
9612b3627cSjmatthew #endif
9712b3627cSjmatthew 
98e01adc04Sdlg #ifndef CACHE_LINE_SIZE
99e01adc04Sdlg #define CACHE_LINE_SIZE 64
100e01adc04Sdlg #endif
101e01adc04Sdlg 
102e01adc04Sdlg #define IXL_MAX_VECTORS			8 /* XXX this is pretty arbitrary */
103e01adc04Sdlg 
104ccb96312Sdlg #define I40E_MASK(mask, shift)		((mask) << (shift))
105ccb96312Sdlg #define I40E_PF_RESET_WAIT_COUNT	200
106ccb96312Sdlg #define I40E_AQ_LARGE_BUF		512
107ccb96312Sdlg 
108ccb96312Sdlg /* bitfields for Tx queue mapping in QTX_CTL */
109ccb96312Sdlg #define I40E_QTX_CTL_VF_QUEUE		0x0
110ccb96312Sdlg #define I40E_QTX_CTL_VM_QUEUE		0x1
111ccb96312Sdlg #define I40E_QTX_CTL_PF_QUEUE		0x2
112ccb96312Sdlg 
113eb1b42e4Sdlg #define I40E_QUEUE_TYPE_EOL		0x7ff
114eb1b42e4Sdlg #define I40E_INTR_NOTX_QUEUE		0
115eb1b42e4Sdlg 
116eb1b42e4Sdlg #define I40E_QUEUE_TYPE_RX		0x0
117eb1b42e4Sdlg #define I40E_QUEUE_TYPE_TX		0x1
118eb1b42e4Sdlg #define I40E_QUEUE_TYPE_PE_CEQ		0x2
119eb1b42e4Sdlg #define I40E_QUEUE_TYPE_UNKNOWN		0x3
120eb1b42e4Sdlg 
121eb1b42e4Sdlg #define I40E_ITR_INDEX_RX		0x0
122eb1b42e4Sdlg #define I40E_ITR_INDEX_TX		0x1
123eb1b42e4Sdlg #define I40E_ITR_INDEX_OTHER		0x2
124eb1b42e4Sdlg #define I40E_ITR_INDEX_NONE		0x3
125eb1b42e4Sdlg 
126ccb96312Sdlg #include <dev/pci/if_ixlreg.h>
127ccb96312Sdlg 
128eb1b42e4Sdlg #define I40E_INTR_NOTX_QUEUE		0
129eb1b42e4Sdlg #define I40E_INTR_NOTX_INTR		0
130eb1b42e4Sdlg #define I40E_INTR_NOTX_RX_QUEUE		0
131eb1b42e4Sdlg #define I40E_INTR_NOTX_TX_QUEUE		1
132eb1b42e4Sdlg #define I40E_INTR_NOTX_RX_MASK		I40E_PFINT_ICR0_QUEUE_0_MASK
133eb1b42e4Sdlg #define I40E_INTR_NOTX_TX_MASK		I40E_PFINT_ICR0_QUEUE_1_MASK
134eb1b42e4Sdlg 
135ccb96312Sdlg struct ixl_aq_desc {
136ccb96312Sdlg 	uint16_t	iaq_flags;
137ccb96312Sdlg #define	IXL_AQ_DD		(1U << 0)
138ccb96312Sdlg #define	IXL_AQ_CMP		(1U << 1)
139ccb96312Sdlg #define IXL_AQ_ERR		(1U << 2)
140ccb96312Sdlg #define IXL_AQ_VFE		(1U << 3)
141ccb96312Sdlg #define IXL_AQ_LB		(1U << 9)
142ccb96312Sdlg #define IXL_AQ_RD		(1U << 10)
143ccb96312Sdlg #define IXL_AQ_VFC		(1U << 11)
144ccb96312Sdlg #define IXL_AQ_BUF		(1U << 12)
145ccb96312Sdlg #define IXL_AQ_SI		(1U << 13)
146ccb96312Sdlg #define IXL_AQ_EI		(1U << 14)
147ccb96312Sdlg #define IXL_AQ_FE		(1U << 15)
148ccb96312Sdlg 
149ccb96312Sdlg #define IXL_AQ_FLAGS_FMT	"\020" "\020FE" "\017EI" "\016SI" "\015BUF" \
150ccb96312Sdlg 				    "\014VFC" "\013DB" "\012LB" "\004VFE" \
151ccb96312Sdlg 				    "\003ERR" "\002CMP" "\001DD"
152ccb96312Sdlg 
153ccb96312Sdlg 	uint16_t	iaq_opcode;
154ccb96312Sdlg 
155ccb96312Sdlg 	uint16_t	iaq_datalen;
156ccb96312Sdlg 	uint16_t	iaq_retval;
157ccb96312Sdlg 
158ccb96312Sdlg 	uint64_t	iaq_cookie;
159ccb96312Sdlg 
160ccb96312Sdlg 	uint32_t	iaq_param[4];
161ccb96312Sdlg /*	iaq_data_hi	iaq_param[2] */
162ccb96312Sdlg /*	iaq_data_lo	iaq_param[3] */
1637e7a8c99Sdlg } __packed __aligned(8);
164ccb96312Sdlg 
165ccb96312Sdlg /* aq commands */
166ccb96312Sdlg #define IXL_AQ_OP_GET_VERSION		0x0001
167ccb96312Sdlg #define IXL_AQ_OP_DRIVER_VERSION	0x0002
168ccb96312Sdlg #define IXL_AQ_OP_QUEUE_SHUTDOWN	0x0003
169ccb96312Sdlg #define IXL_AQ_OP_SET_PF_CONTEXT	0x0004
170ccb96312Sdlg #define IXL_AQ_OP_GET_AQ_ERR_REASON	0x0005
171ccb96312Sdlg #define IXL_AQ_OP_REQUEST_RESOURCE	0x0008
172ccb96312Sdlg #define IXL_AQ_OP_RELEASE_RESOURCE	0x0009
173ccb96312Sdlg #define IXL_AQ_OP_LIST_FUNC_CAP		0x000a
174ccb96312Sdlg #define IXL_AQ_OP_LIST_DEV_CAP		0x000b
175ccb96312Sdlg #define IXL_AQ_OP_MAC_ADDRESS_READ	0x0107
176ccb96312Sdlg #define IXL_AQ_OP_CLEAR_PXE_MODE	0x0110
177ccb96312Sdlg #define IXL_AQ_OP_SWITCH_GET_CONFIG	0x0200
178819ac441Sdlg #define IXL_AQ_OP_RX_CTL_READ		0x0206
179819ac441Sdlg #define IXL_AQ_OP_RX_CTL_WRITE		0x0207
180ccb96312Sdlg #define IXL_AQ_OP_ADD_VSI		0x0210
181ccb96312Sdlg #define IXL_AQ_OP_UPD_VSI_PARAMS	0x0211
182ccb96312Sdlg #define IXL_AQ_OP_GET_VSI_PARAMS	0x0212
183ccb96312Sdlg #define IXL_AQ_OP_ADD_VEB		0x0230
184ccb96312Sdlg #define IXL_AQ_OP_UPD_VEB_PARAMS	0x0231
185ccb96312Sdlg #define IXL_AQ_OP_GET_VEB_PARAMS	0x0232
1862bb8400cSjmatthew #define IXL_AQ_OP_ADD_MACVLAN		0x0250
1872bb8400cSjmatthew #define IXL_AQ_OP_REMOVE_MACVLAN	0x0251
188ccb96312Sdlg #define IXL_AQ_OP_SET_VSI_PROMISC	0x0254
189ccb96312Sdlg #define IXL_AQ_OP_PHY_GET_ABILITIES	0x0600
190ccb96312Sdlg #define IXL_AQ_OP_PHY_SET_CONFIG	0x0601
191ccb96312Sdlg #define IXL_AQ_OP_PHY_SET_MAC_CONFIG	0x0603
192ccb96312Sdlg #define IXL_AQ_OP_PHY_RESTART_AN	0x0605
193ccb96312Sdlg #define IXL_AQ_OP_PHY_LINK_STATUS	0x0607
194ccb96312Sdlg #define IXL_AQ_OP_PHY_SET_EVENT_MASK	0x0613
1954eec9beaSdlg #define IXL_AQ_OP_PHY_SET_REGISTER	0x0628
1964eec9beaSdlg #define IXL_AQ_OP_PHY_GET_REGISTER	0x0629
197ccb96312Sdlg #define IXL_AQ_OP_LLDP_GET_MIB		0x0a00
198ccb96312Sdlg #define IXL_AQ_OP_LLDP_MIB_CHG_EV	0x0a01
199ccb96312Sdlg #define IXL_AQ_OP_LLDP_ADD_TLV		0x0a02
200ccb96312Sdlg #define IXL_AQ_OP_LLDP_UPD_TLV		0x0a03
201ccb96312Sdlg #define IXL_AQ_OP_LLDP_DEL_TLV		0x0a04
202ccb96312Sdlg #define IXL_AQ_OP_LLDP_STOP_AGENT	0x0a05
203ccb96312Sdlg #define IXL_AQ_OP_LLDP_START_AGENT	0x0a06
204ccb96312Sdlg #define IXL_AQ_OP_LLDP_GET_CEE_DCBX	0x0a07
205ccb96312Sdlg #define IXL_AQ_OP_LLDP_SPECIFIC_AGENT	0x0a09
206e0731eceSdlg #define IXL_AQ_OP_SET_RSS_KEY		0x0b02 /* 722 only */
207e0731eceSdlg #define IXL_AQ_OP_SET_RSS_LUT		0x0b03 /* 722 only */
208e0731eceSdlg #define IXL_AQ_OP_GET_RSS_KEY		0x0b04 /* 722 only */
209e0731eceSdlg #define IXL_AQ_OP_GET_RSS_LUT		0x0b05 /* 722 only */
210ccb96312Sdlg 
211ccb96312Sdlg struct ixl_aq_mac_addresses {
212ccb96312Sdlg 	uint8_t		pf_lan[ETHER_ADDR_LEN];
213ccb96312Sdlg 	uint8_t		pf_san[ETHER_ADDR_LEN];
214ccb96312Sdlg 	uint8_t		port[ETHER_ADDR_LEN];
215ccb96312Sdlg 	uint8_t		pf_wol[ETHER_ADDR_LEN];
216ccb96312Sdlg } __packed;
217ccb96312Sdlg 
218ccb96312Sdlg #define IXL_AQ_MAC_PF_LAN_VALID		(1U << 4)
219ccb96312Sdlg #define IXL_AQ_MAC_PF_SAN_VALID		(1U << 5)
220ccb96312Sdlg #define IXL_AQ_MAC_PORT_VALID		(1U << 6)
221ccb96312Sdlg #define IXL_AQ_MAC_PF_WOL_VALID		(1U << 7)
222ccb96312Sdlg 
223ccb96312Sdlg struct ixl_aq_capability {
224ccb96312Sdlg 	uint16_t	cap_id;
225ccb96312Sdlg #define IXL_AQ_CAP_SWITCH_MODE		0x0001
226ccb96312Sdlg #define IXL_AQ_CAP_MNG_MODE		0x0002
227ccb96312Sdlg #define IXL_AQ_CAP_NPAR_ACTIVE		0x0003
228ccb96312Sdlg #define IXL_AQ_CAP_OS2BMC_CAP		0x0004
229ccb96312Sdlg #define IXL_AQ_CAP_FUNCTIONS_VALID	0x0005
230ccb96312Sdlg #define IXL_AQ_CAP_ALTERNATE_RAM	0x0006
231ccb96312Sdlg #define IXL_AQ_CAP_WOL_AND_PROXY	0x0008
232ccb96312Sdlg #define IXL_AQ_CAP_SRIOV		0x0012
233ccb96312Sdlg #define IXL_AQ_CAP_VF			0x0013
234ccb96312Sdlg #define IXL_AQ_CAP_VMDQ			0x0014
235ccb96312Sdlg #define IXL_AQ_CAP_8021QBG		0x0015
236ccb96312Sdlg #define IXL_AQ_CAP_8021QBR		0x0016
237ccb96312Sdlg #define IXL_AQ_CAP_VSI			0x0017
238ccb96312Sdlg #define IXL_AQ_CAP_DCB			0x0018
239ccb96312Sdlg #define IXL_AQ_CAP_FCOE			0x0021
240ccb96312Sdlg #define IXL_AQ_CAP_ISCSI		0x0022
241ccb96312Sdlg #define IXL_AQ_CAP_RSS			0x0040
242ccb96312Sdlg #define IXL_AQ_CAP_RXQ			0x0041
243ccb96312Sdlg #define IXL_AQ_CAP_TXQ			0x0042
244ccb96312Sdlg #define IXL_AQ_CAP_MSIX			0x0043
245ccb96312Sdlg #define IXL_AQ_CAP_VF_MSIX		0x0044
246ccb96312Sdlg #define IXL_AQ_CAP_FLOW_DIRECTOR	0x0045
247ccb96312Sdlg #define IXL_AQ_CAP_1588			0x0046
248ccb96312Sdlg #define IXL_AQ_CAP_IWARP		0x0051
249ccb96312Sdlg #define IXL_AQ_CAP_LED			0x0061
250ccb96312Sdlg #define IXL_AQ_CAP_SDP			0x0062
251ccb96312Sdlg #define IXL_AQ_CAP_MDIO			0x0063
252ccb96312Sdlg #define IXL_AQ_CAP_WSR_PROT		0x0064
253ccb96312Sdlg #define IXL_AQ_CAP_NVM_MGMT		0x0080
254ccb96312Sdlg #define IXL_AQ_CAP_FLEX10		0x00F1
255ccb96312Sdlg #define IXL_AQ_CAP_CEM			0x00F2
256ccb96312Sdlg 	uint8_t		major_rev;
257ccb96312Sdlg 	uint8_t		minor_rev;
258ccb96312Sdlg 	uint32_t	number;
259ccb96312Sdlg 	uint32_t	logical_id;
260ccb96312Sdlg 	uint32_t	phys_id;
261ccb96312Sdlg 	uint8_t		_reserved[16];
262ccb96312Sdlg } __packed __aligned(4);
263ccb96312Sdlg 
264ccb96312Sdlg #define IXL_LLDP_SHUTDOWN		0x1
265ccb96312Sdlg 
266ccb96312Sdlg struct ixl_aq_switch_config {
267ccb96312Sdlg 	uint16_t	num_reported;
268ccb96312Sdlg 	uint16_t	num_total;
269ccb96312Sdlg 	uint8_t		_reserved[12];
270ccb96312Sdlg } __packed __aligned(4);
271ccb96312Sdlg 
272ccb96312Sdlg struct ixl_aq_switch_config_element {
273ccb96312Sdlg 	uint8_t		type;
274ccb96312Sdlg #define IXL_AQ_SW_ELEM_TYPE_MAC		1
275ccb96312Sdlg #define IXL_AQ_SW_ELEM_TYPE_PF		2
276ccb96312Sdlg #define IXL_AQ_SW_ELEM_TYPE_VF		3
277ccb96312Sdlg #define IXL_AQ_SW_ELEM_TYPE_EMP		4
278ccb96312Sdlg #define IXL_AQ_SW_ELEM_TYPE_BMC		5
279ccb96312Sdlg #define IXL_AQ_SW_ELEM_TYPE_PV		16
280ccb96312Sdlg #define IXL_AQ_SW_ELEM_TYPE_VEB		17
281ccb96312Sdlg #define IXL_AQ_SW_ELEM_TYPE_PA		18
282ccb96312Sdlg #define IXL_AQ_SW_ELEM_TYPE_VSI		19
283ccb96312Sdlg 	uint8_t		revision;
284ccb96312Sdlg #define IXL_AQ_SW_ELEM_REV_1		1
285ccb96312Sdlg 	uint16_t	seid;
286ccb96312Sdlg 
287ccb96312Sdlg 	uint16_t	uplink_seid;
288ccb96312Sdlg 	uint16_t	downlink_seid;
289ccb96312Sdlg 
290ccb96312Sdlg 	uint8_t		_reserved[3];
291ccb96312Sdlg 	uint8_t		connection_type;
292ccb96312Sdlg #define IXL_AQ_CONN_TYPE_REGULAR	0x1
293ccb96312Sdlg #define IXL_AQ_CONN_TYPE_DEFAULT	0x2
294ccb96312Sdlg #define IXL_AQ_CONN_TYPE_CASCADED	0x3
295ccb96312Sdlg 
296ccb96312Sdlg 	uint16_t	scheduler_id;
297ccb96312Sdlg 	uint16_t	element_info;
298ccb96312Sdlg } __packed __aligned(4);
299ccb96312Sdlg 
300ccb96312Sdlg #define IXL_PHY_TYPE_SGMII		0x00
301ccb96312Sdlg #define IXL_PHY_TYPE_1000BASE_KX	0x01
302ccb96312Sdlg #define IXL_PHY_TYPE_10GBASE_KX4	0x02
303ccb96312Sdlg #define IXL_PHY_TYPE_10GBASE_KR		0x03
304ccb96312Sdlg #define IXL_PHY_TYPE_40GBASE_KR4	0x04
305ccb96312Sdlg #define IXL_PHY_TYPE_XAUI		0x05
306ccb96312Sdlg #define IXL_PHY_TYPE_XFI		0x06
307ccb96312Sdlg #define IXL_PHY_TYPE_SFI		0x07
308ccb96312Sdlg #define IXL_PHY_TYPE_XLAUI		0x08
309ccb96312Sdlg #define IXL_PHY_TYPE_XLPPI		0x09
310ccb96312Sdlg #define IXL_PHY_TYPE_40GBASE_CR4_CU	0x0a
311ccb96312Sdlg #define IXL_PHY_TYPE_10GBASE_CR1_CU	0x0b
312ccb96312Sdlg #define IXL_PHY_TYPE_10GBASE_AOC	0x0c
313ccb96312Sdlg #define IXL_PHY_TYPE_40GBASE_AOC	0x0d
314ccb96312Sdlg #define IXL_PHY_TYPE_100BASE_TX		0x11
315ccb96312Sdlg #define IXL_PHY_TYPE_1000BASE_T		0x12
316ccb96312Sdlg #define IXL_PHY_TYPE_10GBASE_T		0x13
317ccb96312Sdlg #define IXL_PHY_TYPE_10GBASE_SR		0x14
318ccb96312Sdlg #define IXL_PHY_TYPE_10GBASE_LR		0x15
319ccb96312Sdlg #define IXL_PHY_TYPE_10GBASE_SFPP_CU	0x16
320ccb96312Sdlg #define IXL_PHY_TYPE_10GBASE_CR1	0x17
321ccb96312Sdlg #define IXL_PHY_TYPE_40GBASE_CR4	0x18
322ccb96312Sdlg #define IXL_PHY_TYPE_40GBASE_SR4	0x19
323ccb96312Sdlg #define IXL_PHY_TYPE_40GBASE_LR4	0x1a
324ccb96312Sdlg #define IXL_PHY_TYPE_1000BASE_SX	0x1b
325ccb96312Sdlg #define IXL_PHY_TYPE_1000BASE_LX	0x1c
326ccb96312Sdlg #define IXL_PHY_TYPE_1000BASE_T_OPTICAL	0x1d
327ccb96312Sdlg #define IXL_PHY_TYPE_20GBASE_KR2	0x1e
328ccb96312Sdlg 
329ccb96312Sdlg #define IXL_PHY_TYPE_25GBASE_KR		0x1f
330ccb96312Sdlg #define IXL_PHY_TYPE_25GBASE_CR		0x20
331ccb96312Sdlg #define IXL_PHY_TYPE_25GBASE_SR		0x21
332ccb96312Sdlg #define IXL_PHY_TYPE_25GBASE_LR		0x22
333ccb96312Sdlg #define IXL_PHY_TYPE_25GBASE_AOC	0x23
334ccb96312Sdlg #define IXL_PHY_TYPE_25GBASE_ACC	0x24
335ccb96312Sdlg 
336ccb96312Sdlg struct ixl_aq_module_desc {
337ccb96312Sdlg 	uint8_t		oui[3];
338ccb96312Sdlg 	uint8_t		_reserved1;
339ccb96312Sdlg 	uint8_t		part_number[16];
340ccb96312Sdlg 	uint8_t		revision[4];
341ccb96312Sdlg 	uint8_t		_reserved2[8];
342ccb96312Sdlg } __packed __aligned(4);
343ccb96312Sdlg 
344ccb96312Sdlg struct ixl_aq_phy_abilities {
345ccb96312Sdlg 	uint32_t	phy_type;
346ccb96312Sdlg 
347ccb96312Sdlg 	uint8_t		link_speed;
348185ef768Syasuoka #define IXL_AQ_PHY_LINK_SPEED_100MB	(1 << 1)
349185ef768Syasuoka #define IXL_AQ_PHY_LINK_SPEED_1000MB	(1 << 2)
350185ef768Syasuoka #define IXL_AQ_PHY_LINK_SPEED_10GB	(1 << 3)
351185ef768Syasuoka #define IXL_AQ_PHY_LINK_SPEED_40GB	(1 << 4)
352185ef768Syasuoka #define IXL_AQ_PHY_LINK_SPEED_20GB	(1 << 5)
353185ef768Syasuoka #define IXL_AQ_PHY_LINK_SPEED_25GB	(1 << 6)
354ccb96312Sdlg 	uint8_t		abilities;
355ccb96312Sdlg 	uint16_t	eee_capability;
356ccb96312Sdlg 
357ccb96312Sdlg 	uint32_t	eeer_val;
358ccb96312Sdlg 
359ccb96312Sdlg 	uint8_t		d3_lpan;
360ccb96312Sdlg 	uint8_t		phy_type_ext;
361ccb96312Sdlg #define IXL_AQ_PHY_TYPE_EXT_25G_KR	0x01
362ccb96312Sdlg #define IXL_AQ_PHY_TYPE_EXT_25G_CR	0x02
363ccb96312Sdlg #define IXL_AQ_PHY_TYPE_EXT_25G_SR	0x04
364ccb96312Sdlg #define IXL_AQ_PHY_TYPE_EXT_25G_LR	0x08
365ccb96312Sdlg 	uint8_t		fec_cfg_curr_mod_ext_info;
366ccb96312Sdlg #define IXL_AQ_ENABLE_FEC_KR		0x01
367ccb96312Sdlg #define IXL_AQ_ENABLE_FEC_RS		0x02
368ccb96312Sdlg #define IXL_AQ_REQUEST_FEC_KR		0x04
369ccb96312Sdlg #define IXL_AQ_REQUEST_FEC_RS		0x08
370ccb96312Sdlg #define IXL_AQ_ENABLE_FEC_AUTO		0x10
371ccb96312Sdlg #define IXL_AQ_MODULE_TYPE_EXT_MASK	0xe0
372ccb96312Sdlg #define IXL_AQ_MODULE_TYPE_EXT_SHIFT	5
373ccb96312Sdlg 	uint8_t		ext_comp_code;
374ccb96312Sdlg 
375ccb96312Sdlg 	uint8_t		phy_id[4];
376ccb96312Sdlg 
377ccb96312Sdlg 	uint8_t		module_type[3];
37825fbbcc0Sdlg #define IXL_SFF8024_ID_SFP		0x03
37925fbbcc0Sdlg #define IXL_SFF8024_ID_QSFP		0x0c
38025fbbcc0Sdlg #define IXL_SFF8024_ID_QSFP_PLUS	0x0d
38125fbbcc0Sdlg #define IXL_SFF8024_ID_QSFP28		0x11
382ccb96312Sdlg 	uint8_t		qualified_module_count;
383ccb96312Sdlg #define IXL_AQ_PHY_MAX_QMS		16
384ccb96312Sdlg 	struct ixl_aq_module_desc
385ccb96312Sdlg 			qualified_module[IXL_AQ_PHY_MAX_QMS];
386ccb96312Sdlg } __packed __aligned(4);
387ccb96312Sdlg 
3887f4b2a0fSjmatthew struct ixl_aq_link_param {
3897f4b2a0fSjmatthew 	uint8_t		notify;
3907f4b2a0fSjmatthew #define IXL_AQ_LINK_NOTIFY	0x03
3917f4b2a0fSjmatthew 	uint8_t		_reserved1;
3927f4b2a0fSjmatthew 	uint8_t		phy;
3937f4b2a0fSjmatthew 	uint8_t		speed;
3947f4b2a0fSjmatthew 	uint8_t		status;
3957f4b2a0fSjmatthew 	uint8_t		_reserved2[11];
3967f4b2a0fSjmatthew } __packed __aligned(4);
3977f4b2a0fSjmatthew 
398ccb96312Sdlg struct ixl_aq_vsi_param {
399ccb96312Sdlg 	uint16_t	uplink_seid;
400ccb96312Sdlg 	uint8_t		connect_type;
401ccb96312Sdlg #define IXL_AQ_VSI_CONN_TYPE_NORMAL	(0x1)
402ccb96312Sdlg #define IXL_AQ_VSI_CONN_TYPE_DEFAULT	(0x2)
403ccb96312Sdlg #define IXL_AQ_VSI_CONN_TYPE_CASCADED	(0x3)
404ccb96312Sdlg 	uint8_t		_reserved1;
405ccb96312Sdlg 
406ccb96312Sdlg 	uint8_t		vf_id;
407ccb96312Sdlg 	uint8_t		_reserved2;
408ccb96312Sdlg 	uint16_t	vsi_flags;
409ccb96312Sdlg #define IXL_AQ_VSI_TYPE_SHIFT		0x0
410ccb96312Sdlg #define IXL_AQ_VSI_TYPE_MASK		(0x3 << IXL_AQ_VSI_TYPE_SHIFT)
411ccb96312Sdlg #define IXL_AQ_VSI_TYPE_VF		0x0
412ccb96312Sdlg #define IXL_AQ_VSI_TYPE_VMDQ2		0x1
413ccb96312Sdlg #define IXL_AQ_VSI_TYPE_PF		0x2
414ccb96312Sdlg #define IXL_AQ_VSI_TYPE_EMP_MNG		0x3
415ccb96312Sdlg #define IXL_AQ_VSI_FLAG_CASCADED_PV	0x4
416ccb96312Sdlg 
417ccb96312Sdlg 	uint32_t	addr_hi;
418ccb96312Sdlg 	uint32_t	addr_lo;
419ccb96312Sdlg } __packed __aligned(16);
420ccb96312Sdlg 
4212bb8400cSjmatthew struct ixl_aq_add_macvlan {
4222bb8400cSjmatthew 	uint16_t	num_addrs;
4232bb8400cSjmatthew 	uint16_t	seid0;
4242bb8400cSjmatthew 	uint16_t	seid1;
4252bb8400cSjmatthew 	uint16_t	seid2;
4262bb8400cSjmatthew 	uint32_t	addr_hi;
4272bb8400cSjmatthew 	uint32_t	addr_lo;
4282bb8400cSjmatthew } __packed __aligned(16);
4292bb8400cSjmatthew 
4302bb8400cSjmatthew struct ixl_aq_add_macvlan_elem {
4312bb8400cSjmatthew 	uint8_t		macaddr[6];
4322bb8400cSjmatthew 	uint16_t	vlan;
4332bb8400cSjmatthew 	uint16_t	flags;
4342bb8400cSjmatthew #define IXL_AQ_OP_ADD_MACVLAN_PERFECT_MATCH	0x0001
4352bb8400cSjmatthew #define IXL_AQ_OP_ADD_MACVLAN_IGNORE_VLAN	0x0004
4362bb8400cSjmatthew 	uint16_t	queue;
4372bb8400cSjmatthew 	uint32_t	_reserved;
4382bb8400cSjmatthew } __packed __aligned(16);
4392bb8400cSjmatthew 
4402bb8400cSjmatthew struct ixl_aq_remove_macvlan {
4412bb8400cSjmatthew 	uint16_t	num_addrs;
4422bb8400cSjmatthew 	uint16_t	seid0;
4432bb8400cSjmatthew 	uint16_t	seid1;
4442bb8400cSjmatthew 	uint16_t	seid2;
4452bb8400cSjmatthew 	uint32_t	addr_hi;
4462bb8400cSjmatthew 	uint32_t	addr_lo;
4472bb8400cSjmatthew } __packed __aligned(16);
4482bb8400cSjmatthew 
4492bb8400cSjmatthew struct ixl_aq_remove_macvlan_elem {
4502bb8400cSjmatthew 	uint8_t		macaddr[6];
4512bb8400cSjmatthew 	uint16_t	vlan;
4522bb8400cSjmatthew 	uint8_t		flags;
4532bb8400cSjmatthew #define IXL_AQ_OP_REMOVE_MACVLAN_PERFECT_MATCH	0x0001
4542bb8400cSjmatthew #define IXL_AQ_OP_REMOVE_MACVLAN_IGNORE_VLAN	0x0008
4552bb8400cSjmatthew 	uint8_t		_reserved[7];
4562bb8400cSjmatthew } __packed __aligned(16);
4572bb8400cSjmatthew 
458ccb96312Sdlg struct ixl_aq_vsi_reply {
459ccb96312Sdlg 	uint16_t	seid;
460ccb96312Sdlg 	uint16_t	vsi_number;
461ccb96312Sdlg 
462ccb96312Sdlg 	uint16_t	vsis_used;
463ccb96312Sdlg 	uint16_t	vsis_free;
464ccb96312Sdlg 
465ccb96312Sdlg 	uint32_t	addr_hi;
466ccb96312Sdlg 	uint32_t	addr_lo;
467ccb96312Sdlg } __packed __aligned(16);
468ccb96312Sdlg 
469ccb96312Sdlg struct ixl_aq_vsi_data {
470ccb96312Sdlg 	/* first 96 byte are written by SW */
471ccb96312Sdlg 	uint16_t	valid_sections;
472ccb96312Sdlg #define IXL_AQ_VSI_VALID_SWITCH		(1 << 0)
473ccb96312Sdlg #define IXL_AQ_VSI_VALID_SECURITY	(1 << 1)
474ccb96312Sdlg #define IXL_AQ_VSI_VALID_VLAN		(1 << 2)
475ccb96312Sdlg #define IXL_AQ_VSI_VALID_CAS_PV		(1 << 3)
476ccb96312Sdlg #define IXL_AQ_VSI_VALID_INGRESS_UP	(1 << 4)
477ccb96312Sdlg #define IXL_AQ_VSI_VALID_EGRESS_UP	(1 << 5)
478ccb96312Sdlg #define IXL_AQ_VSI_VALID_QUEUE_MAP	(1 << 6)
479ccb96312Sdlg #define IXL_AQ_VSI_VALID_QUEUE_OPT	(1 << 7)
480ccb96312Sdlg #define IXL_AQ_VSI_VALID_OUTER_UP	(1 << 8)
481ccb96312Sdlg #define IXL_AQ_VSI_VALID_SCHED		(1 << 9)
482ccb96312Sdlg 	/* switch section */
483ccb96312Sdlg 	uint16_t	switch_id;
484ccb96312Sdlg #define IXL_AQ_VSI_SWITCH_ID_SHIFT	0
485ccb96312Sdlg #define IXL_AQ_VSI_SWITCH_ID_MASK	(0xfff << IXL_AQ_VSI_SWITCH_ID_SHIFT)
486ccb96312Sdlg #define IXL_AQ_VSI_SWITCH_NOT_STAG	(1 << 12)
487ccb96312Sdlg #define IXL_AQ_VSI_SWITCH_LOCAL_LB	(1 << 14)
488ccb96312Sdlg 
489ccb96312Sdlg 	uint8_t		_reserved1[2];
490ccb96312Sdlg 	/* security section */
491ccb96312Sdlg 	uint8_t		sec_flags;
492ccb96312Sdlg #define IXL_AQ_VSI_SEC_ALLOW_DEST_OVRD	(1 << 0)
493ccb96312Sdlg #define IXL_AQ_VSI_SEC_ENABLE_VLAN_CHK	(1 << 1)
494ccb96312Sdlg #define IXL_AQ_VSI_SEC_ENABLE_MAC_CHK	(1 << 2)
495ccb96312Sdlg 	uint8_t		_reserved2;
496ccb96312Sdlg 
497ccb96312Sdlg 	/* vlan section */
498ccb96312Sdlg 	uint16_t	pvid;
499ccb96312Sdlg 	uint16_t	fcoe_pvid;
500ccb96312Sdlg 
501ccb96312Sdlg 	uint8_t		port_vlan_flags;
502ccb96312Sdlg #define IXL_AQ_VSI_PVLAN_MODE_SHIFT	0
503ccb96312Sdlg #define IXL_AQ_VSI_PVLAN_MODE_MASK	(0x3 << IXL_AQ_VSI_PVLAN_MODE_SHIFT)
504ccb96312Sdlg #define IXL_AQ_VSI_PVLAN_MODE_TAGGED	(0x1 << IXL_AQ_VSI_PVLAN_MODE_SHIFT)
505ccb96312Sdlg #define IXL_AQ_VSI_PVLAN_MODE_UNTAGGED	(0x2 << IXL_AQ_VSI_PVLAN_MODE_SHIFT)
506ccb96312Sdlg #define IXL_AQ_VSI_PVLAN_MODE_ALL	(0x3 << IXL_AQ_VSI_PVLAN_MODE_SHIFT)
507ccb96312Sdlg #define IXL_AQ_VSI_PVLAN_INSERT_PVID	(0x4 << IXL_AQ_VSI_PVLAN_MODE_SHIFT)
508ccb96312Sdlg #define IXL_AQ_VSI_PVLAN_EMOD_SHIFT	0x3
509ccb96312Sdlg #define IXL_AQ_VSI_PVLAN_EMOD_MASK	(0x3 << IXL_AQ_VSI_PVLAN_EMOD_SHIFT)
510ccb96312Sdlg #define IXL_AQ_VSI_PVLAN_EMOD_STR_BOTH	(0x0 << IXL_AQ_VSI_PVLAN_EMOD_SHIFT)
511ccb96312Sdlg #define IXL_AQ_VSI_PVLAN_EMOD_STR_UP	(0x1 << IXL_AQ_VSI_PVLAN_EMOD_SHIFT)
512ccb96312Sdlg #define IXL_AQ_VSI_PVLAN_EMOD_STR	(0x2 << IXL_AQ_VSI_PVLAN_EMOD_SHIFT)
513ccb96312Sdlg #define IXL_AQ_VSI_PVLAN_EMOD_NOTHING	(0x3 << IXL_AQ_VSI_PVLAN_EMOD_SHIFT)
514ccb96312Sdlg 	uint8_t		_reserved3[3];
515ccb96312Sdlg 
516ccb96312Sdlg 	/* ingress egress up section */
517ccb96312Sdlg 	uint32_t	ingress_table;
518ccb96312Sdlg #define IXL_AQ_VSI_UP_SHIFT(_up)	((_up) * 3)
519ccb96312Sdlg #define IXL_AQ_VSI_UP_MASK(_up)		(0x7 << (IXL_AQ_VSI_UP_SHIFT(_up))
520ccb96312Sdlg 	uint32_t	egress_table;
521ccb96312Sdlg 
522ccb96312Sdlg 	/* cascaded pv section */
523ccb96312Sdlg 	uint16_t	cas_pv_tag;
524ccb96312Sdlg 	uint8_t		cas_pv_flags;
525ccb96312Sdlg #define IXL_AQ_VSI_CAS_PV_TAGX_SHIFT	0
526ccb96312Sdlg #define IXL_AQ_VSI_CAS_PV_TAGX_MASK	(0x3 << IXL_AQ_VSI_CAS_PV_TAGX_SHIFT)
527ccb96312Sdlg #define IXL_AQ_VSI_CAS_PV_TAGX_LEAVE	(0x0 << IXL_AQ_VSI_CAS_PV_TAGX_SHIFT)
528ccb96312Sdlg #define IXL_AQ_VSI_CAS_PV_TAGX_REMOVE	(0x1 << IXL_AQ_VSI_CAS_PV_TAGX_SHIFT)
529ccb96312Sdlg #define IXL_AQ_VSI_CAS_PV_TAGX_COPY	(0x2 << IXL_AQ_VSI_CAS_PV_TAGX_SHIFT)
530ccb96312Sdlg #define IXL_AQ_VSI_CAS_PV_INSERT_TAG	(1 << 4)
531ccb96312Sdlg #define IXL_AQ_VSI_CAS_PV_ETAG_PRUNE	(1 << 5)
532ccb96312Sdlg #define IXL_AQ_VSI_CAS_PV_ACCEPT_HOST_TAG \
533ccb96312Sdlg 					(1 << 6)
534ccb96312Sdlg 	uint8_t		_reserved4;
535ccb96312Sdlg 
536ccb96312Sdlg 	/* queue mapping section */
537ccb96312Sdlg 	uint16_t	mapping_flags;
538ccb96312Sdlg #define IXL_AQ_VSI_QUE_MAP_MASK		0x1
539ccb96312Sdlg #define IXL_AQ_VSI_QUE_MAP_CONTIG	0x0
540ccb96312Sdlg #define IXL_AQ_VSI_QUE_MAP_NONCONTIG	0x1
541ccb96312Sdlg 	uint16_t	queue_mapping[16];
542ccb96312Sdlg #define IXL_AQ_VSI_QUEUE_SHIFT		0x0
543ccb96312Sdlg #define IXL_AQ_VSI_QUEUE_MASK		(0x7ff << IXL_AQ_VSI_QUEUE_SHIFT)
544ccb96312Sdlg 	uint16_t	tc_mapping[8];
545ccb96312Sdlg #define IXL_AQ_VSI_TC_Q_OFFSET_SHIFT	0
546ccb96312Sdlg #define IXL_AQ_VSI_TC_Q_OFFSET_MASK	(0x1ff << IXL_AQ_VSI_TC_Q_OFFSET_SHIFT)
547ccb96312Sdlg #define IXL_AQ_VSI_TC_Q_NUMBER_SHIFT	9
548ccb96312Sdlg #define IXL_AQ_VSI_TC_Q_NUMBER_MASK	(0x7 << IXL_AQ_VSI_TC_Q_NUMBER_SHIFT)
549ccb96312Sdlg 
550ccb96312Sdlg 	/* queueing option section */
551ccb96312Sdlg 	uint8_t		queueing_opt_flags;
552ccb96312Sdlg #define IXL_AQ_VSI_QUE_OPT_MCAST_UDP_EN	(1 << 2)
553ccb96312Sdlg #define IXL_AQ_VSI_QUE_OPT_UCAST_UDP_EN	(1 << 3)
554ccb96312Sdlg #define IXL_AQ_VSI_QUE_OPT_TCP_EN	(1 << 4)
555ccb96312Sdlg #define IXL_AQ_VSI_QUE_OPT_FCOE_EN	(1 << 5)
556ccb96312Sdlg #define IXL_AQ_VSI_QUE_OPT_RSS_LUT_PF	0
557ccb96312Sdlg #define IXL_AQ_VSI_QUE_OPT_RSS_LUT_VSI	(1 << 6)
558ccb96312Sdlg 	uint8_t		_reserved5[3];
559ccb96312Sdlg 
560ccb96312Sdlg 	/* scheduler section */
561ccb96312Sdlg 	uint8_t		up_enable_bits;
562ccb96312Sdlg 	uint8_t		_reserved6;
563ccb96312Sdlg 
564ccb96312Sdlg 	/* outer up section */
565ccb96312Sdlg 	uint32_t	outer_up_table; /* same as ingress/egress tables */
566ccb96312Sdlg 	uint8_t		_reserved7[8];
567ccb96312Sdlg 
568ccb96312Sdlg 	/* last 32 bytes are written by FW */
569ccb96312Sdlg 	uint16_t	qs_handle[8];
570ccb96312Sdlg #define IXL_AQ_VSI_QS_HANDLE_INVALID	0xffff
571ccb96312Sdlg 	uint16_t	stat_counter_idx;
572ccb96312Sdlg 	uint16_t	sched_id;
573ccb96312Sdlg 
574ccb96312Sdlg 	uint8_t		_reserved8[12];
575ccb96312Sdlg } __packed __aligned(8);
576ccb96312Sdlg 
577ccb96312Sdlg CTASSERT(sizeof(struct ixl_aq_vsi_data) == 128);
578ccb96312Sdlg 
579ccb96312Sdlg struct ixl_aq_vsi_promisc_param {
580ccb96312Sdlg 	uint16_t	flags;
581ccb96312Sdlg 	uint16_t	valid_flags;
582ccb96312Sdlg #define IXL_AQ_VSI_PROMISC_FLAG_UCAST	(1 << 0)
583ccb96312Sdlg #define IXL_AQ_VSI_PROMISC_FLAG_MCAST	(1 << 1)
584ccb96312Sdlg #define IXL_AQ_VSI_PROMISC_FLAG_BCAST	(1 << 2)
585ccb96312Sdlg #define IXL_AQ_VSI_PROMISC_FLAG_DFLT	(1 << 3)
586ccb96312Sdlg #define IXL_AQ_VSI_PROMISC_FLAG_VLAN	(1 << 4)
587ccb96312Sdlg #define IXL_AQ_VSI_PROMISC_FLAG_RXONLY	(1 << 15)
588ccb96312Sdlg 
589ccb96312Sdlg 	uint16_t	seid;
590ccb96312Sdlg #define IXL_AQ_VSI_PROMISC_SEID_VALID	(1 << 15)
591ccb96312Sdlg 	uint16_t	vlan;
592ccb96312Sdlg #define IXL_AQ_VSI_PROMISC_VLAN_VALID	(1 << 15)
593ccb96312Sdlg 	uint32_t	reserved[2];
594ccb96312Sdlg } __packed __aligned(8);
595ccb96312Sdlg 
596ccb96312Sdlg struct ixl_aq_veb_param {
597ccb96312Sdlg 	uint16_t	uplink_seid;
598ccb96312Sdlg 	uint16_t	downlink_seid;
599ccb96312Sdlg 	uint16_t	veb_flags;
600ccb96312Sdlg #define IXL_AQ_ADD_VEB_FLOATING		(1 << 0)
601ccb96312Sdlg #define IXL_AQ_ADD_VEB_PORT_TYPE_SHIFT	1
602ccb96312Sdlg #define IXL_AQ_ADD_VEB_PORT_TYPE_MASK	(0x3 << IXL_AQ_ADD_VEB_PORT_TYPE_SHIFT)
603ccb96312Sdlg #define IXL_AQ_ADD_VEB_PORT_TYPE_DEFAULT \
604ccb96312Sdlg 					(0x2 << IXL_AQ_ADD_VEB_PORT_TYPE_SHIFT)
605ccb96312Sdlg #define IXL_AQ_ADD_VEB_PORT_TYPE_DATA	(0x4 << IXL_AQ_ADD_VEB_PORT_TYPE_SHIFT)
606ccb96312Sdlg #define IXL_AQ_ADD_VEB_ENABLE_L2_FILTER	(1 << 3) /* deprecated */
607ccb96312Sdlg #define IXL_AQ_ADD_VEB_DISABLE_STATS	(1 << 4)
608ccb96312Sdlg 	uint8_t		enable_tcs;
609ccb96312Sdlg 	uint8_t		_reserved[9];
610ccb96312Sdlg } __packed __aligned(16);
611ccb96312Sdlg 
612ccb96312Sdlg struct ixl_aq_veb_reply {
613ccb96312Sdlg 	uint16_t	_reserved1;
614ccb96312Sdlg 	uint16_t	_reserved2;
615ccb96312Sdlg 	uint16_t	_reserved3;
616ccb96312Sdlg 	uint16_t	switch_seid;
617ccb96312Sdlg 	uint16_t	veb_seid;
618ccb96312Sdlg #define IXL_AQ_VEB_ERR_FLAG_NO_VEB	(1 << 0)
619ccb96312Sdlg #define IXL_AQ_VEB_ERR_FLAG_NO_SCHED	(1 << 1)
620ccb96312Sdlg #define IXL_AQ_VEB_ERR_FLAG_NO_COUNTER	(1 << 2)
621ccb96312Sdlg #define IXL_AQ_VEB_ERR_FLAG_NO_ENTRY	(1 << 3);
622ccb96312Sdlg 	uint16_t	statistic_index;
623ccb96312Sdlg 	uint16_t	vebs_used;
624ccb96312Sdlg 	uint16_t	vebs_free;
625ccb96312Sdlg } __packed __aligned(16);
626ccb96312Sdlg 
627ccb96312Sdlg /* GET PHY ABILITIES param[0] */
628ccb96312Sdlg #define IXL_AQ_PHY_REPORT_QUAL		(1 << 0)
629ccb96312Sdlg #define IXL_AQ_PHY_REPORT_INIT		(1 << 1)
630ccb96312Sdlg 
6314eec9beaSdlg struct ixl_aq_phy_reg_access {
6324eec9beaSdlg 	uint8_t		phy_iface;
6334eec9beaSdlg #define IXL_AQ_PHY_IF_INTERNAL		0
6344eec9beaSdlg #define IXL_AQ_PHY_IF_EXTERNAL		1
6354eec9beaSdlg #define IXL_AQ_PHY_IF_MODULE		2
6364eec9beaSdlg 	uint8_t		dev_addr;
63725fbbcc0Sdlg 	uint16_t	recall;
63825fbbcc0Sdlg #define IXL_AQ_PHY_QSFP_DEV_ADDR	0
63925fbbcc0Sdlg #define IXL_AQ_PHY_QSFP_LAST		1
6404eec9beaSdlg 	uint32_t	reg;
6414eec9beaSdlg 	uint32_t	val;
6424eec9beaSdlg 	uint32_t	_reserved2;
6434eec9beaSdlg } __packed __aligned(16);
6444eec9beaSdlg 
645ccb96312Sdlg /* RESTART_AN param[0] */
646ccb96312Sdlg #define IXL_AQ_PHY_RESTART_AN		(1 << 1)
647ccb96312Sdlg #define IXL_AQ_PHY_LINK_ENABLE		(1 << 2)
648ccb96312Sdlg 
649ccb96312Sdlg struct ixl_aq_link_status { /* this occupies the iaq_param space */
650ccb96312Sdlg 	uint16_t	command_flags; /* only field set on command */
651ccb96312Sdlg #define IXL_AQ_LSE_MASK			0x3
652ccb96312Sdlg #define IXL_AQ_LSE_NOP			0x0
653ccb96312Sdlg #define IXL_AQ_LSE_DISABLE		0x2
654ccb96312Sdlg #define IXL_AQ_LSE_ENABLE		0x3
655ccb96312Sdlg #define IXL_AQ_LSE_IS_ENABLED		0x1 /* only set in response */
656ccb96312Sdlg 	uint8_t		phy_type;
657ccb96312Sdlg 	uint8_t		link_speed;
658a4742ff3Sdlg #define IXL_AQ_LINK_SPEED_1GB		(1 << 2)
659a4742ff3Sdlg #define IXL_AQ_LINK_SPEED_10GB		(1 << 3)
660a4742ff3Sdlg #define IXL_AQ_LINK_SPEED_40GB		(1 << 4)
661a4742ff3Sdlg #define IXL_AQ_LINK_SPEED_25GB		(1 << 6)
662ccb96312Sdlg 	uint8_t		link_info;
663ccb96312Sdlg #define IXL_AQ_LINK_UP_FUNCTION		0x01
664ccb96312Sdlg #define IXL_AQ_LINK_FAULT		0x02
665ccb96312Sdlg #define IXL_AQ_LINK_FAULT_TX		0x04
666ccb96312Sdlg #define IXL_AQ_LINK_FAULT_RX		0x08
667ccb96312Sdlg #define IXL_AQ_LINK_FAULT_REMOTE	0x10
668ccb96312Sdlg #define IXL_AQ_LINK_UP_PORT		0x20
669ccb96312Sdlg #define IXL_AQ_MEDIA_AVAILABLE		0x40
670ccb96312Sdlg #define IXL_AQ_SIGNAL_DETECT		0x80
671ccb96312Sdlg 	uint8_t		an_info;
672ccb96312Sdlg #define IXL_AQ_AN_COMPLETED		0x01
673ccb96312Sdlg #define IXL_AQ_LP_AN_ABILITY		0x02
674ccb96312Sdlg #define IXL_AQ_PD_FAULT			0x04
675ccb96312Sdlg #define IXL_AQ_FEC_EN			0x08
676ccb96312Sdlg #define IXL_AQ_PHY_LOW_POWER		0x10
677ccb96312Sdlg #define IXL_AQ_LINK_PAUSE_TX		0x20
678ccb96312Sdlg #define IXL_AQ_LINK_PAUSE_RX		0x40
679ccb96312Sdlg #define IXL_AQ_QUALIFIED_MODULE		0x80
680ccb96312Sdlg 
681ccb96312Sdlg 	uint8_t		ext_info;
682ccb96312Sdlg #define IXL_AQ_LINK_PHY_TEMP_ALARM	0x01
683ccb96312Sdlg #define IXL_AQ_LINK_XCESSIVE_ERRORS	0x02
684ccb96312Sdlg #define IXL_AQ_LINK_TX_SHIFT		0x02
685ccb96312Sdlg #define IXL_AQ_LINK_TX_MASK		(0x03 << IXL_AQ_LINK_TX_SHIFT)
686ccb96312Sdlg #define IXL_AQ_LINK_TX_ACTIVE		0x00
687ccb96312Sdlg #define IXL_AQ_LINK_TX_DRAINED		0x01
688ccb96312Sdlg #define IXL_AQ_LINK_TX_FLUSHED		0x03
689ccb96312Sdlg #define IXL_AQ_LINK_FORCED_40G		0x10
690ccb96312Sdlg /* 25G Error Codes */
691ccb96312Sdlg #define IXL_AQ_25G_NO_ERR		0X00
692ccb96312Sdlg #define IXL_AQ_25G_NOT_PRESENT		0X01
693ccb96312Sdlg #define IXL_AQ_25G_NVM_CRC_ERR		0X02
694ccb96312Sdlg #define IXL_AQ_25G_SBUS_UCODE_ERR	0X03
695ccb96312Sdlg #define IXL_AQ_25G_SERDES_UCODE_ERR	0X04
696ccb96312Sdlg #define IXL_AQ_25G_NIMB_UCODE_ERR	0X05
697ccb96312Sdlg 	uint8_t		loopback;
698ccb96312Sdlg 	uint16_t	max_frame_size;
699ccb96312Sdlg 
700ccb96312Sdlg 	uint8_t		config;
701ccb96312Sdlg #define IXL_AQ_CONFIG_FEC_KR_ENA	0x01
702ccb96312Sdlg #define IXL_AQ_CONFIG_FEC_RS_ENA	0x02
703ccb96312Sdlg #define IXL_AQ_CONFIG_CRC_ENA	0x04
704ccb96312Sdlg #define IXL_AQ_CONFIG_PACING_MASK	0x78
705ccb96312Sdlg 	uint8_t		power_desc;
706ccb96312Sdlg #define IXL_AQ_LINK_POWER_CLASS_1	0x00
707ccb96312Sdlg #define IXL_AQ_LINK_POWER_CLASS_2	0x01
708ccb96312Sdlg #define IXL_AQ_LINK_POWER_CLASS_3	0x02
709ccb96312Sdlg #define IXL_AQ_LINK_POWER_CLASS_4	0x03
710ccb96312Sdlg #define IXL_AQ_PWR_CLASS_MASK		0x03
711ccb96312Sdlg 
712ccb96312Sdlg 	uint8_t		reserved[4];
713ccb96312Sdlg } __packed __aligned(4);
714ccb96312Sdlg /* event mask command flags for param[2] */
715ccb96312Sdlg #define IXL_AQ_PHY_EV_MASK		0x3ff
716ccb96312Sdlg #define IXL_AQ_PHY_EV_LINK_UPDOWN	(1 << 1)
717ccb96312Sdlg #define IXL_AQ_PHY_EV_MEDIA_NA		(1 << 2)
718ccb96312Sdlg #define IXL_AQ_PHY_EV_LINK_FAULT	(1 << 3)
719ccb96312Sdlg #define IXL_AQ_PHY_EV_PHY_TEMP_ALARM	(1 << 4)
720ccb96312Sdlg #define IXL_AQ_PHY_EV_EXCESS_ERRORS	(1 << 5)
721ccb96312Sdlg #define IXL_AQ_PHY_EV_SIGNAL_DETECT	(1 << 6)
722ccb96312Sdlg #define IXL_AQ_PHY_EV_AN_COMPLETED	(1 << 7)
723ccb96312Sdlg #define IXL_AQ_PHY_EV_MODULE_QUAL_FAIL	(1 << 8)
724ccb96312Sdlg #define IXL_AQ_PHY_EV_PORT_TX_SUSPENDED	(1 << 9)
725ccb96312Sdlg 
726e0731eceSdlg struct ixl_aq_rss_lut { /* 722 */
727e0731eceSdlg #define IXL_AQ_SET_RSS_LUT_VSI_VALID	(1 << 15)
728e0731eceSdlg #define IXL_AQ_SET_RSS_LUT_VSI_ID_SHIFT	0
729e0731eceSdlg #define IXL_AQ_SET_RSS_LUT_VSI_ID_MASK	\
730e0731eceSdlg 	(0x3FF << IXL_AQ_SET_RSS_LUT_VSI_ID_SHIFT)
731e0731eceSdlg 
732e0731eceSdlg 	uint16_t	vsi_number;
733e0731eceSdlg #define IXL_AQ_SET_RSS_LUT_TABLE_TYPE_SHIFT 0
734e0731eceSdlg #define IXL_AQ_SET_RSS_LUT_TABLE_TYPE_MASK \
735e0731eceSdlg 	(0x1 << IXL_AQ_SET_RSS_LUT_TABLE_TYPE_SHIFT)
736e0731eceSdlg #define IXL_AQ_SET_RSS_LUT_TABLE_TYPE_VSI	0
737e0731eceSdlg #define IXL_AQ_SET_RSS_LUT_TABLE_TYPE_PF	1
738e0731eceSdlg 	uint16_t	flags;
739e0731eceSdlg 	uint8_t		_reserved[4];
740e0731eceSdlg 	uint32_t	addr_hi;
741e0731eceSdlg 	uint32_t	addr_lo;
742e0731eceSdlg } __packed __aligned(16);
743e0731eceSdlg 
744e0731eceSdlg struct ixl_aq_get_set_rss_key { /* 722 */
745e0731eceSdlg #define IXL_AQ_SET_RSS_KEY_VSI_VALID	(1 << 15)
746e0731eceSdlg #define IXL_AQ_SET_RSS_KEY_VSI_ID_SHIFT	0
747e0731eceSdlg #define IXL_AQ_SET_RSS_KEY_VSI_ID_MASK	\
748e0731eceSdlg 	(0x3FF << IXL_AQ_SET_RSS_KEY_VSI_ID_SHIFT)
749e0731eceSdlg 	uint16_t	vsi_number;
750e0731eceSdlg 	uint8_t		_reserved[6];
751e0731eceSdlg 	uint32_t	addr_hi;
752e0731eceSdlg 	uint32_t	addr_lo;
753e0731eceSdlg } __packed __aligned(16);
754e0731eceSdlg 
755ccb96312Sdlg /* aq response codes */
756ccb96312Sdlg #define IXL_AQ_RC_OK			0  /* success */
757ccb96312Sdlg #define IXL_AQ_RC_EPERM			1  /* Operation not permitted */
758ccb96312Sdlg #define IXL_AQ_RC_ENOENT		2  /* No such element */
759ccb96312Sdlg #define IXL_AQ_RC_ESRCH			3  /* Bad opcode */
760ccb96312Sdlg #define IXL_AQ_RC_EINTR			4  /* operation interrupted */
761ccb96312Sdlg #define IXL_AQ_RC_EIO			5  /* I/O error */
762ccb96312Sdlg #define IXL_AQ_RC_ENXIO			6  /* No such resource */
763ccb96312Sdlg #define IXL_AQ_RC_E2BIG			7  /* Arg too long */
764ccb96312Sdlg #define IXL_AQ_RC_EAGAIN		8  /* Try again */
765ccb96312Sdlg #define IXL_AQ_RC_ENOMEM		9  /* Out of memory */
766ccb96312Sdlg #define IXL_AQ_RC_EACCES		10 /* Permission denied */
767ccb96312Sdlg #define IXL_AQ_RC_EFAULT		11 /* Bad address */
768ccb96312Sdlg #define IXL_AQ_RC_EBUSY			12 /* Device or resource busy */
769ccb96312Sdlg #define IXL_AQ_RC_EEXIST		13 /* object already exists */
770ccb96312Sdlg #define IXL_AQ_RC_EINVAL		14 /* invalid argument */
771ccb96312Sdlg #define IXL_AQ_RC_ENOTTY		15 /* not a typewriter */
772ccb96312Sdlg #define IXL_AQ_RC_ENOSPC		16 /* No space or alloc failure */
773ccb96312Sdlg #define IXL_AQ_RC_ENOSYS		17 /* function not implemented */
774ccb96312Sdlg #define IXL_AQ_RC_ERANGE		18 /* parameter out of range */
775ccb96312Sdlg #define IXL_AQ_RC_EFLUSHED		19 /* cmd flushed due to prev error */
776ccb96312Sdlg #define IXL_AQ_RC_BAD_ADDR		20 /* contains a bad pointer */
777ccb96312Sdlg #define IXL_AQ_RC_EMODE			21 /* not allowed in current mode */
778ccb96312Sdlg #define IXL_AQ_RC_EFBIG			22 /* file too large */
779ccb96312Sdlg 
780ccb96312Sdlg struct ixl_tx_desc {
781ccb96312Sdlg 	uint64_t		addr;
782ccb96312Sdlg 	uint64_t		cmd;
783ccb96312Sdlg #define IXL_TX_DESC_DTYPE_SHIFT		0
784ccb96312Sdlg #define IXL_TX_DESC_DTYPE_MASK		(0xfULL << IXL_TX_DESC_DTYPE_SHIFT)
785ccb96312Sdlg #define IXL_TX_DESC_DTYPE_DATA		(0x0ULL << IXL_TX_DESC_DTYPE_SHIFT)
786ccb96312Sdlg #define IXL_TX_DESC_DTYPE_NOP		(0x1ULL << IXL_TX_DESC_DTYPE_SHIFT)
787ccb96312Sdlg #define IXL_TX_DESC_DTYPE_CONTEXT	(0x1ULL << IXL_TX_DESC_DTYPE_SHIFT)
788ccb96312Sdlg #define IXL_TX_DESC_DTYPE_FCOE_CTX	(0x2ULL << IXL_TX_DESC_DTYPE_SHIFT)
789ccb96312Sdlg #define IXL_TX_DESC_DTYPE_FD		(0x8ULL << IXL_TX_DESC_DTYPE_SHIFT)
790ccb96312Sdlg #define IXL_TX_DESC_DTYPE_DDP_CTX	(0x9ULL << IXL_TX_DESC_DTYPE_SHIFT)
791ccb96312Sdlg #define IXL_TX_DESC_DTYPE_FLEX_DATA	(0xbULL << IXL_TX_DESC_DTYPE_SHIFT)
792ccb96312Sdlg #define IXL_TX_DESC_DTYPE_FLEX_CTX_1	(0xcULL << IXL_TX_DESC_DTYPE_SHIFT)
793ccb96312Sdlg #define IXL_TX_DESC_DTYPE_FLEX_CTX_2	(0xdULL << IXL_TX_DESC_DTYPE_SHIFT)
794ccb96312Sdlg #define IXL_TX_DESC_DTYPE_DONE		(0xfULL << IXL_TX_DESC_DTYPE_SHIFT)
795ccb96312Sdlg 
796ccb96312Sdlg #define IXL_TX_DESC_CMD_SHIFT		4
797ccb96312Sdlg #define IXL_TX_DESC_CMD_MASK		(0x3ffULL << IXL_TX_DESC_CMD_SHIFT)
798ccb96312Sdlg #define IXL_TX_DESC_CMD_EOP		(0x001 << IXL_TX_DESC_CMD_SHIFT)
799ccb96312Sdlg #define IXL_TX_DESC_CMD_RS		(0x002 << IXL_TX_DESC_CMD_SHIFT)
800ccb96312Sdlg #define IXL_TX_DESC_CMD_ICRC		(0x004 << IXL_TX_DESC_CMD_SHIFT)
801ccb96312Sdlg #define IXL_TX_DESC_CMD_IL2TAG1		(0x008 << IXL_TX_DESC_CMD_SHIFT)
802ccb96312Sdlg #define IXL_TX_DESC_CMD_DUMMY		(0x010 << IXL_TX_DESC_CMD_SHIFT)
803ccb96312Sdlg #define IXL_TX_DESC_CMD_IIPT_MASK	(0x060 << IXL_TX_DESC_CMD_SHIFT)
804ccb96312Sdlg #define IXL_TX_DESC_CMD_IIPT_NONIP	(0x000 << IXL_TX_DESC_CMD_SHIFT)
805ccb96312Sdlg #define IXL_TX_DESC_CMD_IIPT_IPV6	(0x020 << IXL_TX_DESC_CMD_SHIFT)
806ccb96312Sdlg #define IXL_TX_DESC_CMD_IIPT_IPV4	(0x040 << IXL_TX_DESC_CMD_SHIFT)
807ccb96312Sdlg #define IXL_TX_DESC_CMD_IIPT_IPV4_CSUM	(0x060 << IXL_TX_DESC_CMD_SHIFT)
808ccb96312Sdlg #define IXL_TX_DESC_CMD_FCOET		(0x080 << IXL_TX_DESC_CMD_SHIFT)
809ccb96312Sdlg #define IXL_TX_DESC_CMD_L4T_EOFT_MASK	(0x300 << IXL_TX_DESC_CMD_SHIFT)
810ccb96312Sdlg #define IXL_TX_DESC_CMD_L4T_EOFT_UNK	(0x000 << IXL_TX_DESC_CMD_SHIFT)
811ccb96312Sdlg #define IXL_TX_DESC_CMD_L4T_EOFT_TCP	(0x100 << IXL_TX_DESC_CMD_SHIFT)
812ccb96312Sdlg #define IXL_TX_DESC_CMD_L4T_EOFT_SCTP	(0x200 << IXL_TX_DESC_CMD_SHIFT)
813ccb96312Sdlg #define IXL_TX_DESC_CMD_L4T_EOFT_UDP	(0x300 << IXL_TX_DESC_CMD_SHIFT)
814ccb96312Sdlg 
815ccb96312Sdlg #define IXL_TX_DESC_MACLEN_SHIFT	16
816ccb96312Sdlg #define IXL_TX_DESC_MACLEN_MASK		(0x7fULL << IXL_TX_DESC_MACLEN_SHIFT)
817ccb96312Sdlg #define IXL_TX_DESC_IPLEN_SHIFT		23
818ccb96312Sdlg #define IXL_TX_DESC_IPLEN_MASK		(0x7fULL << IXL_TX_DESC_IPLEN_SHIFT)
819ccb96312Sdlg #define IXL_TX_DESC_L4LEN_SHIFT		30
820ccb96312Sdlg #define IXL_TX_DESC_L4LEN_MASK		(0xfULL << IXL_TX_DESC_L4LEN_SHIFT)
821ccb96312Sdlg #define IXL_TX_DESC_FCLEN_SHIFT		30
822ccb96312Sdlg #define IXL_TX_DESC_FCLEN_MASK		(0xfULL << IXL_TX_DESC_FCLEN_SHIFT)
823ccb96312Sdlg 
824ccb96312Sdlg #define IXL_TX_DESC_BSIZE_SHIFT		34
825ccb96312Sdlg #define IXL_TX_DESC_BSIZE_MAX		0x3fffULL
826ccb96312Sdlg #define IXL_TX_DESC_BSIZE_MASK		\
827ccb96312Sdlg 	(IXL_TX_DESC_BSIZE_MAX << IXL_TX_DESC_BSIZE_SHIFT)
828983d220cSdlg 
829f77c9c95Sjan #define IXL_TX_CTX_DESC_CMD_TSO		0x10
830f77c9c95Sjan #define IXL_TX_CTX_DESC_TLEN_SHIFT	30
831f77c9c95Sjan #define IXL_TX_CTX_DESC_MSS_SHIFT	50
832f77c9c95Sjan 
833983d220cSdlg #define IXL_TX_DESC_L2TAG1_SHIFT	48
834ccb96312Sdlg } __packed __aligned(16);
835ccb96312Sdlg 
836ccb96312Sdlg struct ixl_rx_rd_desc_16 {
837ccb96312Sdlg 	uint64_t		paddr; /* packet addr */
838ccb96312Sdlg 	uint64_t		haddr; /* header addr */
839ccb96312Sdlg } __packed __aligned(16);
840ccb96312Sdlg 
841ccb96312Sdlg struct ixl_rx_rd_desc_32 {
842ccb96312Sdlg 	uint64_t		paddr; /* packet addr */
843ccb96312Sdlg 	uint64_t		haddr; /* header addr */
844ccb96312Sdlg 	uint64_t		_reserved1;
845ccb96312Sdlg 	uint64_t		_reserved2;
846ccb96312Sdlg } __packed __aligned(16);
847ccb96312Sdlg 
848ccb96312Sdlg struct ixl_rx_wb_desc_16 {
849555fd15dSdlg 	uint16_t		_reserved1;
850555fd15dSdlg 	uint16_t		l2tag1;
8516850335aSdlg 	uint32_t		filter_status;
852ccb96312Sdlg 	uint64_t		qword1;
853ccb96312Sdlg #define IXL_RX_DESC_DD			(1 << 0)
854ccb96312Sdlg #define IXL_RX_DESC_EOP			(1 << 1)
855ccb96312Sdlg #define IXL_RX_DESC_L2TAG1P		(1 << 2)
856ccb96312Sdlg #define IXL_RX_DESC_L3L4P		(1 << 3)
857ccb96312Sdlg #define IXL_RX_DESC_CRCP		(1 << 4)
858ccb96312Sdlg #define IXL_RX_DESC_TSYNINDX_SHIFT	5	/* TSYNINDX */
859ccb96312Sdlg #define IXL_RX_DESC_TSYNINDX_MASK	(7 << IXL_RX_DESC_TSYNINDX_SHIFT)
860ccb96312Sdlg #define IXL_RX_DESC_UMB_SHIFT		9
861ccb96312Sdlg #define IXL_RX_DESC_UMB_MASK		(0x3 << IXL_RX_DESC_UMB_SHIFT)
862ccb96312Sdlg #define IXL_RX_DESC_UMB_UCAST		(0x0 << IXL_RX_DESC_UMB_SHIFT)
863ccb96312Sdlg #define IXL_RX_DESC_UMB_MCAST		(0x1 << IXL_RX_DESC_UMB_SHIFT)
864ccb96312Sdlg #define IXL_RX_DESC_UMB_BCAST		(0x2 << IXL_RX_DESC_UMB_SHIFT)
865ccb96312Sdlg #define IXL_RX_DESC_UMB_MIRROR		(0x3 << IXL_RX_DESC_UMB_SHIFT)
866ccb96312Sdlg #define IXL_RX_DESC_FLM			(1 << 11)
867ccb96312Sdlg #define IXL_RX_DESC_FLTSTAT_SHIFT	12
868ccb96312Sdlg #define IXL_RX_DESC_FLTSTAT_MASK	(0x3 << IXL_RX_DESC_FLTSTAT_SHIFT)
869ccb96312Sdlg #define IXL_RX_DESC_FLTSTAT_NODATA	(0x0 << IXL_RX_DESC_FLTSTAT_SHIFT)
870ccb96312Sdlg #define IXL_RX_DESC_FLTSTAT_FDFILTID	(0x1 << IXL_RX_DESC_FLTSTAT_SHIFT)
871ccb96312Sdlg #define IXL_RX_DESC_FLTSTAT_RSS		(0x3 << IXL_RX_DESC_FLTSTAT_SHIFT)
872ccb96312Sdlg #define IXL_RX_DESC_LPBK		(1 << 14)
873ccb96312Sdlg #define IXL_RX_DESC_IPV6EXTADD		(1 << 15)
874ccb96312Sdlg #define IXL_RX_DESC_INT_UDP_0		(1 << 18)
875ccb96312Sdlg 
876ccb96312Sdlg #define IXL_RX_DESC_RXE			(1 << 19)
877ccb96312Sdlg #define IXL_RX_DESC_HBO			(1 << 21)
878ccb96312Sdlg #define IXL_RX_DESC_IPE			(1 << 22)
879ccb96312Sdlg #define IXL_RX_DESC_L4E			(1 << 23)
880ccb96312Sdlg #define IXL_RX_DESC_EIPE		(1 << 24)
881ccb96312Sdlg #define IXL_RX_DESC_OVERSIZE		(1 << 25)
882ccb96312Sdlg 
883ccb96312Sdlg #define IXL_RX_DESC_PTYPE_SHIFT		30
884ccb96312Sdlg #define IXL_RX_DESC_PTYPE_MASK		(0xffULL << IXL_RX_DESC_PTYPE_SHIFT)
885ccb96312Sdlg 
886ccb96312Sdlg #define IXL_RX_DESC_PLEN_SHIFT		38
887ccb96312Sdlg #define IXL_RX_DESC_PLEN_MASK		(0x3fffULL << IXL_RX_DESC_PLEN_SHIFT)
888ccb96312Sdlg #define IXL_RX_DESC_HLEN_SHIFT		42
889ccb96312Sdlg #define IXL_RX_DESC_HLEN_MASK		(0x7ffULL << IXL_RX_DESC_HLEN_SHIFT)
890ccb96312Sdlg } __packed __aligned(16);
891ccb96312Sdlg 
892ccb96312Sdlg struct ixl_rx_wb_desc_32 {
893ccb96312Sdlg 	uint64_t		qword0;
894ccb96312Sdlg 	uint64_t		qword1;
895ccb96312Sdlg 	uint64_t		qword2;
896ccb96312Sdlg 	uint64_t		qword3;
897ccb96312Sdlg } __packed __aligned(16);
898ccb96312Sdlg 
89976ade4a7Sbluhm #define IXL_TX_PKT_DESCS		8
900ccb96312Sdlg #define IXL_TX_QUEUE_ALIGN		128
901ccb96312Sdlg #define IXL_RX_QUEUE_ALIGN		128
902ccb96312Sdlg 
903bf059df2Sjmatthew #define IXL_HARDMTU			9712 /* 9726 - ETHER_HDR_LEN */
904f77c9c95Sjan #define IXL_TSO_SIZE			((255 * 1024) - 1)
905f77c9c95Sjan #define IXL_MAX_DMA_SEG_SIZE		((16 * 1024) - 1)
906f77c9c95Sjan 
907f77c9c95Sjan /*
908936f91c6Sjan  * Our TCP/IP Stack is unable handle packets greater than MAXMCLBYTES.
909936f91c6Sjan  * This interface is unable handle packets greater than IXL_TSO_SIZE.
910f77c9c95Sjan  */
911f77c9c95Sjan CTASSERT(MAXMCLBYTES < IXL_TSO_SIZE);
912ccb96312Sdlg 
913ccb96312Sdlg #define IXL_PCIREG			PCI_MAPREG_START
914ccb96312Sdlg 
915ccb96312Sdlg #define IXL_ITR0			0x0
916ccb96312Sdlg #define IXL_ITR1			0x1
917ccb96312Sdlg #define IXL_ITR2			0x2
918ccb96312Sdlg #define IXL_NOITR			0x2
919ccb96312Sdlg 
920ccb96312Sdlg #define IXL_AQ_NUM			256
921ccb96312Sdlg #define IXL_AQ_MASK			(IXL_AQ_NUM - 1)
922ccb96312Sdlg #define IXL_AQ_ALIGN			64 /* lol */
923ccb96312Sdlg #define IXL_AQ_BUFLEN			4096
924ccb96312Sdlg 
925e0731eceSdlg /* Packet Classifier Types for filters */
926e0731eceSdlg /* bits 0-28 are reserved for future use */
927e0731eceSdlg #define IXL_PCT_NONF_IPV4_UDP_UCAST	(1ULL << 29)	/* 722 */
928e0731eceSdlg #define IXL_PCT_NONF_IPV4_UDP_MCAST	(1ULL << 30)	/* 722 */
929e0731eceSdlg #define IXL_PCT_NONF_IPV4_UDP		(1ULL << 31)
930e0731eceSdlg #define IXL_PCT_NONF_IPV4_TCP_SYN_NOACK	(1ULL << 32)	/* 722 */
931e0731eceSdlg #define IXL_PCT_NONF_IPV4_TCP		(1ULL << 33)
932e0731eceSdlg #define IXL_PCT_NONF_IPV4_SCTP		(1ULL << 34)
933e0731eceSdlg #define IXL_PCT_NONF_IPV4_OTHER		(1ULL << 35)
934e0731eceSdlg #define IXL_PCT_FRAG_IPV4		(1ULL << 36)
935e0731eceSdlg /* bits 37-38 are reserved for future use */
936e0731eceSdlg #define IXL_PCT_NONF_IPV6_UDP_UCAST	(1ULL << 39)	/* 722 */
937e0731eceSdlg #define IXL_PCT_NONF_IPV6_UDP_MCAST	(1ULL << 40)	/* 722 */
938e0731eceSdlg #define IXL_PCT_NONF_IPV6_UDP		(1ULL << 41)
939e0731eceSdlg #define IXL_PCT_NONF_IPV6_TCP_SYN_NOACK	(1ULL << 42)	/* 722 */
940e0731eceSdlg #define IXL_PCT_NONF_IPV6_TCP		(1ULL << 43)
941e0731eceSdlg #define IXL_PCT_NONF_IPV6_SCTP		(1ULL << 44)
942e0731eceSdlg #define IXL_PCT_NONF_IPV6_OTHER		(1ULL << 45)
943e0731eceSdlg #define IXL_PCT_FRAG_IPV6		(1ULL << 46)
944e0731eceSdlg /* bit 47 is reserved for future use */
945e0731eceSdlg #define IXL_PCT_FCOE_OX			(1ULL << 48)
946e0731eceSdlg #define IXL_PCT_FCOE_RX			(1ULL << 49)
947e0731eceSdlg #define IXL_PCT_FCOE_OTHER		(1ULL << 50)
948e0731eceSdlg /* bits 51-62 are reserved for future use */
949e0731eceSdlg #define IXL_PCT_L2_PAYLOAD		(1ULL << 63)
950e0731eceSdlg 
9518d616574Sdlg #define IXL_RSS_HENA_BASE_DEFAULT		\
9528d616574Sdlg 	IXL_PCT_NONF_IPV4_UDP |			\
9538d616574Sdlg 	IXL_PCT_NONF_IPV4_TCP |			\
9548d616574Sdlg 	IXL_PCT_NONF_IPV4_SCTP |		\
9558d616574Sdlg 	IXL_PCT_NONF_IPV4_OTHER |		\
9568d616574Sdlg 	IXL_PCT_FRAG_IPV4 |			\
9578d616574Sdlg 	IXL_PCT_NONF_IPV6_UDP |			\
9588d616574Sdlg 	IXL_PCT_NONF_IPV6_TCP |			\
9598d616574Sdlg 	IXL_PCT_NONF_IPV6_SCTP |		\
9608d616574Sdlg 	IXL_PCT_NONF_IPV6_OTHER |		\
9618d616574Sdlg 	IXL_PCT_FRAG_IPV6 |			\
9628d616574Sdlg 	IXL_PCT_L2_PAYLOAD
9638d616574Sdlg 
9648d616574Sdlg #define IXL_RSS_HENA_BASE_710		IXL_RSS_HENA_BASE_DEFAULT
9658d616574Sdlg #define IXL_RSS_HENA_BASE_722		IXL_RSS_HENA_BASE_DEFAULT | \
9668d616574Sdlg 	IXL_PCT_NONF_IPV4_UDP_UCAST |		\
9678d616574Sdlg 	IXL_PCT_NONF_IPV4_UDP_MCAST |		\
9688d616574Sdlg 	IXL_PCT_NONF_IPV6_UDP_UCAST |		\
9698d616574Sdlg 	IXL_PCT_NONF_IPV6_UDP_MCAST |		\
9708d616574Sdlg 	IXL_PCT_NONF_IPV4_TCP_SYN_NOACK |	\
9718d616574Sdlg 	IXL_PCT_NONF_IPV6_TCP_SYN_NOACK
9728d616574Sdlg 
973ccb96312Sdlg #define IXL_HMC_ROUNDUP			512
974ccb96312Sdlg #define IXL_HMC_PGSIZE			4096
975ccb96312Sdlg #define IXL_HMC_DVASZ			sizeof(uint64_t)
976ccb96312Sdlg #define IXL_HMC_PGS			(IXL_HMC_PGSIZE / IXL_HMC_DVASZ)
977ccb96312Sdlg #define IXL_HMC_L2SZ			(IXL_HMC_PGSIZE * IXL_HMC_PGS)
978ccb96312Sdlg #define IXL_HMC_PDVALID			1ULL
979ccb96312Sdlg 
980ccb96312Sdlg struct ixl_aq_regs {
981ccb96312Sdlg 	bus_size_t		atq_tail;
982ccb96312Sdlg 	bus_size_t		atq_head;
983ccb96312Sdlg 	bus_size_t		atq_len;
984ccb96312Sdlg 	bus_size_t		atq_bal;
985ccb96312Sdlg 	bus_size_t		atq_bah;
986ccb96312Sdlg 
987ccb96312Sdlg 	bus_size_t		arq_tail;
988ccb96312Sdlg 	bus_size_t		arq_head;
989ccb96312Sdlg 	bus_size_t		arq_len;
990ccb96312Sdlg 	bus_size_t		arq_bal;
991ccb96312Sdlg 	bus_size_t		arq_bah;
992ccb96312Sdlg 
993ccb96312Sdlg 	uint32_t		atq_len_enable;
994ccb96312Sdlg 	uint32_t		atq_tail_mask;
995ccb96312Sdlg 	uint32_t		atq_head_mask;
996ccb96312Sdlg 
997ccb96312Sdlg 	uint32_t		arq_len_enable;
998ccb96312Sdlg 	uint32_t		arq_tail_mask;
999ccb96312Sdlg 	uint32_t		arq_head_mask;
1000ccb96312Sdlg };
1001ccb96312Sdlg 
1002ccb96312Sdlg struct ixl_phy_type {
1003ccb96312Sdlg 	uint64_t	phy_type;
1004ccb96312Sdlg 	uint64_t	ifm_type;
1005ccb96312Sdlg };
1006ccb96312Sdlg 
1007ccb96312Sdlg struct ixl_speed_type {
1008ccb96312Sdlg 	uint8_t		dev_speed;
1009ccb96312Sdlg 	uint64_t	net_speed;
1010ccb96312Sdlg };
1011ccb96312Sdlg 
1012ccb96312Sdlg struct ixl_aq_buf {
1013ccb96312Sdlg 	SIMPLEQ_ENTRY(ixl_aq_buf)
1014ccb96312Sdlg 				 aqb_entry;
1015ccb96312Sdlg 	void			*aqb_data;
1016ccb96312Sdlg 	bus_dmamap_t		 aqb_map;
1017ccb96312Sdlg };
1018ccb96312Sdlg SIMPLEQ_HEAD(ixl_aq_bufs, ixl_aq_buf);
1019ccb96312Sdlg 
1020ccb96312Sdlg struct ixl_dmamem {
1021ccb96312Sdlg 	bus_dmamap_t		ixm_map;
1022ccb96312Sdlg 	bus_dma_segment_t	ixm_seg;
1023ccb96312Sdlg 	int			ixm_nsegs;
1024ccb96312Sdlg 	size_t			ixm_size;
1025ccb96312Sdlg 	caddr_t			ixm_kva;
1026ccb96312Sdlg };
1027ccb96312Sdlg #define IXL_DMA_MAP(_ixm)	((_ixm)->ixm_map)
1028ccb96312Sdlg #define IXL_DMA_DVA(_ixm)	((_ixm)->ixm_map->dm_segs[0].ds_addr)
1029ccb96312Sdlg #define IXL_DMA_KVA(_ixm)	((void *)(_ixm)->ixm_kva)
1030ccb96312Sdlg #define IXL_DMA_LEN(_ixm)	((_ixm)->ixm_size)
1031ccb96312Sdlg 
1032ccb96312Sdlg struct ixl_hmc_entry {
1033ccb96312Sdlg 	uint64_t		 hmc_base;
1034ccb96312Sdlg 	uint32_t		 hmc_count;
1035ccb96312Sdlg 	uint32_t		 hmc_size;
1036ccb96312Sdlg };
1037ccb96312Sdlg 
1038ccb96312Sdlg #define IXL_HMC_LAN_TX		 0
1039ccb96312Sdlg #define IXL_HMC_LAN_RX		 1
1040ccb96312Sdlg #define IXL_HMC_FCOE_CTX	 2
1041ccb96312Sdlg #define IXL_HMC_FCOE_FILTER	 3
1042ccb96312Sdlg #define IXL_HMC_COUNT		 4
1043ccb96312Sdlg 
1044ccb96312Sdlg struct ixl_hmc_pack {
1045ccb96312Sdlg 	uint16_t		offset;
1046ccb96312Sdlg 	uint16_t		width;
1047ccb96312Sdlg 	uint16_t		lsb;
1048ccb96312Sdlg };
1049ccb96312Sdlg 
1050ccb96312Sdlg /*
1051ccb96312Sdlg  * these hmc objects have weird sizes and alignments, so these are abstract
1052ccb96312Sdlg  * representations of them that are nice for c to populate.
1053ccb96312Sdlg  *
1054ccb96312Sdlg  * the packing code relies on little-endian values being stored in the fields,
1055ccb96312Sdlg  * no high bits in the fields being set, and the fields must be packed in the
1056ccb96312Sdlg  * same order as they are in the ctx structure.
1057ccb96312Sdlg  */
1058ccb96312Sdlg 
1059ccb96312Sdlg struct ixl_hmc_rxq {
1060ccb96312Sdlg 	uint16_t		 head;
1061ccb96312Sdlg 	uint8_t			 cpuid;
1062ccb96312Sdlg 	uint64_t		 base;
1063ccb96312Sdlg #define IXL_HMC_RXQ_BASE_UNIT		128
1064ccb96312Sdlg 	uint16_t		 qlen;
1065ccb96312Sdlg 	uint16_t		 dbuff;
1066ccb96312Sdlg #define IXL_HMC_RXQ_DBUFF_UNIT		128
1067ccb96312Sdlg 	uint8_t			 hbuff;
1068ccb96312Sdlg #define IXL_HMC_RXQ_HBUFF_UNIT		64
1069ccb96312Sdlg 	uint8_t			 dtype;
1070ccb96312Sdlg #define IXL_HMC_RXQ_DTYPE_NOSPLIT	0x0
1071ccb96312Sdlg #define IXL_HMC_RXQ_DTYPE_HSPLIT	0x1
1072ccb96312Sdlg #define IXL_HMC_RXQ_DTYPE_SPLIT_ALWAYS	0x2
1073ccb96312Sdlg 	uint8_t			 dsize;
1074ccb96312Sdlg #define IXL_HMC_RXQ_DSIZE_16		0
1075ccb96312Sdlg #define IXL_HMC_RXQ_DSIZE_32		1
1076ccb96312Sdlg 	uint8_t			 crcstrip;
1077ccb96312Sdlg 	uint8_t			 fc_ena;
1078555fd15dSdlg 	uint8_t			 l2tsel;
1079555fd15dSdlg #define IXL_HMC_RXQ_L2TSEL_2ND_TAG_TO_L2TAG1 \
1080555fd15dSdlg 					0
1081555fd15dSdlg #define IXL_HMC_RXQ_L2TSEL_1ST_TAG_TO_L2TAG1 \
1082555fd15dSdlg 					1
1083ccb96312Sdlg 	uint8_t			 hsplit_0;
1084ccb96312Sdlg 	uint8_t			 hsplit_1;
1085ccb96312Sdlg 	uint8_t			 showiv;
1086ccb96312Sdlg 	uint16_t		 rxmax;
1087ccb96312Sdlg 	uint8_t			 tphrdesc_ena;
1088ccb96312Sdlg 	uint8_t			 tphwdesc_ena;
1089ccb96312Sdlg 	uint8_t			 tphdata_ena;
1090ccb96312Sdlg 	uint8_t			 tphhead_ena;
1091ccb96312Sdlg 	uint8_t			 lrxqthresh;
1092ccb96312Sdlg 	uint8_t			 prefena;
1093ccb96312Sdlg };
1094ccb96312Sdlg 
1095ccb96312Sdlg static const struct ixl_hmc_pack ixl_hmc_pack_rxq[] = {
1096ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, head),		13,	0 },
1097ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, cpuid),		8,	13 },
1098ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, base),		57,	32 },
1099ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, qlen),		13,	89 },
1100ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, dbuff),		7,	102 },
1101ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, hbuff),		5,	109 },
1102ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, dtype),		2,	114 },
1103ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, dsize),		1,	116 },
1104ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, crcstrip),	1,	117 },
1105ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, fc_ena),		1,	118 },
1106555fd15dSdlg 	{ offsetof(struct ixl_hmc_rxq, l2tsel),		1,	119 },
1107ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, hsplit_0),	4,	120 },
1108ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, hsplit_1),	2,	124 },
1109ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, showiv),		1,	127 },
1110ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, rxmax),		14,	174 },
1111ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, tphrdesc_ena),	1,	193 },
1112ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, tphwdesc_ena),	1,	194 },
1113ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, tphdata_ena),	1,	195 },
1114ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, tphhead_ena),	1,	196 },
1115ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, lrxqthresh),	3,	198 },
1116ccb96312Sdlg 	{ offsetof(struct ixl_hmc_rxq, prefena),	1,	201 },
1117ccb96312Sdlg };
1118ccb96312Sdlg 
1119ccb96312Sdlg #define IXL_HMC_RXQ_MINSIZE (201 + 1)
1120ccb96312Sdlg 
1121ccb96312Sdlg struct ixl_hmc_txq {
1122ccb96312Sdlg 	uint16_t		head;
1123ccb96312Sdlg 	uint8_t			new_context;
1124ccb96312Sdlg 	uint64_t		base;
1125ccb96312Sdlg #define IXL_HMC_TXQ_BASE_UNIT		128
1126ccb96312Sdlg 	uint8_t			fc_ena;
1127ccb96312Sdlg 	uint8_t			timesync_ena;
1128ccb96312Sdlg 	uint8_t			fd_ena;
1129ccb96312Sdlg 	uint8_t			alt_vlan_ena;
1130ccb96312Sdlg 	uint16_t		thead_wb;
1131ccb96312Sdlg 	uint8_t			cpuid;
1132ccb96312Sdlg 	uint8_t			head_wb_ena;
1133ccb96312Sdlg #define IXL_HMC_TXQ_DESC_WB		0
1134ccb96312Sdlg #define IXL_HMC_TXQ_HEAD_WB		1
1135ccb96312Sdlg 	uint16_t		qlen;
1136ccb96312Sdlg 	uint8_t			tphrdesc_ena;
1137ccb96312Sdlg 	uint8_t			tphrpacket_ena;
1138ccb96312Sdlg 	uint8_t			tphwdesc_ena;
1139ccb96312Sdlg 	uint64_t		head_wb_addr;
1140ccb96312Sdlg 	uint32_t		crc;
1141ccb96312Sdlg 	uint16_t		rdylist;
1142ccb96312Sdlg 	uint8_t			rdylist_act;
1143ccb96312Sdlg };
1144ccb96312Sdlg 
1145ccb96312Sdlg static const struct ixl_hmc_pack ixl_hmc_pack_txq[] = {
1146ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, head),		13,	0 },
1147ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, new_context),	1,	30 },
1148ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, base),		57,	32 },
1149ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, fc_ena),		1,	89 },
1150ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, timesync_ena),	1,	90 },
1151ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, fd_ena),		1,	91 },
1152ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, alt_vlan_ena),	1,	92 },
1153ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, cpuid),		8,	96 },
1154ccb96312Sdlg /* line 1 */
1155ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, thead_wb),	13,	0 + 128 },
1156ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, head_wb_ena),	1,	32 + 128 },
1157ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, qlen),		13,	33 + 128 },
1158ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, tphrdesc_ena),	1,	46 + 128 },
1159ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, tphrpacket_ena),	1,	47 + 128 },
1160ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, tphwdesc_ena),	1,	48 + 128 },
1161ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, head_wb_addr),	64,	64 + 128 },
1162ccb96312Sdlg /* line 7 */
1163ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, crc),		32,	0 + (7*128) },
1164ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, rdylist),	10,	84 + (7*128) },
1165ccb96312Sdlg 	{ offsetof(struct ixl_hmc_txq, rdylist_act),	1,	94 + (7*128) },
1166ccb96312Sdlg };
1167ccb96312Sdlg 
1168ccb96312Sdlg #define IXL_HMC_TXQ_MINSIZE (94 + (7*128) + 1)
1169ccb96312Sdlg 
1170819ac441Sdlg struct ixl_rss_key {
1171819ac441Sdlg 	uint32_t		 key[13];
1172819ac441Sdlg };
1173819ac441Sdlg 
1174819ac441Sdlg struct ixl_rss_lut_128 {
1175819ac441Sdlg 	uint32_t		 entries[128 / sizeof(uint32_t)];
1176819ac441Sdlg };
1177819ac441Sdlg 
1178819ac441Sdlg struct ixl_rss_lut_512 {
1179819ac441Sdlg 	uint32_t		 entries[512 / sizeof(uint32_t)];
1180819ac441Sdlg };
1181819ac441Sdlg 
1182819ac441Sdlg /* driver structures */
1183819ac441Sdlg 
1184e01adc04Sdlg struct ixl_vector;
1185819ac441Sdlg struct ixl_chip;
1186e01adc04Sdlg 
1187ccb96312Sdlg struct ixl_tx_map {
1188ccb96312Sdlg 	struct mbuf		*txm_m;
1189ccb96312Sdlg 	bus_dmamap_t		 txm_map;
1190ccb96312Sdlg 	unsigned int		 txm_eop;
1191ccb96312Sdlg };
1192ccb96312Sdlg 
1193ccb96312Sdlg struct ixl_tx_ring {
1194e01adc04Sdlg 	struct ixl_softc	*txr_sc;
1195e01adc04Sdlg 	struct ixl_vector	*txr_vector;
1196e01adc04Sdlg 	struct ifqueue		*txr_ifq;
1197e01adc04Sdlg 
1198ccb96312Sdlg 	unsigned int		 txr_prod;
1199ccb96312Sdlg 	unsigned int		 txr_cons;
1200ccb96312Sdlg 
1201ccb96312Sdlg 	struct ixl_tx_map	*txr_maps;
1202ccb96312Sdlg 	struct ixl_dmamem	 txr_mem;
1203ccb96312Sdlg 
1204ccb96312Sdlg 	bus_size_t		 txr_tail;
1205ccb96312Sdlg 	unsigned int		 txr_qid;
1206e01adc04Sdlg } __aligned(CACHE_LINE_SIZE);
1207ccb96312Sdlg 
1208ccb96312Sdlg struct ixl_rx_map {
1209ccb96312Sdlg 	struct mbuf		*rxm_m;
1210ccb96312Sdlg 	bus_dmamap_t		 rxm_map;
1211ccb96312Sdlg };
1212ccb96312Sdlg 
1213ccb96312Sdlg struct ixl_rx_ring {
1214ccb96312Sdlg 	struct ixl_softc	*rxr_sc;
1215e01adc04Sdlg 	struct ixl_vector	*rxr_vector;
1216e01adc04Sdlg 	struct ifiqueue		*rxr_ifiq;
121700cd24f1Sdlg 
1218ccb96312Sdlg 	struct if_rxring	 rxr_acct;
1219ccb96312Sdlg 	struct timeout		 rxr_refill;
1220ccb96312Sdlg 
1221ccb96312Sdlg 	unsigned int		 rxr_prod;
1222ccb96312Sdlg 	unsigned int		 rxr_cons;
1223ccb96312Sdlg 
1224ccb96312Sdlg 	struct ixl_rx_map	*rxr_maps;
1225ccb96312Sdlg 	struct ixl_dmamem	 rxr_mem;
1226ccb96312Sdlg 
1227ccb96312Sdlg 	struct mbuf		*rxr_m_head;
1228ccb96312Sdlg 	struct mbuf		**rxr_m_tail;
1229ccb96312Sdlg 
1230ccb96312Sdlg 	bus_size_t		 rxr_tail;
1231ccb96312Sdlg 	unsigned int		 rxr_qid;
1232e01adc04Sdlg } __aligned(CACHE_LINE_SIZE);
1233ccb96312Sdlg 
123410e66d97Sjmatthew struct ixl_atq {
123510e66d97Sjmatthew 	struct ixl_aq_desc	  iatq_desc;
123610e66d97Sjmatthew 	void			 *iatq_arg;
123710e66d97Sjmatthew 	void			(*iatq_fn)(struct ixl_softc *, void *);
123810e66d97Sjmatthew };
123910e66d97Sjmatthew SIMPLEQ_HEAD(ixl_atq_list, ixl_atq);
124010e66d97Sjmatthew 
1241e01adc04Sdlg struct ixl_vector {
1242e01adc04Sdlg 	struct ixl_softc	*iv_sc;
1243e01adc04Sdlg 	struct ixl_rx_ring	*iv_rxr;
1244e01adc04Sdlg 	struct ixl_tx_ring	*iv_txr;
1245e01adc04Sdlg 	int			 iv_qid;
1246e01adc04Sdlg 	void			*iv_ihc;
1247e01adc04Sdlg 	char			 iv_name[16];
1248e01adc04Sdlg } __aligned(CACHE_LINE_SIZE);
12499b0c6e1eSjmatthew 
1250ccb96312Sdlg struct ixl_softc {
1251ccb96312Sdlg 	struct device		 sc_dev;
1252819ac441Sdlg 	const struct ixl_chip	*sc_chip;
1253ccb96312Sdlg 	struct arpcom		 sc_ac;
1254ccb96312Sdlg 	struct ifmedia		 sc_media;
1255ccb96312Sdlg 	uint64_t		 sc_media_status;
1256ccb96312Sdlg 	uint64_t		 sc_media_active;
1257ccb96312Sdlg 
1258ccb96312Sdlg 	pci_chipset_tag_t	 sc_pc;
1259ccb96312Sdlg 	pci_intr_handle_t	 sc_ih;
1260ccb96312Sdlg 	void			*sc_ihc;
1261ccb96312Sdlg 	pcitag_t		 sc_tag;
1262ccb96312Sdlg 
1263ccb96312Sdlg 	bus_dma_tag_t		 sc_dmat;
1264ccb96312Sdlg 	bus_space_tag_t		 sc_memt;
1265ccb96312Sdlg 	bus_space_handle_t	 sc_memh;
1266ccb96312Sdlg 	bus_size_t		 sc_mems;
1267ccb96312Sdlg 
1268f5777d33Sdlg 	uint16_t		 sc_api_major;
1269f5777d33Sdlg 	uint16_t		 sc_api_minor;
1270ccb96312Sdlg 	uint8_t			 sc_pf_id;
1271ccb96312Sdlg 	uint16_t		 sc_uplink_seid;	/* le */
1272ccb96312Sdlg 	uint16_t		 sc_downlink_seid;	/* le */
1273ccb96312Sdlg 	uint16_t		 sc_veb_seid;		/* le */
1274ccb96312Sdlg 	uint16_t		 sc_vsi_number;		/* le */
1275ccb96312Sdlg 	uint16_t		 sc_seid;
1276eb1b42e4Sdlg 	unsigned int		 sc_base_queue;
12772ee1fcb3Sdlg 	unsigned int		 sc_port;
1278ccb96312Sdlg 
12792bb8400cSjmatthew 	struct ixl_dmamem	 sc_scratch;
1280ccb96312Sdlg 
1281ccb96312Sdlg 	const struct ixl_aq_regs *
1282ccb96312Sdlg 				 sc_aq_regs;
1283ccb96312Sdlg 
1284ccb96312Sdlg 	struct ixl_dmamem	 sc_atq;
1285ccb96312Sdlg 	unsigned int		 sc_atq_prod;
1286ccb96312Sdlg 	unsigned int		 sc_atq_cons;
1287ccb96312Sdlg 
128895f940dfSjan 	struct mutex		 sc_atq_mtx;
1289ccb96312Sdlg 	struct ixl_dmamem	 sc_arq;
1290ccb96312Sdlg 	struct task		 sc_arq_task;
1291ccb96312Sdlg 	struct ixl_aq_bufs	 sc_arq_idle;
1292ccb96312Sdlg 	struct ixl_aq_bufs	 sc_arq_live;
1293ccb96312Sdlg 	struct if_rxring	 sc_arq_ring;
1294ccb96312Sdlg 	unsigned int		 sc_arq_prod;
1295ccb96312Sdlg 	unsigned int		 sc_arq_cons;
1296ccb96312Sdlg 
12978014a50bSdlg 	struct mutex		 sc_link_state_mtx;
129810e66d97Sjmatthew 	struct task		 sc_link_state_task;
129910e66d97Sjmatthew 	struct ixl_atq		 sc_link_state_atq;
130010e66d97Sjmatthew 
1301eb1b42e4Sdlg 	struct ixl_dmamem	 sc_hmc_sd;
1302eb1b42e4Sdlg 	struct ixl_dmamem	 sc_hmc_pd;
1303ccb96312Sdlg 	struct ixl_hmc_entry	 sc_hmc_entries[IXL_HMC_COUNT];
1304ccb96312Sdlg 
1305ccb96312Sdlg 	unsigned int		 sc_tx_ring_ndescs;
1306ccb96312Sdlg 	unsigned int		 sc_rx_ring_ndescs;
1307eb1b42e4Sdlg 	unsigned int		 sc_nqueues;	/* 1 << sc_nqueues */
1308d3ac7020Sdlg 
1309e01adc04Sdlg 	struct intrmap		*sc_intrmap;
1310e01adc04Sdlg 	struct ixl_vector	*sc_vectors;
1311e01adc04Sdlg 
1312d3ac7020Sdlg 	struct rwlock		 sc_cfg_lock;
1313d3ac7020Sdlg 	unsigned int		 sc_dead;
13144eec9beaSdlg 
131556319b45Sjmatthew 	uint8_t			 sc_enaddr[ETHER_ADDR_LEN];
13162ee1fcb3Sdlg 
13172ee1fcb3Sdlg #if NKSTAT > 0
13182ee1fcb3Sdlg 	struct mutex		 sc_kstat_mtx;
13192ee1fcb3Sdlg 	struct timeout		 sc_kstat_tmo;
13202ee1fcb3Sdlg 	struct kstat		*sc_port_kstat;
13212ee1fcb3Sdlg 	struct kstat		*sc_vsi_kstat;
13222ee1fcb3Sdlg #endif
1323ccb96312Sdlg };
1324ccb96312Sdlg #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
1325ccb96312Sdlg 
1326ccb96312Sdlg #define delaymsec(_ms)	delay(1000 * (_ms))
1327ccb96312Sdlg 
1328ccb96312Sdlg static void	ixl_clear_hw(struct ixl_softc *);
1329ccb96312Sdlg static int	ixl_pf_reset(struct ixl_softc *);
1330ccb96312Sdlg 
1331ccb96312Sdlg static int	ixl_dmamem_alloc(struct ixl_softc *, struct ixl_dmamem *,
1332ccb96312Sdlg 		    bus_size_t, u_int);
1333ccb96312Sdlg static void	ixl_dmamem_free(struct ixl_softc *, struct ixl_dmamem *);
1334ccb96312Sdlg 
1335ccb96312Sdlg static int	ixl_arq_fill(struct ixl_softc *);
1336ccb96312Sdlg static void	ixl_arq_unfill(struct ixl_softc *);
1337ccb96312Sdlg 
1338ccb96312Sdlg static int	ixl_atq_poll(struct ixl_softc *, struct ixl_aq_desc *,
1339ccb96312Sdlg 		    unsigned int);
1340ccb96312Sdlg static void	ixl_atq_set(struct ixl_atq *,
1341ccb96312Sdlg 		    void (*)(struct ixl_softc *, void *), void *);
1342ccb96312Sdlg static void	ixl_atq_post(struct ixl_softc *, struct ixl_atq *);
1343ccb96312Sdlg static void	ixl_atq_done(struct ixl_softc *);
1344ccb96312Sdlg static void	ixl_atq_exec(struct ixl_softc *, struct ixl_atq *,
1345ccb96312Sdlg 		    const char *);
1346ccb96312Sdlg static int	ixl_get_version(struct ixl_softc *);
1347ccb96312Sdlg static int	ixl_pxe_clear(struct ixl_softc *);
1348ccb96312Sdlg static int	ixl_lldp_shut(struct ixl_softc *);
1349ccb96312Sdlg static int	ixl_get_mac(struct ixl_softc *);
1350ccb96312Sdlg static int	ixl_get_switch_config(struct ixl_softc *);
1351ccb96312Sdlg static int	ixl_phy_mask_ints(struct ixl_softc *);
135225fbbcc0Sdlg static int	ixl_get_phy_types(struct ixl_softc *, uint64_t *);
1353ccb96312Sdlg static int	ixl_restart_an(struct ixl_softc *);
1354ccb96312Sdlg static int	ixl_hmc(struct ixl_softc *);
1355eb1b42e4Sdlg static void	ixl_hmc_free(struct ixl_softc *);
1356ccb96312Sdlg static int	ixl_get_vsi(struct ixl_softc *);
1357ccb96312Sdlg static int	ixl_set_vsi(struct ixl_softc *);
1358ccb96312Sdlg static int	ixl_get_link_status(struct ixl_softc *);
1359ccb96312Sdlg static int	ixl_set_link_status(struct ixl_softc *,
1360ccb96312Sdlg 		    const struct ixl_aq_desc *);
13612bb8400cSjmatthew static int	ixl_add_macvlan(struct ixl_softc *, uint8_t *, uint16_t,
13622bb8400cSjmatthew 		    uint16_t);
13632bb8400cSjmatthew static int	ixl_remove_macvlan(struct ixl_softc *, uint8_t *, uint16_t,
13642bb8400cSjmatthew 		    uint16_t);
136510e66d97Sjmatthew static void	ixl_link_state_update(void *);
1366ccb96312Sdlg static void	ixl_arq(void *);
1367ccb96312Sdlg static void	ixl_hmc_pack(void *, const void *,
1368ccb96312Sdlg 		    const struct ixl_hmc_pack *, unsigned int);
1369ccb96312Sdlg 
13704eec9beaSdlg static int	ixl_get_sffpage(struct ixl_softc *, struct if_sffpage *);
13714eec9beaSdlg static int	ixl_sff_get_byte(struct ixl_softc *, uint8_t, uint32_t,
13724eec9beaSdlg 		    uint8_t *);
13734eec9beaSdlg static int	ixl_sff_set_byte(struct ixl_softc *, uint8_t, uint32_t,
13744eec9beaSdlg 		    uint8_t);
13754eec9beaSdlg 
1376ccb96312Sdlg static int	ixl_match(struct device *, void *, void *);
1377ccb96312Sdlg static void	ixl_attach(struct device *, struct device *, void *);
1378ccb96312Sdlg 
1379ccb96312Sdlg static void	ixl_media_add(struct ixl_softc *, uint64_t);
1380ccb96312Sdlg static int	ixl_media_change(struct ifnet *);
1381ccb96312Sdlg static void	ixl_media_status(struct ifnet *, struct ifmediareq *);
1382ccb96312Sdlg static void	ixl_watchdog(struct ifnet *);
1383ccb96312Sdlg static int	ixl_ioctl(struct ifnet *, u_long, caddr_t);
1384ccb96312Sdlg static void	ixl_start(struct ifqueue *);
13859b0c6e1eSjmatthew static int	ixl_intr0(void *);
1386e01adc04Sdlg static int	ixl_intr_vector(void *);
1387ccb96312Sdlg static int	ixl_up(struct ixl_softc *);
1388ccb96312Sdlg static int	ixl_down(struct ixl_softc *);
1389ccb96312Sdlg static int	ixl_iff(struct ixl_softc *);
1390ccb96312Sdlg 
1391ccb96312Sdlg static struct ixl_tx_ring *
1392ccb96312Sdlg 		ixl_txr_alloc(struct ixl_softc *, unsigned int);
1393eb1b42e4Sdlg static void	ixl_txr_qdis(struct ixl_softc *, struct ixl_tx_ring *, int);
1394ccb96312Sdlg static void	ixl_txr_config(struct ixl_softc *, struct ixl_tx_ring *);
1395eb1b42e4Sdlg static int	ixl_txr_enabled(struct ixl_softc *, struct ixl_tx_ring *);
1396eb1b42e4Sdlg static int	ixl_txr_disabled(struct ixl_softc *, struct ixl_tx_ring *);
1397ccb96312Sdlg static void	ixl_txr_unconfig(struct ixl_softc *, struct ixl_tx_ring *);
1398ccb96312Sdlg static void	ixl_txr_clean(struct ixl_softc *, struct ixl_tx_ring *);
1399ccb96312Sdlg static void	ixl_txr_free(struct ixl_softc *, struct ixl_tx_ring *);
1400e01adc04Sdlg static int	ixl_txeof(struct ixl_softc *, struct ixl_tx_ring *);
1401ccb96312Sdlg 
1402ccb96312Sdlg static struct ixl_rx_ring *
1403ccb96312Sdlg 		ixl_rxr_alloc(struct ixl_softc *, unsigned int);
1404ccb96312Sdlg static void	ixl_rxr_config(struct ixl_softc *, struct ixl_rx_ring *);
1405eb1b42e4Sdlg static int	ixl_rxr_enabled(struct ixl_softc *, struct ixl_rx_ring *);
1406eb1b42e4Sdlg static int	ixl_rxr_disabled(struct ixl_softc *, struct ixl_rx_ring *);
1407ccb96312Sdlg static void	ixl_rxr_unconfig(struct ixl_softc *, struct ixl_rx_ring *);
1408ccb96312Sdlg static void	ixl_rxr_clean(struct ixl_softc *, struct ixl_rx_ring *);
1409ccb96312Sdlg static void	ixl_rxr_free(struct ixl_softc *, struct ixl_rx_ring *);
1410e01adc04Sdlg static int	ixl_rxeof(struct ixl_softc *, struct ixl_rx_ring *);
1411ccb96312Sdlg static void	ixl_rxfill(struct ixl_softc *, struct ixl_rx_ring *);
1412ccb96312Sdlg static void	ixl_rxrefill(void *);
141396438522Sjmatthew static int	ixl_rxrinfo(struct ixl_softc *, struct if_rxrinfo *);
141489760ddfSbluhm static void	ixl_rx_checksum(struct mbuf *, uint64_t);
1415ccb96312Sdlg 
14162ee1fcb3Sdlg #if NKSTAT > 0
14172ee1fcb3Sdlg static void	ixl_kstat_attach(struct ixl_softc *);
14182ee1fcb3Sdlg #endif
14192ee1fcb3Sdlg 
1420ccb96312Sdlg struct cfdriver ixl_cd = {
1421ccb96312Sdlg 	NULL,
1422ccb96312Sdlg 	"ixl",
1423ccb96312Sdlg 	DV_IFNET,
1424ccb96312Sdlg };
1425ccb96312Sdlg 
14268d2c75e4Smpi const struct cfattach ixl_ca = {
1427ccb96312Sdlg 	sizeof(struct ixl_softc),
1428ccb96312Sdlg 	ixl_match,
1429ccb96312Sdlg 	ixl_attach,
1430ccb96312Sdlg };
1431ccb96312Sdlg 
1432ccb96312Sdlg static const struct ixl_phy_type ixl_phy_type_map[] = {
1433ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_SGMII,		IFM_1000_SGMII },
1434ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_1000BASE_KX,	IFM_1000_KX },
1435ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_10GBASE_KX4,	IFM_10G_KX4 },
1436ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_10GBASE_KR,	IFM_10G_KR },
1437ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_40GBASE_KR4,	IFM_40G_KR4 },
1438ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_XAUI |
1439ccb96312Sdlg 	  1ULL << IXL_PHY_TYPE_XFI,		IFM_10G_CX4 },
1440ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_SFI,		IFM_10G_SFI },
1441ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_XLAUI |
1442ccb96312Sdlg 	  1ULL << IXL_PHY_TYPE_XLPPI,		IFM_40G_XLPPI },
1443ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_40GBASE_CR4_CU |
1444ccb96312Sdlg 	  1ULL << IXL_PHY_TYPE_40GBASE_CR4,	IFM_40G_CR4 },
1445ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_10GBASE_CR1_CU |
1446ccb96312Sdlg 	  1ULL << IXL_PHY_TYPE_10GBASE_CR1,	IFM_10G_CR1 },
1447ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_10GBASE_AOC,	IFM_10G_AOC },
1448ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_40GBASE_AOC,	IFM_40G_AOC },
1449ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_100BASE_TX,	IFM_100_TX },
1450ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_1000BASE_T_OPTICAL |
1451ccb96312Sdlg 	  1ULL << IXL_PHY_TYPE_1000BASE_T,	IFM_1000_T },
1452ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_10GBASE_T,	IFM_10G_T },
1453ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_10GBASE_SR,	IFM_10G_SR },
1454ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_10GBASE_LR,	IFM_10G_LR },
1455ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_10GBASE_SFPP_CU,	IFM_10G_SFP_CU },
1456ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_40GBASE_SR4,	IFM_40G_SR4 },
1457ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_40GBASE_LR4,	IFM_40G_LR4 },
1458ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_1000BASE_SX,	IFM_1000_SX },
1459ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_1000BASE_LX,	IFM_1000_LX },
1460ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_20GBASE_KR2,	IFM_20G_KR2 },
1461ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_25GBASE_KR,	IFM_25G_KR },
1462ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_25GBASE_CR,	IFM_25G_CR },
1463ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_25GBASE_SR,	IFM_25G_SR },
1464ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_25GBASE_LR,	IFM_25G_LR },
1465ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_25GBASE_AOC,	IFM_25G_AOC },
1466ccb96312Sdlg 	{ 1ULL << IXL_PHY_TYPE_25GBASE_ACC,	IFM_25G_CR },
1467ccb96312Sdlg };
1468ccb96312Sdlg 
1469ccb96312Sdlg static const struct ixl_speed_type ixl_speed_type_map[] = {
1470a4742ff3Sdlg 	{ IXL_AQ_LINK_SPEED_40GB,		IF_Gbps(40) },
1471a4742ff3Sdlg 	{ IXL_AQ_LINK_SPEED_25GB,		IF_Gbps(25) },
1472a4742ff3Sdlg 	{ IXL_AQ_LINK_SPEED_10GB,		IF_Gbps(10) },
1473a4742ff3Sdlg 	{ IXL_AQ_LINK_SPEED_1GB,		IF_Gbps(1) },
1474ccb96312Sdlg };
1475ccb96312Sdlg 
1476ccb96312Sdlg static const struct ixl_aq_regs ixl_pf_aq_regs = {
1477ccb96312Sdlg 	.atq_tail	= I40E_PF_ATQT,
1478ccb96312Sdlg 	.atq_tail_mask	= I40E_PF_ATQT_ATQT_MASK,
1479ccb96312Sdlg 	.atq_head	= I40E_PF_ATQH,
1480ccb96312Sdlg 	.atq_head_mask	= I40E_PF_ATQH_ATQH_MASK,
1481ccb96312Sdlg 	.atq_len	= I40E_PF_ATQLEN,
1482ccb96312Sdlg 	.atq_bal	= I40E_PF_ATQBAL,
1483ccb96312Sdlg 	.atq_bah	= I40E_PF_ATQBAH,
1484ccb96312Sdlg 	.atq_len_enable	= I40E_PF_ATQLEN_ATQENABLE_MASK,
1485ccb96312Sdlg 
1486ccb96312Sdlg 	.arq_tail	= I40E_PF_ARQT,
1487ccb96312Sdlg 	.arq_tail_mask	= I40E_PF_ARQT_ARQT_MASK,
1488ccb96312Sdlg 	.arq_head	= I40E_PF_ARQH,
1489ccb96312Sdlg 	.arq_head_mask	= I40E_PF_ARQH_ARQH_MASK,
1490ccb96312Sdlg 	.arq_len	= I40E_PF_ARQLEN,
1491ccb96312Sdlg 	.arq_bal	= I40E_PF_ARQBAL,
1492ccb96312Sdlg 	.arq_bah	= I40E_PF_ARQBAH,
1493ccb96312Sdlg 	.arq_len_enable	= I40E_PF_ARQLEN_ARQENABLE_MASK,
1494ccb96312Sdlg };
1495ccb96312Sdlg 
1496ccb96312Sdlg #define ixl_rd(_s, _r) \
1497ccb96312Sdlg 	bus_space_read_4((_s)->sc_memt, (_s)->sc_memh, (_r))
1498ccb96312Sdlg #define ixl_wr(_s, _r, _v) \
1499ccb96312Sdlg 	bus_space_write_4((_s)->sc_memt, (_s)->sc_memh, (_r), (_v))
1500ccb96312Sdlg #define ixl_barrier(_s, _r, _l, _o) \
1501ccb96312Sdlg 	bus_space_barrier((_s)->sc_memt, (_s)->sc_memh, (_r), (_l), (_o))
1502ccb96312Sdlg #define ixl_intr_enable(_s) \
1503ccb96312Sdlg 	ixl_wr((_s), I40E_PFINT_DYN_CTL0, I40E_PFINT_DYN_CTL0_INTENA_MASK | \
1504ccb96312Sdlg 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | \
1505ccb96312Sdlg 	    (IXL_NOITR << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT))
1506ccb96312Sdlg 
1507eb1b42e4Sdlg #define ixl_nqueues(_sc)	(1 << (_sc)->sc_nqueues)
1508eb1b42e4Sdlg 
1509ccb96312Sdlg #ifdef __LP64__
1510ccb96312Sdlg #define ixl_dmamem_hi(_ixm)	(uint32_t)(IXL_DMA_DVA(_ixm) >> 32)
1511ccb96312Sdlg #else
1512ccb96312Sdlg #define ixl_dmamem_hi(_ixm)	0
1513ccb96312Sdlg #endif
1514ccb96312Sdlg 
1515ccb96312Sdlg #define ixl_dmamem_lo(_ixm)	(uint32_t)IXL_DMA_DVA(_ixm)
1516ccb96312Sdlg 
1517ccb96312Sdlg static inline void
ixl_aq_dva(struct ixl_aq_desc * iaq,bus_addr_t addr)1518ccb96312Sdlg ixl_aq_dva(struct ixl_aq_desc *iaq, bus_addr_t addr)
1519ccb96312Sdlg {
1520ccb96312Sdlg #ifdef __LP64__
1521ccb96312Sdlg 	htolem32(&iaq->iaq_param[2], addr >> 32);
1522ccb96312Sdlg #else
1523ccb96312Sdlg 	iaq->iaq_param[2] = htole32(0);
1524ccb96312Sdlg #endif
1525ccb96312Sdlg 	htolem32(&iaq->iaq_param[3], addr);
1526ccb96312Sdlg }
1527ccb96312Sdlg 
1528ccb96312Sdlg #if _BYTE_ORDER == _BIG_ENDIAN
1529ccb96312Sdlg #define HTOLE16(_x)	(uint16_t)(((_x) & 0xff) << 8 | ((_x) & 0xff00) >> 8)
1530ccb96312Sdlg #else
1531ccb96312Sdlg #define HTOLE16(_x)	(_x)
1532ccb96312Sdlg #endif
1533ccb96312Sdlg 
15344eec9beaSdlg static struct rwlock ixl_sff_lock = RWLOCK_INITIALIZER("ixlsff");
15354eec9beaSdlg 
1536819ac441Sdlg /* deal with differences between chips */
1537819ac441Sdlg 
1538db742a36Sdlg struct ixl_chip {
15398d616574Sdlg 	uint64_t		  ic_rss_hena;
1540819ac441Sdlg 	uint32_t		(*ic_rd_ctl)(struct ixl_softc *, uint32_t);
1541819ac441Sdlg 	void			(*ic_wr_ctl)(struct ixl_softc *, uint32_t,
1542819ac441Sdlg 				      uint32_t);
1543819ac441Sdlg 
1544819ac441Sdlg 	int			(*ic_set_rss_key)(struct ixl_softc *,
1545819ac441Sdlg 				      const struct ixl_rss_key *);
1546819ac441Sdlg 	int			(*ic_set_rss_lut)(struct ixl_softc *,
1547819ac441Sdlg 				      const struct ixl_rss_lut_128 *);
1548ccb96312Sdlg };
1549ccb96312Sdlg 
1550819ac441Sdlg static inline uint64_t
ixl_rss_hena(struct ixl_softc * sc)1551819ac441Sdlg ixl_rss_hena(struct ixl_softc *sc)
1552819ac441Sdlg {
1553819ac441Sdlg 	return (sc->sc_chip->ic_rss_hena);
1554819ac441Sdlg }
1555819ac441Sdlg 
1556819ac441Sdlg static inline uint32_t
ixl_rd_ctl(struct ixl_softc * sc,uint32_t r)1557819ac441Sdlg ixl_rd_ctl(struct ixl_softc *sc, uint32_t r)
1558819ac441Sdlg {
1559819ac441Sdlg 	return ((*sc->sc_chip->ic_rd_ctl)(sc, r));
1560819ac441Sdlg }
1561819ac441Sdlg 
1562819ac441Sdlg static inline void
ixl_wr_ctl(struct ixl_softc * sc,uint32_t r,uint32_t v)1563819ac441Sdlg ixl_wr_ctl(struct ixl_softc *sc, uint32_t r, uint32_t v)
1564819ac441Sdlg {
1565819ac441Sdlg 	(*sc->sc_chip->ic_wr_ctl)(sc, r, v);
1566819ac441Sdlg }
1567819ac441Sdlg 
1568819ac441Sdlg static inline int
ixl_set_rss_key(struct ixl_softc * sc,const struct ixl_rss_key * rsskey)1569819ac441Sdlg ixl_set_rss_key(struct ixl_softc *sc, const struct ixl_rss_key *rsskey)
1570819ac441Sdlg {
1571819ac441Sdlg 	return ((*sc->sc_chip->ic_set_rss_key)(sc, rsskey));
1572819ac441Sdlg }
1573819ac441Sdlg 
1574819ac441Sdlg static inline int
ixl_set_rss_lut(struct ixl_softc * sc,const struct ixl_rss_lut_128 * lut)1575819ac441Sdlg ixl_set_rss_lut(struct ixl_softc *sc, const struct ixl_rss_lut_128 *lut)
1576819ac441Sdlg {
1577819ac441Sdlg 	return ((*sc->sc_chip->ic_set_rss_lut)(sc, lut));
1578819ac441Sdlg }
1579819ac441Sdlg 
1580819ac441Sdlg /* 710 chip specifics */
1581819ac441Sdlg 
1582819ac441Sdlg static uint32_t		ixl_710_rd_ctl(struct ixl_softc *, uint32_t);
1583819ac441Sdlg static void		ixl_710_wr_ctl(struct ixl_softc *, uint32_t, uint32_t);
1584819ac441Sdlg static int		ixl_710_set_rss_key(struct ixl_softc *,
1585819ac441Sdlg 			    const struct ixl_rss_key *);
1586819ac441Sdlg static int		ixl_710_set_rss_lut(struct ixl_softc *,
1587819ac441Sdlg 			    const struct ixl_rss_lut_128 *);
1588819ac441Sdlg 
1589db742a36Sdlg static const struct ixl_chip ixl_710 = {
15908d616574Sdlg 	.ic_rss_hena =		IXL_RSS_HENA_BASE_710,
1591819ac441Sdlg 	.ic_rd_ctl =		ixl_710_rd_ctl,
1592819ac441Sdlg 	.ic_wr_ctl =		ixl_710_wr_ctl,
1593819ac441Sdlg 	.ic_set_rss_key =	ixl_710_set_rss_key,
1594819ac441Sdlg 	.ic_set_rss_lut =	ixl_710_set_rss_lut,
1595db742a36Sdlg };
1596db742a36Sdlg 
1597819ac441Sdlg /* 722 chip specifics */
1598819ac441Sdlg 
1599819ac441Sdlg static uint32_t		ixl_722_rd_ctl(struct ixl_softc *, uint32_t);
1600819ac441Sdlg static void		ixl_722_wr_ctl(struct ixl_softc *, uint32_t, uint32_t);
1601819ac441Sdlg static int		ixl_722_set_rss_key(struct ixl_softc *,
1602819ac441Sdlg 			    const struct ixl_rss_key *);
1603819ac441Sdlg static int		ixl_722_set_rss_lut(struct ixl_softc *,
1604819ac441Sdlg 			    const struct ixl_rss_lut_128 *);
1605819ac441Sdlg 
1606db742a36Sdlg static const struct ixl_chip ixl_722 = {
16078d616574Sdlg 	.ic_rss_hena =		IXL_RSS_HENA_BASE_722,
1608819ac441Sdlg 	.ic_rd_ctl =		ixl_722_rd_ctl,
1609819ac441Sdlg 	.ic_wr_ctl =		ixl_722_wr_ctl,
1610819ac441Sdlg 	.ic_set_rss_key =	ixl_722_set_rss_key,
1611819ac441Sdlg 	.ic_set_rss_lut =	ixl_722_set_rss_lut,
1612db742a36Sdlg };
1613db742a36Sdlg 
1614f5777d33Sdlg /*
1615f5777d33Sdlg  * 710 chips using an older firmware/API use the same ctl ops as
1616f5777d33Sdlg  * 722 chips. or 722 chips use the same ctl ops as 710 chips in early
1617f5777d33Sdlg  * firmware/API versions?
1618f5777d33Sdlg */
1619f5777d33Sdlg 
1620f5777d33Sdlg static const struct ixl_chip ixl_710_decrepit = {
1621f5777d33Sdlg 	.ic_rss_hena =		IXL_RSS_HENA_BASE_710,
1622f5777d33Sdlg 	.ic_rd_ctl =		ixl_722_rd_ctl,
1623f5777d33Sdlg 	.ic_wr_ctl =		ixl_722_wr_ctl,
1624f5777d33Sdlg 	.ic_set_rss_key =	ixl_710_set_rss_key,
1625f5777d33Sdlg 	.ic_set_rss_lut =	ixl_710_set_rss_lut,
1626f5777d33Sdlg };
1627f5777d33Sdlg 
1628819ac441Sdlg /* driver code */
1629819ac441Sdlg 
1630db742a36Sdlg struct ixl_device {
1631db742a36Sdlg 	const struct ixl_chip	*id_chip;
1632db742a36Sdlg 	pci_vendor_id_t		 id_vid;
1633db742a36Sdlg 	pci_product_id_t	 id_pid;
1634db742a36Sdlg };
1635db742a36Sdlg 
1636db742a36Sdlg static const struct ixl_device ixl_devices[] = {
1637db742a36Sdlg 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X710_10G_SFP },
1638c85bea54Sjan 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X710_10G_SFP_2 },
1639db742a36Sdlg 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_XL710_40G_BP },
1640db742a36Sdlg 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X710_10G_BP, },
1641db742a36Sdlg 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_XL710_QSFP_1 },
1642db742a36Sdlg 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_XL710_QSFP_2 },
1643db742a36Sdlg 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X710_10G_QSFP },
1644db742a36Sdlg 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X710_10G_BASET },
1645db742a36Sdlg 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_XL710_20G_BP_1 },
1646db742a36Sdlg 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_XL710_20G_BP_2 },
1647db742a36Sdlg 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X710_T4_10G },
1648db742a36Sdlg 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_XXV710_25G_BP },
1649db742a36Sdlg 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_XXV710_25G_SFP28, },
1650ae527cb3Sjan 	{ &ixl_710, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X710_10G_T, },
1651db742a36Sdlg 	{ &ixl_722, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X722_10G_KX },
1652db742a36Sdlg 	{ &ixl_722, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X722_10G_QSFP },
1653db742a36Sdlg 	{ &ixl_722, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X722_10G_SFP_1 },
1654db742a36Sdlg 	{ &ixl_722, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X722_1G },
1655db742a36Sdlg 	{ &ixl_722, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X722_10G_T },
1656db742a36Sdlg 	{ &ixl_722, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X722_10G_SFP_2 },
1657db742a36Sdlg };
1658db742a36Sdlg 
1659db742a36Sdlg static const struct ixl_device *
ixl_device_lookup(struct pci_attach_args * pa)1660db742a36Sdlg ixl_device_lookup(struct pci_attach_args *pa)
1661db742a36Sdlg {
1662db742a36Sdlg 	pci_vendor_id_t vid = PCI_VENDOR(pa->pa_id);
1663db742a36Sdlg 	pci_product_id_t pid = PCI_PRODUCT(pa->pa_id);
1664db742a36Sdlg 	const struct ixl_device *id;
1665db742a36Sdlg 	unsigned int i;
1666db742a36Sdlg 
1667db742a36Sdlg 	for (i = 0; i < nitems(ixl_devices); i++) {
1668db742a36Sdlg 		id = &ixl_devices[i];
1669db742a36Sdlg 		if (id->id_vid == vid && id->id_pid == pid)
1670db742a36Sdlg 			return (id);
1671db742a36Sdlg 	}
1672db742a36Sdlg 
1673db742a36Sdlg 	return (NULL);
1674db742a36Sdlg }
1675db742a36Sdlg 
1676ccb96312Sdlg static int
ixl_match(struct device * parent,void * match,void * aux)1677ccb96312Sdlg ixl_match(struct device *parent, void *match, void *aux)
1678ccb96312Sdlg {
1679db742a36Sdlg 	return (ixl_device_lookup(aux) != NULL);
1680ccb96312Sdlg }
1681ccb96312Sdlg 
1682ccb96312Sdlg void
ixl_attach(struct device * parent,struct device * self,void * aux)1683ccb96312Sdlg ixl_attach(struct device *parent, struct device *self, void *aux)
1684ccb96312Sdlg {
1685ccb96312Sdlg 	struct ixl_softc *sc = (struct ixl_softc *)self;
1686ccb96312Sdlg 	struct ifnet *ifp = &sc->sc_ac.ac_if;
1687ccb96312Sdlg 	struct pci_attach_args *pa = aux;
1688ccb96312Sdlg 	pcireg_t memtype;
1689ccb96312Sdlg 	uint32_t port, ari, func;
1690ccb96312Sdlg 	uint64_t phy_types = 0;
1691e01adc04Sdlg 	unsigned int nqueues, i;
1692ccb96312Sdlg 	int tries;
1693ccb96312Sdlg 
1694d3ac7020Sdlg 	rw_init(&sc->sc_cfg_lock, "ixlcfg");
1695d3ac7020Sdlg 
1696819ac441Sdlg 	sc->sc_chip = ixl_device_lookup(pa)->id_chip;
1697ccb96312Sdlg 	sc->sc_pc = pa->pa_pc;
1698ccb96312Sdlg 	sc->sc_tag = pa->pa_tag;
1699ccb96312Sdlg 	sc->sc_dmat = pa->pa_dmat;
170001fa8758Sjmatthew 	sc->sc_aq_regs = &ixl_pf_aq_regs;
1701ccb96312Sdlg 
1702eb1b42e4Sdlg 	sc->sc_nqueues = 0; /* 1 << 0 is 1 queue */
1703ccb96312Sdlg 	sc->sc_tx_ring_ndescs = 1024;
1704ccb96312Sdlg 	sc->sc_rx_ring_ndescs = 1024;
1705ccb96312Sdlg 
1706ccb96312Sdlg 	memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, IXL_PCIREG);
170753ad6b53Sjmatthew 	if (pci_mapreg_map(pa, IXL_PCIREG, memtype, 0,
1708ccb96312Sdlg 	    &sc->sc_memt, &sc->sc_memh, NULL, &sc->sc_mems, 0)) {
1709ccb96312Sdlg 		printf(": unable to map registers\n");
1710ccb96312Sdlg 		return;
1711ccb96312Sdlg 	}
1712ccb96312Sdlg 
1713eb1b42e4Sdlg 	sc->sc_base_queue = (ixl_rd(sc, I40E_PFLAN_QALLOC) &
1714eb1b42e4Sdlg 	    I40E_PFLAN_QALLOC_FIRSTQ_MASK) >>
1715eb1b42e4Sdlg 	    I40E_PFLAN_QALLOC_FIRSTQ_SHIFT;
1716eb1b42e4Sdlg 
1717ccb96312Sdlg 	ixl_clear_hw(sc);
1718ccb96312Sdlg 	if (ixl_pf_reset(sc) == -1) {
1719ccb96312Sdlg 		/* error printed by ixl_pf_reset */
1720ccb96312Sdlg 		goto unmap;
1721ccb96312Sdlg 	}
1722ccb96312Sdlg 
1723ccb96312Sdlg 	port = ixl_rd(sc, I40E_PFGEN_PORTNUM);
1724ccb96312Sdlg 	port &= I40E_PFGEN_PORTNUM_PORT_NUM_MASK;
1725ccb96312Sdlg 	port >>= I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT;
17262ee1fcb3Sdlg 	sc->sc_port = port;
1727ccb96312Sdlg 	printf(": port %u", port);
1728ccb96312Sdlg 
1729ccb96312Sdlg 	ari = ixl_rd(sc, I40E_GLPCI_CAPSUP);
1730ccb96312Sdlg 	ari &= I40E_GLPCI_CAPSUP_ARI_EN_MASK;
1731ccb96312Sdlg 	ari >>= I40E_GLPCI_CAPSUP_ARI_EN_SHIFT;
1732ccb96312Sdlg 
1733ccb96312Sdlg 	func = ixl_rd(sc, I40E_PF_FUNC_RID);
1734ccb96312Sdlg 	sc->sc_pf_id = func & (ari ? 0xff : 0x7);
1735ccb96312Sdlg 
1736ccb96312Sdlg 	/* initialise the adminq */
1737ccb96312Sdlg 
173895f940dfSjan 	mtx_init(&sc->sc_atq_mtx, IPL_NET);
173995f940dfSjan 
1740ccb96312Sdlg 	if (ixl_dmamem_alloc(sc, &sc->sc_atq,
1741ccb96312Sdlg 	    sizeof(struct ixl_aq_desc) * IXL_AQ_NUM, IXL_AQ_ALIGN) != 0) {
1742ccb96312Sdlg 		printf("\n" "%s: unable to allocate atq\n", DEVNAME(sc));
1743ccb96312Sdlg 		goto unmap;
1744ccb96312Sdlg 	}
1745ccb96312Sdlg 
1746ccb96312Sdlg 	SIMPLEQ_INIT(&sc->sc_arq_idle);
1747ccb96312Sdlg 	SIMPLEQ_INIT(&sc->sc_arq_live);
1748ccb96312Sdlg 	if_rxr_init(&sc->sc_arq_ring, 2, IXL_AQ_NUM - 1);
1749ccb96312Sdlg 	task_set(&sc->sc_arq_task, ixl_arq, sc);
1750ccb96312Sdlg 	sc->sc_arq_cons = 0;
1751ccb96312Sdlg 	sc->sc_arq_prod = 0;
1752ccb96312Sdlg 
1753ccb96312Sdlg 	if (ixl_dmamem_alloc(sc, &sc->sc_arq,
1754ccb96312Sdlg 	    sizeof(struct ixl_aq_desc) * IXL_AQ_NUM, IXL_AQ_ALIGN) != 0) {
1755ccb96312Sdlg 		printf("\n" "%s: unable to allocate arq\n", DEVNAME(sc));
1756ccb96312Sdlg 		goto free_atq;
1757ccb96312Sdlg 	}
1758ccb96312Sdlg 
1759ccb96312Sdlg 	if (!ixl_arq_fill(sc)) {
1760ccb96312Sdlg 		printf("\n" "%s: unable to fill arq descriptors\n",
1761ccb96312Sdlg 		    DEVNAME(sc));
1762ccb96312Sdlg 		goto free_arq;
1763ccb96312Sdlg 	}
1764ccb96312Sdlg 
1765ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_atq),
1766ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_atq),
1767ccb96312Sdlg 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
1768ccb96312Sdlg 
1769ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_arq),
1770ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_arq),
1771ccb96312Sdlg 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
1772ccb96312Sdlg 
1773ccb96312Sdlg 	for (tries = 0; tries < 10; tries++) {
1774ccb96312Sdlg 		int rv;
1775ccb96312Sdlg 
1776ccb96312Sdlg 		sc->sc_atq_cons = 0;
1777ccb96312Sdlg 		sc->sc_atq_prod = 0;
1778ccb96312Sdlg 
1779ccb96312Sdlg 		ixl_wr(sc, sc->sc_aq_regs->atq_head, 0);
1780ccb96312Sdlg 		ixl_wr(sc, sc->sc_aq_regs->arq_head, 0);
1781ccb96312Sdlg 		ixl_wr(sc, sc->sc_aq_regs->atq_tail, 0);
1782ccb96312Sdlg 		ixl_wr(sc, sc->sc_aq_regs->arq_tail, 0);
1783ccb96312Sdlg 
1784ccb96312Sdlg 		ixl_barrier(sc, 0, sc->sc_mems, BUS_SPACE_BARRIER_WRITE);
1785ccb96312Sdlg 
1786ccb96312Sdlg 		ixl_wr(sc, sc->sc_aq_regs->atq_bal,
1787ccb96312Sdlg 		    ixl_dmamem_lo(&sc->sc_atq));
1788ccb96312Sdlg 		ixl_wr(sc, sc->sc_aq_regs->atq_bah,
1789ccb96312Sdlg 		    ixl_dmamem_hi(&sc->sc_atq));
1790ccb96312Sdlg 		ixl_wr(sc, sc->sc_aq_regs->atq_len,
1791ccb96312Sdlg 		    sc->sc_aq_regs->atq_len_enable | IXL_AQ_NUM);
1792ccb96312Sdlg 
1793ccb96312Sdlg 		ixl_wr(sc, sc->sc_aq_regs->arq_bal,
1794ccb96312Sdlg 		    ixl_dmamem_lo(&sc->sc_arq));
1795ccb96312Sdlg 		ixl_wr(sc, sc->sc_aq_regs->arq_bah,
1796ccb96312Sdlg 		    ixl_dmamem_hi(&sc->sc_arq));
1797ccb96312Sdlg 		ixl_wr(sc, sc->sc_aq_regs->arq_len,
1798ccb96312Sdlg 		    sc->sc_aq_regs->arq_len_enable | IXL_AQ_NUM);
1799ccb96312Sdlg 
1800ccb96312Sdlg 		rv = ixl_get_version(sc);
1801ccb96312Sdlg 		if (rv == 0)
1802ccb96312Sdlg 			break;
1803ccb96312Sdlg 		if (rv != ETIMEDOUT) {
1804ccb96312Sdlg 			printf(", unable to get firmware version\n");
1805ccb96312Sdlg 			goto shutdown;
1806ccb96312Sdlg 		}
1807ccb96312Sdlg 
1808ccb96312Sdlg 		delaymsec(100);
1809ccb96312Sdlg 	}
1810ccb96312Sdlg 
1811ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->arq_tail, sc->sc_arq_prod);
1812ccb96312Sdlg 
1813ccb96312Sdlg 	if (ixl_pxe_clear(sc) != 0) {
1814ccb96312Sdlg 		/* error printed by ixl_pxe_clear */
1815ccb96312Sdlg 		goto shutdown;
1816ccb96312Sdlg 	}
1817ccb96312Sdlg 
1818ccb96312Sdlg 	if (ixl_get_mac(sc) != 0) {
1819ccb96312Sdlg 		/* error printed by ixl_get_mac */
1820ccb96312Sdlg 		goto shutdown;
1821ccb96312Sdlg 	}
1822ccb96312Sdlg 
18239b0c6e1eSjmatthew 	if (pci_intr_map_msix(pa, 0, &sc->sc_ih) == 0) {
1824bc8858ceSjmatthew 		int nmsix = pci_intr_msix_count(pa);
1825e01adc04Sdlg 		if (nmsix > 1) { /* we used 1 (the 0th) for the adminq */
1826e01adc04Sdlg 			nmsix--;
1827e01adc04Sdlg 
1828e01adc04Sdlg 			sc->sc_intrmap = intrmap_create(&sc->sc_dev,
1829e01adc04Sdlg 			    nmsix, IXL_MAX_VECTORS, INTRMAP_POWEROF2);
1830e01adc04Sdlg 			nqueues = intrmap_count(sc->sc_intrmap);
1831e01adc04Sdlg 			KASSERT(nqueues > 0);
1832e01adc04Sdlg 			KASSERT(powerof2(nqueues));
1833e01adc04Sdlg 			sc->sc_nqueues = fls(nqueues) - 1;
18349b0c6e1eSjmatthew 		}
18359b0c6e1eSjmatthew 	} else {
1836ccb96312Sdlg 		if (pci_intr_map_msi(pa, &sc->sc_ih) != 0 &&
1837ccb96312Sdlg 		    pci_intr_map(pa, &sc->sc_ih) != 0) {
1838ccb96312Sdlg 			printf(", unable to map interrupt\n");
1839ccb96312Sdlg 			goto shutdown;
1840ccb96312Sdlg 		}
18419b0c6e1eSjmatthew 	}
1842ccb96312Sdlg 
1843e01adc04Sdlg 	nqueues = ixl_nqueues(sc);
1844e01adc04Sdlg 
18459b0c6e1eSjmatthew 	printf(", %s, %d queue%s, address %s\n",
18469b0c6e1eSjmatthew 	    pci_intr_string(sc->sc_pc, sc->sc_ih), ixl_nqueues(sc),
1847e01adc04Sdlg 	    (nqueues > 1 ? "s" : ""),
1848ccb96312Sdlg 	    ether_sprintf(sc->sc_ac.ac_enaddr));
1849ccb96312Sdlg 
1850ccb96312Sdlg 	if (ixl_hmc(sc) != 0) {
1851ccb96312Sdlg 		/* error printed by ixl_hmc */
1852ccb96312Sdlg 		goto shutdown;
1853ccb96312Sdlg 	}
1854ccb96312Sdlg 
1855ccb96312Sdlg 	if (ixl_lldp_shut(sc) != 0) {
1856ccb96312Sdlg 		/* error printed by ixl_lldp_shut */
1857eb1b42e4Sdlg 		goto free_hmc;
1858ccb96312Sdlg 	}
1859ccb96312Sdlg 
1860ccb96312Sdlg 	if (ixl_phy_mask_ints(sc) != 0) {
1861ccb96312Sdlg 		/* error printed by ixl_phy_mask_ints */
1862eb1b42e4Sdlg 		goto free_hmc;
1863ccb96312Sdlg 	}
1864ccb96312Sdlg 
1865ccb96312Sdlg 	if (ixl_restart_an(sc) != 0) {
1866ccb96312Sdlg 		/* error printed by ixl_restart_an */
1867eb1b42e4Sdlg 		goto free_hmc;
1868ccb96312Sdlg 	}
1869ccb96312Sdlg 
1870ccb96312Sdlg 	if (ixl_get_switch_config(sc) != 0) {
1871ccb96312Sdlg 		/* error printed by ixl_get_switch_config */
1872eb1b42e4Sdlg 		goto free_hmc;
1873ccb96312Sdlg 	}
1874ccb96312Sdlg 
187525fbbcc0Sdlg 	if (ixl_get_phy_types(sc, &phy_types) != 0) {
1876ccb96312Sdlg 		/* error printed by ixl_get_phy_abilities */
1877eb1b42e4Sdlg 		goto free_hmc;
1878ccb96312Sdlg 	}
1879ccb96312Sdlg 
1880608c7d94Sbluhm 	mtx_init(&sc->sc_link_state_mtx, IPL_NET);
1881ccb96312Sdlg 	if (ixl_get_link_status(sc) != 0) {
1882ccb96312Sdlg 		/* error printed by ixl_get_link_status */
1883eb1b42e4Sdlg 		goto free_hmc;
1884ccb96312Sdlg 	}
1885ccb96312Sdlg 
18862bb8400cSjmatthew 	if (ixl_dmamem_alloc(sc, &sc->sc_scratch,
1887ccb96312Sdlg 	    sizeof(struct ixl_aq_vsi_data), 8) != 0) {
18882bb8400cSjmatthew 		printf("%s: unable to allocate scratch buffer\n", DEVNAME(sc));
1889eb1b42e4Sdlg 		goto free_hmc;
1890ccb96312Sdlg 	}
1891ccb96312Sdlg 
1892ccb96312Sdlg 	if (ixl_get_vsi(sc) != 0) {
1893ccb96312Sdlg 		/* error printed by ixl_get_vsi */
18942bb8400cSjmatthew 		goto free_hmc;
1895ccb96312Sdlg 	}
1896ccb96312Sdlg 
1897ccb96312Sdlg 	if (ixl_set_vsi(sc) != 0) {
1898ccb96312Sdlg 		/* error printed by ixl_set_vsi */
18992bb8400cSjmatthew 		goto free_scratch;
1900ccb96312Sdlg 	}
1901ccb96312Sdlg 
1902ccb96312Sdlg 	sc->sc_ihc = pci_intr_establish(sc->sc_pc, sc->sc_ih,
19039b0c6e1eSjmatthew 	    IPL_NET | IPL_MPSAFE, ixl_intr0, sc, DEVNAME(sc));
1904ccb96312Sdlg 	if (sc->sc_ihc == NULL) {
1905ccb96312Sdlg 		printf("%s: unable to establish interrupt handler\n",
1906ccb96312Sdlg 		    DEVNAME(sc));
19072bb8400cSjmatthew 		goto free_scratch;
1908ccb96312Sdlg 	}
1909ccb96312Sdlg 
1910e01adc04Sdlg 	sc->sc_vectors = mallocarray(sizeof(*sc->sc_vectors), nqueues,
1911e01adc04Sdlg 	    M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO);
1912e01adc04Sdlg 	if (sc->sc_vectors == NULL) {
1913e01adc04Sdlg 		printf("%s: unable to allocate vectors\n", DEVNAME(sc));
19149b0c6e1eSjmatthew 		goto free_scratch;
19159b0c6e1eSjmatthew 	}
19169b0c6e1eSjmatthew 
1917e01adc04Sdlg 	for (i = 0; i < nqueues; i++) {
1918e01adc04Sdlg 		struct ixl_vector *iv = &sc->sc_vectors[i];
1919e01adc04Sdlg 		iv->iv_sc = sc;
1920e01adc04Sdlg 		iv->iv_qid = i;
1921e01adc04Sdlg 		snprintf(iv->iv_name, sizeof(iv->iv_name),
1922e01adc04Sdlg 		    "%s:%u", DEVNAME(sc), i); /* truncated? */
1923e01adc04Sdlg 	}
1924e01adc04Sdlg 
1925e01adc04Sdlg 	if (sc->sc_intrmap) {
1926e01adc04Sdlg 		for (i = 0; i < nqueues; i++) {
1927e01adc04Sdlg 			struct ixl_vector *iv = &sc->sc_vectors[i];
1928e01adc04Sdlg 			pci_intr_handle_t ih;
1929e01adc04Sdlg 			int v = i + 1; /* 0 is used for adminq */
1930e01adc04Sdlg 
1931e01adc04Sdlg 			if (pci_intr_map_msix(pa, v, &ih)) {
1932e01adc04Sdlg 				printf("%s: unable to map msi-x vector %d\n",
1933e01adc04Sdlg 				    DEVNAME(sc), v);
1934e01adc04Sdlg 				goto free_vectors;
1935e01adc04Sdlg 			}
1936e01adc04Sdlg 
1937e01adc04Sdlg 			iv->iv_ihc = pci_intr_establish_cpu(sc->sc_pc, ih,
1938e01adc04Sdlg 			    IPL_NET | IPL_MPSAFE,
1939e01adc04Sdlg 			    intrmap_cpu(sc->sc_intrmap, i),
1940e01adc04Sdlg 			    ixl_intr_vector, iv, iv->iv_name);
1941e01adc04Sdlg 			if (iv->iv_ihc == NULL) {
1942e01adc04Sdlg 				printf("%s: unable to establish interrupt %d\n",
1943e01adc04Sdlg 				    DEVNAME(sc), v);
1944e01adc04Sdlg 				goto free_vectors;
1945e01adc04Sdlg 			}
1946e01adc04Sdlg 
1947e01adc04Sdlg 			ixl_wr(sc, I40E_PFINT_DYN_CTLN(i),
1948e01adc04Sdlg 			    I40E_PFINT_DYN_CTLN_INTENA_MASK |
1949e01adc04Sdlg 			    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
1950e01adc04Sdlg 			    (IXL_NOITR << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT));
1951e01adc04Sdlg 		}
1952e01adc04Sdlg 	}
1953e01adc04Sdlg 
1954f5777d33Sdlg 	/* fixup the chip ops for older fw releases */
1955f5777d33Sdlg 	if (sc->sc_chip == &ixl_710 &&
1956f5777d33Sdlg 	    sc->sc_api_major == 1 && sc->sc_api_minor < 5)
1957f5777d33Sdlg 		sc->sc_chip = &ixl_710_decrepit;
1958f5777d33Sdlg 
1959ccb96312Sdlg 	ifp->if_softc = sc;
1960ccb96312Sdlg 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1961ccb96312Sdlg 	ifp->if_xflags = IFXF_MPSAFE;
1962ccb96312Sdlg 	ifp->if_ioctl = ixl_ioctl;
1963ccb96312Sdlg 	ifp->if_qstart = ixl_start;
1964ccb96312Sdlg 	ifp->if_watchdog = ixl_watchdog;
1965ccb96312Sdlg 	ifp->if_hardmtu = IXL_HARDMTU;
1966ccb96312Sdlg 	strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
1967cf96265bSbluhm 	ifq_init_maxlen(&ifp->if_snd, sc->sc_tx_ring_ndescs);
1968ccb96312Sdlg 
1969983d220cSdlg 	ifp->if_capabilities = IFCAP_VLAN_HWTAGGING;
197004206048Sdlg 	ifp->if_capabilities |= IFCAP_CSUM_IPv4 |
197104206048Sdlg 	    IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4 |
197204206048Sdlg 	    IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6;
1973f77c9c95Sjan 	ifp->if_capabilities |= IFCAP_TSOv4 | IFCAP_TSOv6;
1974ccb96312Sdlg 
1975ccb96312Sdlg 	ifmedia_init(&sc->sc_media, 0, ixl_media_change, ixl_media_status);
1976ccb96312Sdlg 
1977ccb96312Sdlg 	ixl_media_add(sc, phy_types);
1978ccb96312Sdlg 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
1979ccb96312Sdlg 	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
1980ccb96312Sdlg 
1981ccb96312Sdlg 	if_attach(ifp);
1982ccb96312Sdlg 	ether_ifattach(ifp);
1983ccb96312Sdlg 
1984e01adc04Sdlg 	if_attach_queues(ifp, nqueues);
1985e01adc04Sdlg 	if_attach_iqueues(ifp, nqueues);
1986ccb96312Sdlg 
198710e66d97Sjmatthew 	task_set(&sc->sc_link_state_task, ixl_link_state_update, sc);
1988ccb96312Sdlg 	ixl_wr(sc, I40E_PFINT_ICR0_ENA,
1989ccb96312Sdlg 	    I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK |
1990ccb96312Sdlg 	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK);
1991ccb96312Sdlg 	ixl_wr(sc, I40E_PFINT_STAT_CTL0,
1992ccb96312Sdlg 	    IXL_NOITR << I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT);
1993ccb96312Sdlg 
19942bb8400cSjmatthew 	/* remove default mac filter and replace it so we can see vlans */
19952bb8400cSjmatthew 	ixl_remove_macvlan(sc, sc->sc_ac.ac_enaddr, 0, 0);
19962bb8400cSjmatthew 	ixl_remove_macvlan(sc, sc->sc_ac.ac_enaddr, 0,
19972bb8400cSjmatthew 	    IXL_AQ_OP_REMOVE_MACVLAN_IGNORE_VLAN);
19982bb8400cSjmatthew 	ixl_add_macvlan(sc, sc->sc_ac.ac_enaddr, 0,
19992bb8400cSjmatthew 	    IXL_AQ_OP_ADD_MACVLAN_IGNORE_VLAN);
200045e31cb9Sjmatthew 	ixl_add_macvlan(sc, etherbroadcastaddr, 0,
200145e31cb9Sjmatthew 	    IXL_AQ_OP_ADD_MACVLAN_IGNORE_VLAN);
200256319b45Sjmatthew 	memcpy(sc->sc_enaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
20032bb8400cSjmatthew 
2004ccb96312Sdlg 	ixl_intr_enable(sc);
2005ccb96312Sdlg 
20062ee1fcb3Sdlg #if NKSTAT > 0
20072ee1fcb3Sdlg 	ixl_kstat_attach(sc);
20082ee1fcb3Sdlg #endif
20092ee1fcb3Sdlg 
2010ccb96312Sdlg 	return;
2011e01adc04Sdlg free_vectors:
2012e01adc04Sdlg 	if (sc->sc_intrmap != NULL) {
2013e01adc04Sdlg 		for (i = 0; i < nqueues; i++) {
2014e01adc04Sdlg 			struct ixl_vector *iv = &sc->sc_vectors[i];
2015e01adc04Sdlg 			if (iv->iv_ihc == NULL)
2016e01adc04Sdlg 				continue;
2017e01adc04Sdlg 			pci_intr_disestablish(sc->sc_pc, iv->iv_ihc);
2018e01adc04Sdlg 		}
2019e01adc04Sdlg 	}
2020e01adc04Sdlg 	free(sc->sc_vectors, M_DEVBUF, nqueues * sizeof(*sc->sc_vectors));
20212bb8400cSjmatthew free_scratch:
20222bb8400cSjmatthew 	ixl_dmamem_free(sc, &sc->sc_scratch);
2023eb1b42e4Sdlg free_hmc:
2024eb1b42e4Sdlg 	ixl_hmc_free(sc);
2025ccb96312Sdlg shutdown:
2026ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->atq_head, 0);
2027ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->arq_head, 0);
2028ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->atq_tail, 0);
2029ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->arq_tail, 0);
2030ccb96312Sdlg 
2031ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->atq_bal, 0);
2032ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->atq_bah, 0);
2033ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->atq_len, 0);
2034ccb96312Sdlg 
2035ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->arq_bal, 0);
2036ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->arq_bah, 0);
2037ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->arq_len, 0);
2038ccb96312Sdlg 
2039ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_arq),
2040ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_arq),
2041ccb96312Sdlg 	    BUS_DMASYNC_POSTREAD);
2042ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_atq),
2043ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_atq),
2044ccb96312Sdlg 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
2045ccb96312Sdlg 
2046ccb96312Sdlg 	ixl_arq_unfill(sc);
20479b0c6e1eSjmatthew 
2048ccb96312Sdlg free_arq:
2049ccb96312Sdlg 	ixl_dmamem_free(sc, &sc->sc_arq);
2050ccb96312Sdlg free_atq:
2051ccb96312Sdlg 	ixl_dmamem_free(sc, &sc->sc_atq);
2052ccb96312Sdlg unmap:
2053ccb96312Sdlg 	bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems);
2054ccb96312Sdlg 	sc->sc_mems = 0;
2055e01adc04Sdlg 
2056e01adc04Sdlg 	if (sc->sc_intrmap != NULL)
2057e01adc04Sdlg 		intrmap_destroy(sc->sc_intrmap);
2058ccb96312Sdlg }
2059ccb96312Sdlg 
2060ccb96312Sdlg static void
ixl_media_add(struct ixl_softc * sc,uint64_t phy_types)2061ccb96312Sdlg ixl_media_add(struct ixl_softc *sc, uint64_t phy_types)
2062ccb96312Sdlg {
2063ccb96312Sdlg 	struct ifmedia *ifm = &sc->sc_media;
2064ccb96312Sdlg 	const struct ixl_phy_type *itype;
2065ccb96312Sdlg 	unsigned int i;
2066ccb96312Sdlg 
2067ccb96312Sdlg 	for (i = 0; i < nitems(ixl_phy_type_map); i++) {
2068ccb96312Sdlg 		itype = &ixl_phy_type_map[i];
2069ccb96312Sdlg 
2070ccb96312Sdlg 		if (ISSET(phy_types, itype->phy_type))
2071ccb96312Sdlg 			ifmedia_add(ifm, IFM_ETHER | itype->ifm_type, 0, NULL);
2072ccb96312Sdlg 	}
2073ccb96312Sdlg }
2074ccb96312Sdlg 
2075ccb96312Sdlg static int
ixl_media_change(struct ifnet * ifp)2076ccb96312Sdlg ixl_media_change(struct ifnet *ifp)
2077ccb96312Sdlg {
2078ccb96312Sdlg 	/* ignore? */
2079ccb96312Sdlg 	return (EOPNOTSUPP);
2080ccb96312Sdlg }
2081ccb96312Sdlg 
2082ccb96312Sdlg static void
ixl_media_status(struct ifnet * ifp,struct ifmediareq * ifm)2083ccb96312Sdlg ixl_media_status(struct ifnet *ifp, struct ifmediareq *ifm)
2084ccb96312Sdlg {
2085ccb96312Sdlg 	struct ixl_softc *sc = ifp->if_softc;
2086ccb96312Sdlg 
208791afdc87Sbluhm 	KERNEL_ASSERT_LOCKED();
2088ccb96312Sdlg 
2089fea9c2abSbluhm 	mtx_enter(&sc->sc_link_state_mtx);
2090ccb96312Sdlg 	ifm->ifm_status = sc->sc_media_status;
2091ccb96312Sdlg 	ifm->ifm_active = sc->sc_media_active;
2092fea9c2abSbluhm 	mtx_leave(&sc->sc_link_state_mtx);
2093ccb96312Sdlg }
2094ccb96312Sdlg 
2095ccb96312Sdlg static void
ixl_watchdog(struct ifnet * ifp)2096ccb96312Sdlg ixl_watchdog(struct ifnet *ifp)
2097ccb96312Sdlg {
2098ccb96312Sdlg 
2099ccb96312Sdlg }
2100ccb96312Sdlg 
2101ccb96312Sdlg int
ixl_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)2102ccb96312Sdlg ixl_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
2103ccb96312Sdlg {
2104ccb96312Sdlg 	struct ixl_softc *sc = (struct ixl_softc *)ifp->if_softc;
2105ccb96312Sdlg 	struct ifreq *ifr = (struct ifreq *)data;
2106300096a1Sjmatthew 	uint8_t addrhi[ETHER_ADDR_LEN], addrlo[ETHER_ADDR_LEN];
2107300096a1Sjmatthew 	int aqerror, error = 0;
2108ccb96312Sdlg 
2109ccb96312Sdlg 	switch (cmd) {
2110ccb96312Sdlg 	case SIOCSIFADDR:
2111ccb96312Sdlg 		ifp->if_flags |= IFF_UP;
2112ccb96312Sdlg 		/* FALLTHROUGH */
2113ccb96312Sdlg 
2114ccb96312Sdlg 	case SIOCSIFFLAGS:
2115ccb96312Sdlg 		if (ISSET(ifp->if_flags, IFF_UP)) {
2116ccb96312Sdlg 			if (ISSET(ifp->if_flags, IFF_RUNNING))
2117ccb96312Sdlg 				error = ENETRESET;
2118ccb96312Sdlg 			else
2119ccb96312Sdlg 				error = ixl_up(sc);
2120ccb96312Sdlg 		} else {
2121ccb96312Sdlg 			if (ISSET(ifp->if_flags, IFF_RUNNING))
2122ccb96312Sdlg 				error = ixl_down(sc);
2123ccb96312Sdlg 		}
2124ccb96312Sdlg 		break;
2125ccb96312Sdlg 
2126ccb96312Sdlg 	case SIOCGIFMEDIA:
2127ccb96312Sdlg 	case SIOCSIFMEDIA:
2128ccb96312Sdlg 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
2129ccb96312Sdlg 		break;
2130ccb96312Sdlg 
2131ccb96312Sdlg 	case SIOCGIFRXR:
2132ccb96312Sdlg 		error = ixl_rxrinfo(sc, (struct if_rxrinfo *)ifr->ifr_data);
2133ccb96312Sdlg 		break;
2134ccb96312Sdlg 
2135300096a1Sjmatthew 	case SIOCADDMULTI:
2136300096a1Sjmatthew 		if (ether_addmulti(ifr, &sc->sc_ac) == ENETRESET) {
2137300096a1Sjmatthew 			error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
2138300096a1Sjmatthew 			if (error != 0)
2139300096a1Sjmatthew 				return (error);
2140300096a1Sjmatthew 
2141300096a1Sjmatthew 			aqerror = ixl_add_macvlan(sc, addrlo, 0,
2142300096a1Sjmatthew 			    IXL_AQ_OP_ADD_MACVLAN_IGNORE_VLAN);
2143300096a1Sjmatthew 			if (aqerror == IXL_AQ_RC_ENOSPC) {
2144300096a1Sjmatthew 				ether_delmulti(ifr, &sc->sc_ac);
2145300096a1Sjmatthew 				error = ENOSPC;
2146300096a1Sjmatthew 			}
2147300096a1Sjmatthew 
2148300096a1Sjmatthew 			if (sc->sc_ac.ac_multirangecnt > 0) {
2149300096a1Sjmatthew 				SET(ifp->if_flags, IFF_ALLMULTI);
2150300096a1Sjmatthew 				error = ENETRESET;
2151300096a1Sjmatthew 			}
2152300096a1Sjmatthew 		}
2153300096a1Sjmatthew 		break;
2154300096a1Sjmatthew 
2155300096a1Sjmatthew 	case SIOCDELMULTI:
2156300096a1Sjmatthew 		if (ether_delmulti(ifr, &sc->sc_ac) == ENETRESET) {
2157300096a1Sjmatthew 			error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
2158300096a1Sjmatthew 			if (error != 0)
2159300096a1Sjmatthew 				return (error);
2160300096a1Sjmatthew 
2161300096a1Sjmatthew 			ixl_remove_macvlan(sc, addrlo, 0,
2162300096a1Sjmatthew 			    IXL_AQ_OP_REMOVE_MACVLAN_IGNORE_VLAN);
2163300096a1Sjmatthew 
2164300096a1Sjmatthew 			if (ISSET(ifp->if_flags, IFF_ALLMULTI) &&
2165300096a1Sjmatthew 			    sc->sc_ac.ac_multirangecnt == 0) {
2166300096a1Sjmatthew 				CLR(ifp->if_flags, IFF_ALLMULTI);
2167300096a1Sjmatthew 				error = ENETRESET;
2168300096a1Sjmatthew 			}
2169300096a1Sjmatthew 		}
2170300096a1Sjmatthew 		break;
2171300096a1Sjmatthew 
21724eec9beaSdlg 	case SIOCGIFSFFPAGE:
21734eec9beaSdlg 		error = rw_enter(&ixl_sff_lock, RW_WRITE|RW_INTR);
21744eec9beaSdlg 		if (error != 0)
21754eec9beaSdlg 			break;
21764eec9beaSdlg 
21774eec9beaSdlg 		error = ixl_get_sffpage(sc, (struct if_sffpage *)data);
21784eec9beaSdlg 		rw_exit(&ixl_sff_lock);
21794eec9beaSdlg 		break;
21804eec9beaSdlg 
2181ccb96312Sdlg 	default:
2182ccb96312Sdlg 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
2183ccb96312Sdlg 		break;
2184ccb96312Sdlg 	}
2185ccb96312Sdlg 
2186ccb96312Sdlg 	if (error == ENETRESET)
2187ccb96312Sdlg 		error = ixl_iff(sc);
2188ccb96312Sdlg 
2189ccb96312Sdlg 	return (error);
2190ccb96312Sdlg }
2191ccb96312Sdlg 
2192ccb96312Sdlg static inline void *
ixl_hmc_kva(struct ixl_softc * sc,unsigned int type,unsigned int i)2193ccb96312Sdlg ixl_hmc_kva(struct ixl_softc *sc, unsigned int type, unsigned int i)
2194ccb96312Sdlg {
2195eb1b42e4Sdlg 	uint8_t *kva = IXL_DMA_KVA(&sc->sc_hmc_pd);
2196ccb96312Sdlg 	struct ixl_hmc_entry *e = &sc->sc_hmc_entries[type];
2197ccb96312Sdlg 
2198ccb96312Sdlg 	if (i >= e->hmc_count)
2199ccb96312Sdlg 		return (NULL);
2200ccb96312Sdlg 
2201ccb96312Sdlg 	kva += e->hmc_base;
2202ccb96312Sdlg 	kva += i * e->hmc_size;
2203ccb96312Sdlg 
2204ccb96312Sdlg 	return (kva);
2205ccb96312Sdlg }
2206ccb96312Sdlg 
2207ccb96312Sdlg static inline size_t
ixl_hmc_len(struct ixl_softc * sc,unsigned int type)2208ccb96312Sdlg ixl_hmc_len(struct ixl_softc *sc, unsigned int type)
2209ccb96312Sdlg {
2210ccb96312Sdlg 	struct ixl_hmc_entry *e = &sc->sc_hmc_entries[type];
2211ccb96312Sdlg 
2212ccb96312Sdlg 	return (e->hmc_size);
2213ccb96312Sdlg }
2214ccb96312Sdlg 
2215ccb96312Sdlg static int
ixl_configure_rss(struct ixl_softc * sc)2216819ac441Sdlg ixl_configure_rss(struct ixl_softc *sc)
2217819ac441Sdlg {
2218819ac441Sdlg 	struct ixl_rss_key rsskey;
2219819ac441Sdlg 	struct ixl_rss_lut_128 lut;
2220819ac441Sdlg 	uint8_t *lute = (uint8_t *)&lut;
2221819ac441Sdlg 	uint64_t rss_hena;
2222819ac441Sdlg 	unsigned int i, nqueues;
2223819ac441Sdlg 	int error;
2224819ac441Sdlg 
2225819ac441Sdlg #if 0
2226819ac441Sdlg 	/* if we want to do a 512 entry LUT, do this. */
2227819ac441Sdlg 	uint32_t v = ixl_rd_ctl(sc, I40E_PFQF_CTL_0);
2228819ac441Sdlg 	SET(v, I40E_PFQF_CTL_0_HASHLUTSIZE_MASK);
2229819ac441Sdlg 	ixl_wr_ctl(sc, I40E_PFQF_CTL_0, v);
2230819ac441Sdlg #endif
2231819ac441Sdlg 
2232819ac441Sdlg 	stoeplitz_to_key(&rsskey, sizeof(rsskey));
2233819ac441Sdlg 
2234819ac441Sdlg 	nqueues = ixl_nqueues(sc);
2235819ac441Sdlg 	for (i = 0; i < sizeof(lut); i++) {
2236819ac441Sdlg 		/*
2237819ac441Sdlg 		 * ixl must have a power of 2 rings, so using mod
2238819ac441Sdlg 		 * to populate the table is fine.
2239819ac441Sdlg 		 */
2240819ac441Sdlg 		lute[i] = i % nqueues;
2241819ac441Sdlg 	}
2242819ac441Sdlg 
2243819ac441Sdlg 	error = ixl_set_rss_key(sc, &rsskey);
2244819ac441Sdlg 	if (error != 0)
2245819ac441Sdlg 		return (error);
2246819ac441Sdlg 
2247819ac441Sdlg 	rss_hena = (uint64_t)ixl_rd_ctl(sc, I40E_PFQF_HENA(0));
2248819ac441Sdlg 	rss_hena |= (uint64_t)ixl_rd_ctl(sc, I40E_PFQF_HENA(1)) << 32;
2249819ac441Sdlg 	rss_hena |= ixl_rss_hena(sc);
2250819ac441Sdlg 	ixl_wr_ctl(sc, I40E_PFQF_HENA(0), rss_hena);
2251819ac441Sdlg 	ixl_wr_ctl(sc, I40E_PFQF_HENA(1), rss_hena >> 32);
2252819ac441Sdlg 
2253819ac441Sdlg 	error = ixl_set_rss_lut(sc, &lut);
2254819ac441Sdlg 	if (error != 0)
2255819ac441Sdlg 		return (error);
2256819ac441Sdlg 
2257819ac441Sdlg 	/* nothing to clena up :( */
2258819ac441Sdlg 
2259819ac441Sdlg 	return (0);
2260819ac441Sdlg }
2261819ac441Sdlg 
2262819ac441Sdlg static int
ixl_up(struct ixl_softc * sc)2263ccb96312Sdlg ixl_up(struct ixl_softc *sc)
2264ccb96312Sdlg {
2265ccb96312Sdlg 	struct ifnet *ifp = &sc->sc_ac.ac_if;
2266e01adc04Sdlg 	struct ifqueue *ifq;
2267e01adc04Sdlg 	struct ifiqueue *ifiq;
2268e01adc04Sdlg 	struct ixl_vector *iv;
2269eb1b42e4Sdlg 	struct ixl_rx_ring *rxr;
2270eb1b42e4Sdlg 	struct ixl_tx_ring *txr;
2271eb1b42e4Sdlg 	unsigned int nqueues, i;
2272eb1b42e4Sdlg 	uint32_t reg;
2273eb1b42e4Sdlg 	int rv = ENOMEM;
2274ccb96312Sdlg 
2275eb1b42e4Sdlg 	nqueues = ixl_nqueues(sc);
2276eb1b42e4Sdlg 
2277d3ac7020Sdlg 	rw_enter_write(&sc->sc_cfg_lock);
2278d3ac7020Sdlg 	if (sc->sc_dead) {
2279d3ac7020Sdlg 		rw_exit_write(&sc->sc_cfg_lock);
2280d3ac7020Sdlg 		return (ENXIO);
2281d3ac7020Sdlg 	}
2282d3ac7020Sdlg 
2283eb1b42e4Sdlg 	/* allocation is the only thing that can fail, so do it up front */
2284eb1b42e4Sdlg 	for (i = 0; i < nqueues; i++) {
2285eb1b42e4Sdlg 		rxr = ixl_rxr_alloc(sc, i);
2286eb1b42e4Sdlg 		if (rxr == NULL)
2287eb1b42e4Sdlg 			goto free;
2288eb1b42e4Sdlg 
228900cd24f1Sdlg 		txr = ixl_txr_alloc(sc, i);
2290eb1b42e4Sdlg 		if (txr == NULL) {
2291eb1b42e4Sdlg 			ixl_rxr_free(sc, rxr);
2292eb1b42e4Sdlg 			goto free;
2293ccb96312Sdlg 		}
2294ccb96312Sdlg 
2295e01adc04Sdlg 		/* wire everything together */
2296e01adc04Sdlg 		iv = &sc->sc_vectors[i];
2297e01adc04Sdlg 		iv->iv_rxr = rxr;
2298e01adc04Sdlg 		iv->iv_txr = txr;
2299e01adc04Sdlg 
2300e01adc04Sdlg 		ifq = ifp->if_ifqs[i];
2301e01adc04Sdlg 		ifq->ifq_softc = txr;
2302e01adc04Sdlg 		txr->txr_ifq = ifq;
2303e01adc04Sdlg 
2304e01adc04Sdlg 		ifiq = ifp->if_iqs[i];
2305e01adc04Sdlg 		ifiq->ifiq_softc = rxr;
2306e01adc04Sdlg 		rxr->rxr_ifiq = ifiq;
2307ccb96312Sdlg 	}
2308ccb96312Sdlg 
2309eb1b42e4Sdlg 	/* XXX wait 50ms from completion of last RX queue disable */
2310ccb96312Sdlg 
2311eb1b42e4Sdlg 	for (i = 0; i < nqueues; i++) {
2312e01adc04Sdlg 		iv = &sc->sc_vectors[i];
2313e01adc04Sdlg 		rxr = iv->iv_rxr;
2314e01adc04Sdlg 		txr = iv->iv_txr;
2315eb1b42e4Sdlg 
2316eb1b42e4Sdlg 		ixl_txr_qdis(sc, txr, 1);
2317eb1b42e4Sdlg 
2318eb1b42e4Sdlg 		ixl_rxr_config(sc, rxr);
2319eb1b42e4Sdlg 		ixl_txr_config(sc, txr);
2320eb1b42e4Sdlg 
2321eb1b42e4Sdlg 		ixl_wr(sc, I40E_QTX_CTL(i), I40E_QTX_CTL_PF_QUEUE |
2322ccb96312Sdlg 		    (sc->sc_pf_id << I40E_QTX_CTL_PF_INDX_SHIFT));
2323ccb96312Sdlg 
2324eb1b42e4Sdlg 		ixl_wr(sc, rxr->rxr_tail, 0);
2325203b1b65Sdlg 		ixl_rxfill(sc, rxr);
2326eb1b42e4Sdlg 
2327eb1b42e4Sdlg 		reg = ixl_rd(sc, I40E_QRX_ENA(i));
2328eb1b42e4Sdlg 		SET(reg, I40E_QRX_ENA_QENA_REQ_MASK);
2329eb1b42e4Sdlg 		ixl_wr(sc, I40E_QRX_ENA(i), reg);
2330eb1b42e4Sdlg 
2331eb1b42e4Sdlg 		reg = ixl_rd(sc, I40E_QTX_ENA(i));
2332eb1b42e4Sdlg 		SET(reg, I40E_QTX_ENA_QENA_REQ_MASK);
2333eb1b42e4Sdlg 		ixl_wr(sc, I40E_QTX_ENA(i), reg);
2334eb1b42e4Sdlg 	}
2335eb1b42e4Sdlg 
2336eb1b42e4Sdlg 	for (i = 0; i < nqueues; i++) {
2337e01adc04Sdlg 		iv = &sc->sc_vectors[i];
2338e01adc04Sdlg 		rxr = iv->iv_rxr;
2339e01adc04Sdlg 		txr = iv->iv_txr;
2340eb1b42e4Sdlg 
2341eb1b42e4Sdlg 		if (ixl_rxr_enabled(sc, rxr) != 0)
2342eb1b42e4Sdlg 			goto down;
2343eb1b42e4Sdlg 
2344eb1b42e4Sdlg 		if (ixl_txr_enabled(sc, txr) != 0)
2345eb1b42e4Sdlg 			goto down;
2346eb1b42e4Sdlg 	}
2347ccb96312Sdlg 
2348819ac441Sdlg 	ixl_configure_rss(sc);
2349819ac441Sdlg 
2350ccb96312Sdlg 	SET(ifp->if_flags, IFF_RUNNING);
2351ccb96312Sdlg 
2352e01adc04Sdlg 	if (sc->sc_intrmap == NULL) {
2353eb1b42e4Sdlg 		ixl_wr(sc, I40E_PFINT_LNKLST0,
23549b0c6e1eSjmatthew 		    (I40E_INTR_NOTX_QUEUE <<
23559b0c6e1eSjmatthew 		     I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
23569b0c6e1eSjmatthew 		    (I40E_QUEUE_TYPE_RX <<
23579b0c6e1eSjmatthew 		     I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
2358eb1b42e4Sdlg 
2359eb1b42e4Sdlg 		ixl_wr(sc, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE),
2360eb1b42e4Sdlg 		    (I40E_INTR_NOTX_INTR << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
2361eb1b42e4Sdlg 		    (I40E_ITR_INDEX_RX << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
23629b0c6e1eSjmatthew 		    (I40E_INTR_NOTX_RX_QUEUE <<
23639b0c6e1eSjmatthew 		     I40E_QINT_RQCTL_MSIX0_INDX_SHIFT) |
2364eb1b42e4Sdlg 		    (I40E_INTR_NOTX_QUEUE << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
2365646632e9Sjmatthew 		    (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
2366646632e9Sjmatthew 		    I40E_QINT_RQCTL_CAUSE_ENA_MASK);
2367eb1b42e4Sdlg 
2368eb1b42e4Sdlg 		ixl_wr(sc, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE),
2369eb1b42e4Sdlg 		    (I40E_INTR_NOTX_INTR << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
2370eb1b42e4Sdlg 		    (I40E_ITR_INDEX_TX << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
23719b0c6e1eSjmatthew 		    (I40E_INTR_NOTX_TX_QUEUE <<
23729b0c6e1eSjmatthew 		     I40E_QINT_TQCTL_MSIX0_INDX_SHIFT) |
2373eb1b42e4Sdlg 		    (I40E_QUEUE_TYPE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
2374646632e9Sjmatthew 		    (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT) |
2375646632e9Sjmatthew 		    I40E_QINT_TQCTL_CAUSE_ENA_MASK);
23769b0c6e1eSjmatthew 	} else {
23779b0c6e1eSjmatthew 		/* vector 0 has no queues */
23789b0c6e1eSjmatthew 		ixl_wr(sc, I40E_PFINT_LNKLST0,
23799b0c6e1eSjmatthew 		    I40E_QUEUE_TYPE_EOL <<
23809b0c6e1eSjmatthew 		    I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT);
23819b0c6e1eSjmatthew 
23829b0c6e1eSjmatthew 		/* queue n is mapped to vector n+1 */
2383e01adc04Sdlg 		for (i = 0; i < nqueues; i++) {
23849b0c6e1eSjmatthew 			/* LNKLSTN(i) configures vector i+1 */
23859b0c6e1eSjmatthew 			ixl_wr(sc, I40E_PFINT_LNKLSTN(i),
23869b0c6e1eSjmatthew 			    (i << I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
23879b0c6e1eSjmatthew 			    (I40E_QUEUE_TYPE_RX <<
23889b0c6e1eSjmatthew 			     I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
23899b0c6e1eSjmatthew 			ixl_wr(sc, I40E_QINT_RQCTL(i),
23909b0c6e1eSjmatthew 			    ((i+1) << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
23919b0c6e1eSjmatthew 			    (I40E_ITR_INDEX_RX <<
23929b0c6e1eSjmatthew 			     I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
23939b0c6e1eSjmatthew 			    (i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
23949b0c6e1eSjmatthew 			    (I40E_QUEUE_TYPE_TX <<
23959b0c6e1eSjmatthew 			     I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
23969b0c6e1eSjmatthew 			    I40E_QINT_RQCTL_CAUSE_ENA_MASK);
23979b0c6e1eSjmatthew 			ixl_wr(sc, I40E_QINT_TQCTL(i),
23989b0c6e1eSjmatthew 			    ((i+1) << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
23999b0c6e1eSjmatthew 			    (I40E_ITR_INDEX_TX <<
24009b0c6e1eSjmatthew 			     I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
24019b0c6e1eSjmatthew 			    (I40E_QUEUE_TYPE_EOL <<
24029b0c6e1eSjmatthew 			     I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
24039b0c6e1eSjmatthew 			    (I40E_QUEUE_TYPE_RX <<
24049b0c6e1eSjmatthew 			     I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT) |
24059b0c6e1eSjmatthew 			    I40E_QINT_TQCTL_CAUSE_ENA_MASK);
24069b0c6e1eSjmatthew 
24079b0c6e1eSjmatthew 			ixl_wr(sc, I40E_PFINT_ITRN(0, i), 0x7a);
24089b0c6e1eSjmatthew 			ixl_wr(sc, I40E_PFINT_ITRN(1, i), 0x7a);
24099b0c6e1eSjmatthew 			ixl_wr(sc, I40E_PFINT_ITRN(2, i), 0);
24109b0c6e1eSjmatthew 		}
24119b0c6e1eSjmatthew 	}
2412eb1b42e4Sdlg 
2413eb1b42e4Sdlg 	ixl_wr(sc, I40E_PFINT_ITR0(0), 0x7a);
2414eb1b42e4Sdlg 	ixl_wr(sc, I40E_PFINT_ITR0(1), 0x7a);
2415eb1b42e4Sdlg 	ixl_wr(sc, I40E_PFINT_ITR0(2), 0);
2416eb1b42e4Sdlg 
2417d3ac7020Sdlg 	rw_exit_write(&sc->sc_cfg_lock);
2418d3ac7020Sdlg 
2419eb1b42e4Sdlg 	return (ENETRESET);
2420eb1b42e4Sdlg 
2421eb1b42e4Sdlg free:
2422eb1b42e4Sdlg 	for (i = 0; i < nqueues; i++) {
2423e01adc04Sdlg 		iv = &sc->sc_vectors[i];
2424e01adc04Sdlg 		rxr = iv->iv_rxr;
2425e01adc04Sdlg 		txr = iv->iv_txr;
2426eb1b42e4Sdlg 
2427eb1b42e4Sdlg 		if (rxr == NULL) {
2428eb1b42e4Sdlg 			/*
2429eb1b42e4Sdlg 			 * tx and rx get set at the same time, so if one
2430eb1b42e4Sdlg 			 * is NULL, the other is too.
2431eb1b42e4Sdlg 			 */
2432eb1b42e4Sdlg 			continue;
2433eb1b42e4Sdlg 		}
2434eb1b42e4Sdlg 
2435eb1b42e4Sdlg 		ixl_txr_free(sc, txr);
2436eb1b42e4Sdlg 		ixl_rxr_free(sc, rxr);
2437eb1b42e4Sdlg 	}
2438d3ac7020Sdlg 	rw_exit_write(&sc->sc_cfg_lock);
2439ccb96312Sdlg 	return (rv);
2440eb1b42e4Sdlg down:
2441d3ac7020Sdlg 	rw_exit_write(&sc->sc_cfg_lock);
2442eb1b42e4Sdlg 	ixl_down(sc);
2443eb1b42e4Sdlg 	return (ETIMEDOUT);
2444ccb96312Sdlg }
2445ccb96312Sdlg 
2446ccb96312Sdlg static int
ixl_iff(struct ixl_softc * sc)2447ccb96312Sdlg ixl_iff(struct ixl_softc *sc)
2448ccb96312Sdlg {
2449ccb96312Sdlg 	struct ifnet *ifp = &sc->sc_ac.ac_if;
2450ccb96312Sdlg 	struct ixl_atq iatq;
2451ccb96312Sdlg 	struct ixl_aq_desc *iaq;
2452ccb96312Sdlg 	struct ixl_aq_vsi_promisc_param *param;
2453ccb96312Sdlg 
2454ccb96312Sdlg 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
2455ccb96312Sdlg 		return (0);
2456ccb96312Sdlg 
2457ccb96312Sdlg 	memset(&iatq, 0, sizeof(iatq));
2458ccb96312Sdlg 
2459ccb96312Sdlg 	iaq = &iatq.iatq_desc;
2460ccb96312Sdlg 	iaq->iaq_opcode = htole16(IXL_AQ_OP_SET_VSI_PROMISC);
2461ccb96312Sdlg 
2462ccb96312Sdlg 	param = (struct ixl_aq_vsi_promisc_param *)&iaq->iaq_param;
2463b4a9eb13Sdlg 	param->flags = htole16(IXL_AQ_VSI_PROMISC_FLAG_BCAST |
2464b4a9eb13Sdlg 	    IXL_AQ_VSI_PROMISC_FLAG_VLAN);
24652bb8400cSjmatthew 	if (ISSET(ifp->if_flags, IFF_PROMISC)) {
2466ccb96312Sdlg 		param->flags |= htole16(IXL_AQ_VSI_PROMISC_FLAG_UCAST |
2467ccb96312Sdlg 		    IXL_AQ_VSI_PROMISC_FLAG_MCAST);
2468300096a1Sjmatthew 	} else if (ISSET(ifp->if_flags, IFF_ALLMULTI)) {
2469300096a1Sjmatthew 		param->flags |= htole16(IXL_AQ_VSI_PROMISC_FLAG_MCAST);
24702bb8400cSjmatthew 	}
2471ccb96312Sdlg 	param->valid_flags = htole16(IXL_AQ_VSI_PROMISC_FLAG_UCAST |
2472b4a9eb13Sdlg 	    IXL_AQ_VSI_PROMISC_FLAG_MCAST | IXL_AQ_VSI_PROMISC_FLAG_BCAST |
2473b4a9eb13Sdlg 	    IXL_AQ_VSI_PROMISC_FLAG_VLAN);
2474ccb96312Sdlg 	param->seid = sc->sc_seid;
2475ccb96312Sdlg 
2476ccb96312Sdlg 	ixl_atq_exec(sc, &iatq, "ixliff");
2477ccb96312Sdlg 
2478ccb96312Sdlg 	if (iaq->iaq_retval != htole16(IXL_AQ_RC_OK))
2479ccb96312Sdlg 		return (EIO);
2480ccb96312Sdlg 
248156319b45Sjmatthew 	if (memcmp(sc->sc_enaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN) != 0) {
248256319b45Sjmatthew 		ixl_remove_macvlan(sc, sc->sc_enaddr, 0,
248356319b45Sjmatthew 		    IXL_AQ_OP_REMOVE_MACVLAN_IGNORE_VLAN);
248456319b45Sjmatthew 		ixl_add_macvlan(sc, sc->sc_ac.ac_enaddr, 0,
248556319b45Sjmatthew 		    IXL_AQ_OP_ADD_MACVLAN_IGNORE_VLAN);
248656319b45Sjmatthew 		memcpy(sc->sc_enaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
248756319b45Sjmatthew 	}
2488ccb96312Sdlg 	return (0);
2489ccb96312Sdlg }
2490ccb96312Sdlg 
2491ccb96312Sdlg static int
ixl_down(struct ixl_softc * sc)2492ccb96312Sdlg ixl_down(struct ixl_softc *sc)
2493ccb96312Sdlg {
2494eb1b42e4Sdlg 	struct ifnet *ifp = &sc->sc_ac.ac_if;
2495e01adc04Sdlg 	struct ixl_vector *iv;
2496eb1b42e4Sdlg 	struct ixl_rx_ring *rxr;
2497eb1b42e4Sdlg 	struct ixl_tx_ring *txr;
2498eb1b42e4Sdlg 	unsigned int nqueues, i;
2499eb1b42e4Sdlg 	uint32_t reg;
2500eb1b42e4Sdlg 	int error = 0;
2501ccb96312Sdlg 
2502eb1b42e4Sdlg 	nqueues = ixl_nqueues(sc);
2503ccb96312Sdlg 
2504d3ac7020Sdlg 	rw_enter_write(&sc->sc_cfg_lock);
2505d3ac7020Sdlg 
2506eb1b42e4Sdlg 	CLR(ifp->if_flags, IFF_RUNNING);
2507ccb96312Sdlg 
2508d3ac7020Sdlg 	NET_UNLOCK();
2509d3ac7020Sdlg 
2510eb1b42e4Sdlg 	/* mask interrupts */
2511eb1b42e4Sdlg 	reg = ixl_rd(sc, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE));
2512eb1b42e4Sdlg 	CLR(reg, I40E_QINT_RQCTL_CAUSE_ENA_MASK);
2513eb1b42e4Sdlg 	ixl_wr(sc, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE), reg);
2514eb1b42e4Sdlg 
2515eb1b42e4Sdlg 	reg = ixl_rd(sc, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE));
2516eb1b42e4Sdlg 	CLR(reg, I40E_QINT_TQCTL_CAUSE_ENA_MASK);
2517eb1b42e4Sdlg 	ixl_wr(sc, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE), reg);
2518eb1b42e4Sdlg 
2519eb1b42e4Sdlg 	ixl_wr(sc, I40E_PFINT_LNKLST0, I40E_QUEUE_TYPE_EOL);
2520eb1b42e4Sdlg 
2521eb1b42e4Sdlg 	/* make sure the no hw generated work is still in flight */
2522eb1b42e4Sdlg 	intr_barrier(sc->sc_ihc);
2523e01adc04Sdlg 	if (sc->sc_intrmap != NULL) {
2524eb1b42e4Sdlg 		for (i = 0; i < nqueues; i++) {
2525e01adc04Sdlg 			iv = &sc->sc_vectors[i];
2526e01adc04Sdlg 			rxr = iv->iv_rxr;
2527e01adc04Sdlg 			txr = iv->iv_txr;
2528eb1b42e4Sdlg 
2529eb1b42e4Sdlg 			ixl_txr_qdis(sc, txr, 0);
2530eb1b42e4Sdlg 
2531e01adc04Sdlg 			ifq_barrier(txr->txr_ifq);
2532203b1b65Sdlg 
2533c87f73ddSvisa 			timeout_del_barrier(&rxr->rxr_refill);
25349b0c6e1eSjmatthew 
2535e01adc04Sdlg 			intr_barrier(iv->iv_ihc);
2536e01adc04Sdlg 		}
2537eb1b42e4Sdlg 	}
2538eb1b42e4Sdlg 
2539eb1b42e4Sdlg 	/* XXX wait at least 400 usec for all tx queues in one go */
2540eb1b42e4Sdlg 	delay(500);
2541eb1b42e4Sdlg 
2542eb1b42e4Sdlg 	for (i = 0; i < nqueues; i++) {
2543eb1b42e4Sdlg 		reg = ixl_rd(sc, I40E_QTX_ENA(i));
2544eb1b42e4Sdlg 		CLR(reg, I40E_QTX_ENA_QENA_REQ_MASK);
2545eb1b42e4Sdlg 		ixl_wr(sc, I40E_QTX_ENA(i), reg);
2546eb1b42e4Sdlg 
2547eb1b42e4Sdlg 		reg = ixl_rd(sc, I40E_QRX_ENA(i));
2548eb1b42e4Sdlg 		CLR(reg, I40E_QRX_ENA_QENA_REQ_MASK);
2549eb1b42e4Sdlg 		ixl_wr(sc, I40E_QRX_ENA(i), reg);
2550eb1b42e4Sdlg 	}
2551eb1b42e4Sdlg 
2552eb1b42e4Sdlg 	for (i = 0; i < nqueues; i++) {
2553e01adc04Sdlg 		iv = &sc->sc_vectors[i];
2554e01adc04Sdlg 		rxr = iv->iv_rxr;
2555e01adc04Sdlg 		txr = iv->iv_txr;
2556eb1b42e4Sdlg 
2557eb1b42e4Sdlg 		if (ixl_txr_disabled(sc, txr) != 0)
2558d3ac7020Sdlg 			goto die;
2559eb1b42e4Sdlg 
2560eb1b42e4Sdlg 		if (ixl_rxr_disabled(sc, rxr) != 0)
2561d3ac7020Sdlg 			goto die;
2562eb1b42e4Sdlg 	}
2563eb1b42e4Sdlg 
2564eb1b42e4Sdlg 	for (i = 0; i < nqueues; i++) {
2565e01adc04Sdlg 		iv = &sc->sc_vectors[i];
2566e01adc04Sdlg 		rxr = iv->iv_rxr;
2567e01adc04Sdlg 		txr = iv->iv_txr;
2568eb1b42e4Sdlg 
2569eb1b42e4Sdlg 		ixl_txr_unconfig(sc, txr);
2570eb1b42e4Sdlg 		ixl_rxr_unconfig(sc, rxr);
2571eb1b42e4Sdlg 
2572eb1b42e4Sdlg 		ixl_txr_clean(sc, txr);
2573eb1b42e4Sdlg 		ixl_rxr_clean(sc, rxr);
2574eb1b42e4Sdlg 
2575eb1b42e4Sdlg 		ixl_txr_free(sc, txr);
2576eb1b42e4Sdlg 		ixl_rxr_free(sc, rxr);
2577ccb96312Sdlg 
257800cd24f1Sdlg 		ifp->if_iqs[i]->ifiq_softc = NULL;
2579eb1b42e4Sdlg 		ifp->if_ifqs[i]->ifq_softc =  NULL;
2580eb1b42e4Sdlg 	}
2581ccb96312Sdlg 
2582d3ac7020Sdlg out:
2583d3ac7020Sdlg 	rw_exit_write(&sc->sc_cfg_lock);
2584d3ac7020Sdlg 	NET_LOCK();
2585d3ac7020Sdlg 	return (error);
2586d3ac7020Sdlg die:
2587d3ac7020Sdlg 	sc->sc_dead = 1;
2588d3ac7020Sdlg 	log(LOG_CRIT, "%s: failed to shut down rings", DEVNAME(sc));
2589d3ac7020Sdlg 	error = ETIMEDOUT;
2590d3ac7020Sdlg 	goto out;
2591ccb96312Sdlg }
2592ccb96312Sdlg 
2593ccb96312Sdlg static struct ixl_tx_ring *
ixl_txr_alloc(struct ixl_softc * sc,unsigned int qid)2594ccb96312Sdlg ixl_txr_alloc(struct ixl_softc *sc, unsigned int qid)
2595ccb96312Sdlg {
2596ccb96312Sdlg 	struct ixl_tx_ring *txr;
2597ccb96312Sdlg 	struct ixl_tx_map *maps, *txm;
2598ccb96312Sdlg 	unsigned int i;
2599ccb96312Sdlg 
2600ccb96312Sdlg 	txr = malloc(sizeof(*txr), M_DEVBUF, M_WAITOK|M_CANFAIL);
2601ccb96312Sdlg 	if (txr == NULL)
2602ccb96312Sdlg 		return (NULL);
2603ccb96312Sdlg 
2604ccb96312Sdlg 	maps = mallocarray(sizeof(*maps),
2605ccb96312Sdlg 	    sc->sc_tx_ring_ndescs, M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO);
2606ccb96312Sdlg 	if (maps == NULL)
2607ccb96312Sdlg 		goto free;
2608ccb96312Sdlg 
2609ccb96312Sdlg 	if (ixl_dmamem_alloc(sc, &txr->txr_mem,
2610ccb96312Sdlg 	    sizeof(struct ixl_tx_desc) * sc->sc_tx_ring_ndescs,
2611ccb96312Sdlg 	    IXL_TX_QUEUE_ALIGN) != 0)
2612ccb96312Sdlg 		goto freemap;
2613ccb96312Sdlg 
2614ccb96312Sdlg 	for (i = 0; i < sc->sc_tx_ring_ndescs; i++) {
2615ccb96312Sdlg 		txm = &maps[i];
2616ccb96312Sdlg 
2617ccb96312Sdlg 		if (bus_dmamap_create(sc->sc_dmat,
2618f77c9c95Sjan 		    MAXMCLBYTES, IXL_TX_PKT_DESCS, IXL_MAX_DMA_SEG_SIZE, 0,
2619ccb96312Sdlg 		    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
2620ccb96312Sdlg 		    &txm->txm_map) != 0)
2621ccb96312Sdlg 			goto uncreate;
2622ccb96312Sdlg 
2623ccb96312Sdlg 		txm->txm_eop = -1;
2624ccb96312Sdlg 		txm->txm_m = NULL;
2625ccb96312Sdlg 	}
2626ccb96312Sdlg 
2627ccb96312Sdlg 	txr->txr_cons = txr->txr_prod = 0;
2628ccb96312Sdlg 	txr->txr_maps = maps;
2629eb1b42e4Sdlg 
2630ccb96312Sdlg 	txr->txr_tail = I40E_QTX_TAIL(qid);
2631ccb96312Sdlg 	txr->txr_qid = qid;
2632ccb96312Sdlg 
2633ccb96312Sdlg 	return (txr);
2634ccb96312Sdlg 
2635ccb96312Sdlg uncreate:
2636ccb96312Sdlg 	for (i = 0; i < sc->sc_tx_ring_ndescs; i++) {
2637ccb96312Sdlg 		txm = &maps[i];
2638ccb96312Sdlg 
2639ccb96312Sdlg 		if (txm->txm_map == NULL)
2640ccb96312Sdlg 			continue;
2641ccb96312Sdlg 
2642ccb96312Sdlg 		bus_dmamap_destroy(sc->sc_dmat, txm->txm_map);
2643ccb96312Sdlg 	}
2644ccb96312Sdlg 
2645ccb96312Sdlg 	ixl_dmamem_free(sc, &txr->txr_mem);
2646ccb96312Sdlg freemap:
2647ccb96312Sdlg 	free(maps, M_DEVBUF, sizeof(*maps) * sc->sc_tx_ring_ndescs);
2648ccb96312Sdlg free:
2649ccb96312Sdlg 	free(txr, M_DEVBUF, sizeof(*txr));
2650ccb96312Sdlg 	return (NULL);
2651ccb96312Sdlg }
2652ccb96312Sdlg 
2653ccb96312Sdlg static void
ixl_txr_qdis(struct ixl_softc * sc,struct ixl_tx_ring * txr,int enable)2654eb1b42e4Sdlg ixl_txr_qdis(struct ixl_softc *sc, struct ixl_tx_ring *txr, int enable)
2655eb1b42e4Sdlg {
2656eb1b42e4Sdlg 	unsigned int qid;
2657eb1b42e4Sdlg 	bus_size_t reg;
2658eb1b42e4Sdlg 	uint32_t r;
2659eb1b42e4Sdlg 
2660eb1b42e4Sdlg 	qid = txr->txr_qid + sc->sc_base_queue;
2661eb1b42e4Sdlg 	reg = I40E_GLLAN_TXPRE_QDIS(qid / 128);
2662eb1b42e4Sdlg 	qid %= 128;
2663eb1b42e4Sdlg 
2664eb1b42e4Sdlg 	r = ixl_rd(sc, reg);
2665eb1b42e4Sdlg 	CLR(r, I40E_GLLAN_TXPRE_QDIS_QINDX_MASK);
2666eb1b42e4Sdlg 	SET(r, qid << I40E_GLLAN_TXPRE_QDIS_QINDX_SHIFT);
2667eb1b42e4Sdlg 	SET(r, enable ? I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_MASK :
2668eb1b42e4Sdlg 	    I40E_GLLAN_TXPRE_QDIS_SET_QDIS_MASK);
2669eb1b42e4Sdlg 	ixl_wr(sc, reg, r);
2670eb1b42e4Sdlg }
2671eb1b42e4Sdlg 
2672eb1b42e4Sdlg static void
ixl_txr_config(struct ixl_softc * sc,struct ixl_tx_ring * txr)2673ccb96312Sdlg ixl_txr_config(struct ixl_softc *sc, struct ixl_tx_ring *txr)
2674ccb96312Sdlg {
2675ccb96312Sdlg 	struct ixl_hmc_txq txq;
26762bb8400cSjmatthew 	struct ixl_aq_vsi_data *data = IXL_DMA_KVA(&sc->sc_scratch);
2677ccb96312Sdlg 	void *hmc;
2678ccb96312Sdlg 
2679ccb96312Sdlg 	memset(&txq, 0, sizeof(txq));
2680ccb96312Sdlg 	txq.head = htole16(0);
2681ccb96312Sdlg 	txq.new_context = 1;
2682ccb96312Sdlg 	htolem64(&txq.base,
2683eb1b42e4Sdlg 	    IXL_DMA_DVA(&txr->txr_mem) / IXL_HMC_TXQ_BASE_UNIT);
2684ccb96312Sdlg 	txq.head_wb_ena = IXL_HMC_TXQ_DESC_WB;
2685ccb96312Sdlg 	htolem16(&txq.qlen, sc->sc_tx_ring_ndescs);
2686eb1b42e4Sdlg 	txq.tphrdesc_ena = 0;
2687eb1b42e4Sdlg 	txq.tphrpacket_ena = 0;
2688eb1b42e4Sdlg 	txq.tphwdesc_ena = 0;
2689ccb96312Sdlg 	txq.rdylist = data->qs_handle[0];
2690ccb96312Sdlg 
2691eb1b42e4Sdlg 	hmc = ixl_hmc_kva(sc, IXL_HMC_LAN_TX, txr->txr_qid);
2692ccb96312Sdlg 	memset(hmc, 0, ixl_hmc_len(sc, IXL_HMC_LAN_TX));
2693ccb96312Sdlg 	ixl_hmc_pack(hmc, &txq, ixl_hmc_pack_txq, nitems(ixl_hmc_pack_txq));
2694ccb96312Sdlg }
2695ccb96312Sdlg 
2696ccb96312Sdlg static void
ixl_txr_unconfig(struct ixl_softc * sc,struct ixl_tx_ring * txr)2697ccb96312Sdlg ixl_txr_unconfig(struct ixl_softc *sc, struct ixl_tx_ring *txr)
2698ccb96312Sdlg {
2699ccb96312Sdlg 	void *hmc;
2700ccb96312Sdlg 
2701eb1b42e4Sdlg 	hmc = ixl_hmc_kva(sc, IXL_HMC_LAN_TX, txr->txr_qid);
2702ccb96312Sdlg 	memset(hmc, 0, ixl_hmc_len(sc, IXL_HMC_LAN_TX));
2703ccb96312Sdlg }
2704ccb96312Sdlg 
2705ccb96312Sdlg static void
ixl_txr_clean(struct ixl_softc * sc,struct ixl_tx_ring * txr)2706ccb96312Sdlg ixl_txr_clean(struct ixl_softc *sc, struct ixl_tx_ring *txr)
2707ccb96312Sdlg {
2708ccb96312Sdlg 	struct ixl_tx_map *maps, *txm;
2709ccb96312Sdlg 	bus_dmamap_t map;
2710ccb96312Sdlg 	unsigned int i;
2711ccb96312Sdlg 
2712ccb96312Sdlg 	maps = txr->txr_maps;
2713ccb96312Sdlg 	for (i = 0; i < sc->sc_tx_ring_ndescs; i++) {
2714ccb96312Sdlg 		txm = &maps[i];
2715ccb96312Sdlg 
2716ccb96312Sdlg 		if (txm->txm_m == NULL)
2717ccb96312Sdlg 			continue;
2718ccb96312Sdlg 
2719ccb96312Sdlg 		map = txm->txm_map;
2720ccb96312Sdlg 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
2721ccb96312Sdlg 		    BUS_DMASYNC_POSTWRITE);
2722ccb96312Sdlg 		bus_dmamap_unload(sc->sc_dmat, map);
2723ccb96312Sdlg 
2724ccb96312Sdlg 		m_freem(txm->txm_m);
2725ccb96312Sdlg 		txm->txm_m = NULL;
2726ccb96312Sdlg 	}
2727ccb96312Sdlg }
2728ccb96312Sdlg 
2729ccb96312Sdlg static int
ixl_txr_enabled(struct ixl_softc * sc,struct ixl_tx_ring * txr)2730eb1b42e4Sdlg ixl_txr_enabled(struct ixl_softc *sc, struct ixl_tx_ring *txr)
2731ccb96312Sdlg {
2732ccb96312Sdlg 	bus_size_t ena = I40E_QTX_ENA(txr->txr_qid);
2733ccb96312Sdlg 	uint32_t reg;
2734ccb96312Sdlg 	int i;
2735ccb96312Sdlg 
2736ccb96312Sdlg 	for (i = 0; i < 10; i++) {
2737ccb96312Sdlg 		reg = ixl_rd(sc, ena);
2738ccb96312Sdlg 		if (ISSET(reg, I40E_QTX_ENA_QENA_STAT_MASK))
2739ccb96312Sdlg 			return (0);
2740ccb96312Sdlg 
2741ccb96312Sdlg 		delaymsec(10);
2742ccb96312Sdlg 	}
2743ccb96312Sdlg 
2744ccb96312Sdlg 	return (ETIMEDOUT);
2745ccb96312Sdlg }
2746ccb96312Sdlg 
2747ccb96312Sdlg static int
ixl_txr_disabled(struct ixl_softc * sc,struct ixl_tx_ring * txr)2748eb1b42e4Sdlg ixl_txr_disabled(struct ixl_softc *sc, struct ixl_tx_ring *txr)
2749ccb96312Sdlg {
2750ccb96312Sdlg 	bus_size_t ena = I40E_QTX_ENA(txr->txr_qid);
2751ccb96312Sdlg 	uint32_t reg;
2752ccb96312Sdlg 	int i;
2753ccb96312Sdlg 
2754eb1b42e4Sdlg 	for (i = 0; i < 20; i++) {
2755ccb96312Sdlg 		reg = ixl_rd(sc, ena);
2756eb1b42e4Sdlg 		if (ISSET(reg, I40E_QTX_ENA_QENA_STAT_MASK) == 0)
2757ccb96312Sdlg 			return (0);
2758ccb96312Sdlg 
2759ccb96312Sdlg 		delaymsec(10);
2760ccb96312Sdlg 	}
2761ccb96312Sdlg 
2762ccb96312Sdlg 	return (ETIMEDOUT);
2763ccb96312Sdlg }
2764ccb96312Sdlg 
2765ccb96312Sdlg static void
ixl_txr_free(struct ixl_softc * sc,struct ixl_tx_ring * txr)2766ccb96312Sdlg ixl_txr_free(struct ixl_softc *sc, struct ixl_tx_ring *txr)
2767ccb96312Sdlg {
2768ccb96312Sdlg 	struct ixl_tx_map *maps, *txm;
2769ccb96312Sdlg 	unsigned int i;
2770ccb96312Sdlg 
2771ccb96312Sdlg 	maps = txr->txr_maps;
2772ccb96312Sdlg 	for (i = 0; i < sc->sc_tx_ring_ndescs; i++) {
2773ccb96312Sdlg 		txm = &maps[i];
2774ccb96312Sdlg 
2775ccb96312Sdlg 		bus_dmamap_destroy(sc->sc_dmat, txm->txm_map);
2776ccb96312Sdlg 	}
2777ccb96312Sdlg 
2778ccb96312Sdlg 	ixl_dmamem_free(sc, &txr->txr_mem);
2779ccb96312Sdlg 	free(maps, M_DEVBUF, sizeof(*maps) * sc->sc_tx_ring_ndescs);
2780ccb96312Sdlg 	free(txr, M_DEVBUF, sizeof(*txr));
2781ccb96312Sdlg }
2782ccb96312Sdlg 
2783ccb96312Sdlg static inline int
ixl_load_mbuf(bus_dma_tag_t dmat,bus_dmamap_t map,struct mbuf * m)2784ccb96312Sdlg ixl_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m)
2785ccb96312Sdlg {
2786ccb96312Sdlg 	int error;
2787ccb96312Sdlg 
2788ccb96312Sdlg 	error = bus_dmamap_load_mbuf(dmat, map, m,
2789ccb96312Sdlg 	    BUS_DMA_STREAMING | BUS_DMA_NOWAIT);
2790a78aaae2Sdlg 	if (error != EFBIG)
2791a78aaae2Sdlg 		return (error);
2792a78aaae2Sdlg 
2793a78aaae2Sdlg 	error = m_defrag(m, M_DONTWAIT);
2794a78aaae2Sdlg 	if (error != 0)
2795ccb96312Sdlg 		return (error);
2796ccb96312Sdlg 
2797ccb96312Sdlg 	return (bus_dmamap_load_mbuf(dmat, map, m,
2798ccb96312Sdlg 	    BUS_DMA_STREAMING | BUS_DMA_NOWAIT));
2799ccb96312Sdlg }
2800ccb96312Sdlg 
280104206048Sdlg static uint64_t
ixl_tx_setup_offload(struct mbuf * m0,struct ixl_tx_ring * txr,unsigned int prod)2802f77c9c95Sjan ixl_tx_setup_offload(struct mbuf *m0, struct ixl_tx_ring *txr,
2803f77c9c95Sjan     unsigned int prod)
280404206048Sdlg {
280526fd91ceSjan 	struct ether_extracted ext;
280604206048Sdlg 	uint64_t hlen;
280704206048Sdlg 	uint64_t offload = 0;
280804206048Sdlg 
2809983d220cSdlg 	if (ISSET(m0->m_flags, M_VLANTAG)) {
2810983d220cSdlg 		uint64_t vtag = m0->m_pkthdr.ether_vtag;
2811983d220cSdlg 		offload |= IXL_TX_DESC_CMD_IL2TAG1;
2812983d220cSdlg 		offload |= vtag << IXL_TX_DESC_L2TAG1_SHIFT;
2813983d220cSdlg 	}
2814983d220cSdlg 
281504206048Sdlg 	if (!ISSET(m0->m_pkthdr.csum_flags,
2816f77c9c95Sjan 	    M_IPV4_CSUM_OUT|M_TCP_CSUM_OUT|M_UDP_CSUM_OUT|M_TCP_TSO))
2817983d220cSdlg 		return (offload);
281804206048Sdlg 
281926fd91ceSjan 	ether_extract_headers(m0, &ext);
282004206048Sdlg 
282126fd91ceSjan 	if (ext.ip4) {
282204206048Sdlg 		offload |= ISSET(m0->m_pkthdr.csum_flags, M_IPV4_CSUM_OUT) ?
282304206048Sdlg 		    IXL_TX_DESC_CMD_IIPT_IPV4_CSUM :
282404206048Sdlg 		    IXL_TX_DESC_CMD_IIPT_IPV4;
282504206048Sdlg #ifdef INET6
282626fd91ceSjan 	} else if (ext.ip6) {
282704206048Sdlg 		offload |= IXL_TX_DESC_CMD_IIPT_IPV6;
282804206048Sdlg #endif
282926fd91ceSjan 	} else {
283004206048Sdlg 		panic("CSUM_OUT set for non-IP packet");
283104206048Sdlg 		/* NOTREACHED */
283204206048Sdlg 	}
2833ac5f541aSbluhm 	hlen = ext.iphlen;
283404206048Sdlg 
283504206048Sdlg 	offload |= (ETHER_HDR_LEN >> 1) << IXL_TX_DESC_MACLEN_SHIFT;
283604206048Sdlg 	offload |= (hlen >> 2) << IXL_TX_DESC_IPLEN_SHIFT;
283704206048Sdlg 
283826fd91ceSjan 	if (ext.tcp && ISSET(m0->m_pkthdr.csum_flags, M_TCP_CSUM_OUT)) {
283904206048Sdlg 		offload |= IXL_TX_DESC_CMD_L4T_EOFT_TCP;
2840e78a66e5Sbluhm 		offload |= (uint64_t)(ext.tcphlen >> 2)
2841e78a66e5Sbluhm 		    << IXL_TX_DESC_L4LEN_SHIFT;
284226fd91ceSjan 	} else if (ext.udp && ISSET(m0->m_pkthdr.csum_flags, M_UDP_CSUM_OUT)) {
284304206048Sdlg 		offload |= IXL_TX_DESC_CMD_L4T_EOFT_UDP;
2844e78a66e5Sbluhm 		offload |= (uint64_t)(sizeof(*ext.udp) >> 2)
2845e78a66e5Sbluhm 		    << IXL_TX_DESC_L4LEN_SHIFT;
284604206048Sdlg 	}
284704206048Sdlg 
2848f77c9c95Sjan 	if (ISSET(m0->m_pkthdr.csum_flags, M_TCP_TSO)) {
28497f8ccd64Sjan 		if (ext.tcp && m0->m_pkthdr.ph_mss > 0) {
2850f77c9c95Sjan 			struct ixl_tx_desc *ring, *txd;
2851dc62a2d5Sjan 			uint64_t cmd = 0, paylen, outlen;
2852f77c9c95Sjan 
2853e78a66e5Sbluhm 			hlen += ext.tcphlen;
2854dc62a2d5Sjan 
2855db052177Sjan 			/*
2856db052177Sjan 			 * The MSS should not be set to a lower value than 64
2857db052177Sjan 			 * or larger than 9668 bytes.
2858db052177Sjan 			 */
2859db052177Sjan 			outlen = MIN(9668, MAX(64, m0->m_pkthdr.ph_mss));
2860dc62a2d5Sjan 			paylen = m0->m_pkthdr.len - ETHER_HDR_LEN - hlen;
2861dc62a2d5Sjan 
2862f77c9c95Sjan 			ring = IXL_DMA_KVA(&txr->txr_mem);
2863f77c9c95Sjan 			txd = &ring[prod];
2864f77c9c95Sjan 
2865f77c9c95Sjan 			cmd |= IXL_TX_DESC_DTYPE_CONTEXT;
2866f77c9c95Sjan 			cmd |= IXL_TX_CTX_DESC_CMD_TSO;
2867dc62a2d5Sjan 			cmd |= paylen << IXL_TX_CTX_DESC_TLEN_SHIFT;
2868dc62a2d5Sjan 			cmd |= outlen << IXL_TX_CTX_DESC_MSS_SHIFT;
2869f77c9c95Sjan 
2870f77c9c95Sjan 			htolem64(&txd->addr, 0);
2871f77c9c95Sjan 			htolem64(&txd->cmd, cmd);
2872dc62a2d5Sjan 
2873dc62a2d5Sjan 			tcpstat_add(tcps_outpkttso,
2874dc62a2d5Sjan 			    (paylen + outlen - 1) / outlen);
2875f77c9c95Sjan 		} else
2876f77c9c95Sjan 			tcpstat_inc(tcps_outbadtso);
2877f77c9c95Sjan 	}
2878f77c9c95Sjan 
287904206048Sdlg 	return (offload);
288004206048Sdlg }
288104206048Sdlg 
2882ccb96312Sdlg static void
ixl_start(struct ifqueue * ifq)2883ccb96312Sdlg ixl_start(struct ifqueue *ifq)
2884ccb96312Sdlg {
2885ccb96312Sdlg 	struct ifnet *ifp = ifq->ifq_if;
2886ccb96312Sdlg 	struct ixl_softc *sc = ifp->if_softc;
2887ccb96312Sdlg 	struct ixl_tx_ring *txr = ifq->ifq_softc;
2888ccb96312Sdlg 	struct ixl_tx_desc *ring, *txd;
2889ccb96312Sdlg 	struct ixl_tx_map *txm;
2890ccb96312Sdlg 	bus_dmamap_t map;
2891ccb96312Sdlg 	struct mbuf *m;
2892378d0f97Sderaadt 	uint64_t cmd;
2893ccb96312Sdlg 	unsigned int prod, free, last, i;
2894ccb96312Sdlg 	unsigned int mask;
2895ccb96312Sdlg 	int post = 0;
289604206048Sdlg 	uint64_t offload;
2897ccb96312Sdlg #if NBPFILTER > 0
2898ccb96312Sdlg 	caddr_t if_bpf;
2899ccb96312Sdlg #endif
2900ccb96312Sdlg 
2901ccb96312Sdlg 	if (!LINK_STATE_IS_UP(ifp->if_link_state)) {
2902ccb96312Sdlg 		ifq_purge(ifq);
2903ccb96312Sdlg 		return;
2904ccb96312Sdlg 	}
2905ccb96312Sdlg 
2906ccb96312Sdlg 	prod = txr->txr_prod;
2907ccb96312Sdlg 	free = txr->txr_cons;
2908ccb96312Sdlg 	if (free <= prod)
2909ccb96312Sdlg 		free += sc->sc_tx_ring_ndescs;
2910ccb96312Sdlg 	free -= prod;
2911ccb96312Sdlg 
2912ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&txr->txr_mem),
2913ccb96312Sdlg 	    0, IXL_DMA_LEN(&txr->txr_mem), BUS_DMASYNC_POSTWRITE);
2914ccb96312Sdlg 
2915ccb96312Sdlg 	ring = IXL_DMA_KVA(&txr->txr_mem);
2916ccb96312Sdlg 	mask = sc->sc_tx_ring_ndescs - 1;
2917ccb96312Sdlg 
2918ccb96312Sdlg 	for (;;) {
2919f77c9c95Sjan 		/* We need one extra descriptor for TSO packets. */
2920f77c9c95Sjan 		if (free <= (IXL_TX_PKT_DESCS + 1)) {
2921ccb96312Sdlg 			ifq_set_oactive(ifq);
2922ccb96312Sdlg 			break;
2923ccb96312Sdlg 		}
2924ccb96312Sdlg 
2925ccb96312Sdlg 		m = ifq_dequeue(ifq);
2926ccb96312Sdlg 		if (m == NULL)
2927ccb96312Sdlg 			break;
2928ccb96312Sdlg 
2929f77c9c95Sjan 		offload = ixl_tx_setup_offload(m, txr, prod);
293004206048Sdlg 
2931ccb96312Sdlg 		txm = &txr->txr_maps[prod];
2932ccb96312Sdlg 		map = txm->txm_map;
2933ccb96312Sdlg 
2934f77c9c95Sjan 		if (ISSET(m->m_pkthdr.csum_flags, M_TCP_TSO)) {
2935f77c9c95Sjan 			prod++;
2936f77c9c95Sjan 			prod &= mask;
2937f77c9c95Sjan 			free--;
2938f77c9c95Sjan 		}
2939f77c9c95Sjan 
2940ccb96312Sdlg 		if (ixl_load_mbuf(sc->sc_dmat, map, m) != 0) {
2941a78aaae2Sdlg 			ifq->ifq_errors++;
2942ccb96312Sdlg 			m_freem(m);
2943ccb96312Sdlg 			continue;
2944ccb96312Sdlg 		}
2945ccb96312Sdlg 
2946ccb96312Sdlg 		bus_dmamap_sync(sc->sc_dmat, map, 0,
2947ccb96312Sdlg 		    map->dm_mapsize, BUS_DMASYNC_PREWRITE);
2948ccb96312Sdlg 
2949ccb96312Sdlg 		for (i = 0; i < map->dm_nsegs; i++) {
2950ccb96312Sdlg 			txd = &ring[prod];
2951ccb96312Sdlg 
2952ccb96312Sdlg 			cmd = (uint64_t)map->dm_segs[i].ds_len <<
2953ccb96312Sdlg 			    IXL_TX_DESC_BSIZE_SHIFT;
2954ccb96312Sdlg 			cmd |= IXL_TX_DESC_DTYPE_DATA | IXL_TX_DESC_CMD_ICRC;
295504206048Sdlg 			cmd |= offload;
2956ccb96312Sdlg 
2957ccb96312Sdlg 			htolem64(&txd->addr, map->dm_segs[i].ds_addr);
2958ccb96312Sdlg 			htolem64(&txd->cmd, cmd);
2959ccb96312Sdlg 
2960ccb96312Sdlg 			last = prod;
2961ccb96312Sdlg 
2962ccb96312Sdlg 			prod++;
2963ccb96312Sdlg 			prod &= mask;
2964ccb96312Sdlg 		}
2965ccb96312Sdlg 		cmd |= IXL_TX_DESC_CMD_EOP | IXL_TX_DESC_CMD_RS;
2966ccb96312Sdlg 		htolem64(&txd->cmd, cmd);
2967ccb96312Sdlg 
2968ccb96312Sdlg 		txm->txm_m = m;
2969ccb96312Sdlg 		txm->txm_eop = last;
2970ccb96312Sdlg 
2971ccb96312Sdlg #if NBPFILTER > 0
2972ccb96312Sdlg 		if_bpf = ifp->if_bpf;
2973ccb96312Sdlg 		if (if_bpf)
2974ccb96312Sdlg 			bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_OUT);
2975ccb96312Sdlg #endif
2976ccb96312Sdlg 
2977ccb96312Sdlg 		free -= i;
2978ccb96312Sdlg 		post = 1;
2979ccb96312Sdlg 	}
2980ccb96312Sdlg 
2981ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&txr->txr_mem),
2982ccb96312Sdlg 	    0, IXL_DMA_LEN(&txr->txr_mem), BUS_DMASYNC_PREWRITE);
2983ccb96312Sdlg 
2984ccb96312Sdlg 	if (post) {
2985ccb96312Sdlg 		txr->txr_prod = prod;
2986ccb96312Sdlg 		ixl_wr(sc, txr->txr_tail, prod);
2987ccb96312Sdlg 	}
2988ccb96312Sdlg }
2989ccb96312Sdlg 
2990ccb96312Sdlg static int
ixl_txeof(struct ixl_softc * sc,struct ixl_tx_ring * txr)2991e01adc04Sdlg ixl_txeof(struct ixl_softc *sc, struct ixl_tx_ring *txr)
2992ccb96312Sdlg {
2993e01adc04Sdlg 	struct ifqueue *ifq = txr->txr_ifq;
2994ccb96312Sdlg 	struct ixl_tx_desc *ring, *txd;
2995ccb96312Sdlg 	struct ixl_tx_map *txm;
2996ccb96312Sdlg 	bus_dmamap_t map;
2997ccb96312Sdlg 	unsigned int cons, prod, last;
2998ccb96312Sdlg 	unsigned int mask;
2999ccb96312Sdlg 	uint64_t dtype;
3000ccb96312Sdlg 	int done = 0;
3001ccb96312Sdlg 
3002ccb96312Sdlg 	prod = txr->txr_prod;
3003ccb96312Sdlg 	cons = txr->txr_cons;
3004ccb96312Sdlg 
3005ccb96312Sdlg 	if (cons == prod)
3006ccb96312Sdlg 		return (0);
3007ccb96312Sdlg 
3008ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&txr->txr_mem),
3009ccb96312Sdlg 	    0, IXL_DMA_LEN(&txr->txr_mem), BUS_DMASYNC_POSTREAD);
3010ccb96312Sdlg 
3011ccb96312Sdlg 	ring = IXL_DMA_KVA(&txr->txr_mem);
3012ccb96312Sdlg 	mask = sc->sc_tx_ring_ndescs - 1;
3013ccb96312Sdlg 
3014ccb96312Sdlg 	do {
3015ccb96312Sdlg 		txm = &txr->txr_maps[cons];
3016ccb96312Sdlg 		last = txm->txm_eop;
3017ccb96312Sdlg 		txd = &ring[last];
3018ccb96312Sdlg 
3019ccb96312Sdlg 		dtype = txd->cmd & htole64(IXL_TX_DESC_DTYPE_MASK);
3020ccb96312Sdlg 		if (dtype != htole64(IXL_TX_DESC_DTYPE_DONE))
3021ccb96312Sdlg 			break;
3022ccb96312Sdlg 
3023ccb96312Sdlg 		map = txm->txm_map;
3024ccb96312Sdlg 
3025ccb96312Sdlg 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
3026ccb96312Sdlg 		    BUS_DMASYNC_POSTWRITE);
3027ccb96312Sdlg 		bus_dmamap_unload(sc->sc_dmat, map);
3028ccb96312Sdlg 		m_freem(txm->txm_m);
3029ccb96312Sdlg 
3030ccb96312Sdlg 		txm->txm_m = NULL;
3031ccb96312Sdlg 		txm->txm_eop = -1;
3032ccb96312Sdlg 
3033ccb96312Sdlg 		cons = last + 1;
3034ccb96312Sdlg 		cons &= mask;
3035ccb96312Sdlg 
3036ccb96312Sdlg 		done = 1;
3037ccb96312Sdlg 	} while (cons != prod);
3038ccb96312Sdlg 
3039ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&txr->txr_mem),
3040ccb96312Sdlg 	    0, IXL_DMA_LEN(&txr->txr_mem), BUS_DMASYNC_PREREAD);
3041ccb96312Sdlg 
3042ccb96312Sdlg 	txr->txr_cons = cons;
3043ccb96312Sdlg 
3044ccb96312Sdlg 	//ixl_enable(sc, txr->txr_msix);
3045ccb96312Sdlg 
3046ccb96312Sdlg 	if (ifq_is_oactive(ifq))
3047ccb96312Sdlg 		ifq_restart(ifq);
3048ccb96312Sdlg 
3049ccb96312Sdlg 	return (done);
3050ccb96312Sdlg }
3051ccb96312Sdlg 
3052ccb96312Sdlg static struct ixl_rx_ring *
ixl_rxr_alloc(struct ixl_softc * sc,unsigned int qid)3053ccb96312Sdlg ixl_rxr_alloc(struct ixl_softc *sc, unsigned int qid)
3054ccb96312Sdlg {
3055ccb96312Sdlg 	struct ixl_rx_ring *rxr;
3056ccb96312Sdlg 	struct ixl_rx_map *maps, *rxm;
3057ccb96312Sdlg 	unsigned int i;
3058ccb96312Sdlg 
3059ccb96312Sdlg 	rxr = malloc(sizeof(*rxr), M_DEVBUF, M_WAITOK|M_CANFAIL);
3060ccb96312Sdlg 	if (rxr == NULL)
3061ccb96312Sdlg 		return (NULL);
3062ccb96312Sdlg 
3063ccb96312Sdlg 	maps = mallocarray(sizeof(*maps),
3064ccb96312Sdlg 	    sc->sc_rx_ring_ndescs, M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO);
3065ccb96312Sdlg 	if (maps == NULL)
3066ccb96312Sdlg 		goto free;
3067ccb96312Sdlg 
3068ccb96312Sdlg 	if (ixl_dmamem_alloc(sc, &rxr->rxr_mem,
3069ccb96312Sdlg 	    sizeof(struct ixl_rx_rd_desc_16) * sc->sc_rx_ring_ndescs,
3070ccb96312Sdlg 	    IXL_RX_QUEUE_ALIGN) != 0)
3071ccb96312Sdlg 		goto freemap;
3072ccb96312Sdlg 
3073ccb96312Sdlg 	for (i = 0; i < sc->sc_rx_ring_ndescs; i++) {
3074ccb96312Sdlg 		rxm = &maps[i];
3075ccb96312Sdlg 
3076ccb96312Sdlg 		if (bus_dmamap_create(sc->sc_dmat,
3077ccb96312Sdlg 		    IXL_HARDMTU, 1, IXL_HARDMTU, 0,
3078ccb96312Sdlg 		    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
3079ccb96312Sdlg 		    &rxm->rxm_map) != 0)
3080ccb96312Sdlg 			goto uncreate;
3081ccb96312Sdlg 
3082ccb96312Sdlg 		rxm->rxm_m = NULL;
3083ccb96312Sdlg 	}
3084ccb96312Sdlg 
308500cd24f1Sdlg 	rxr->rxr_sc = sc;
3086ccb96312Sdlg 	if_rxr_init(&rxr->rxr_acct, 17, sc->sc_rx_ring_ndescs - 1);
3087ccb96312Sdlg 	timeout_set(&rxr->rxr_refill, ixl_rxrefill, rxr);
3088ccb96312Sdlg 	rxr->rxr_cons = rxr->rxr_prod = 0;
3089ccb96312Sdlg 	rxr->rxr_m_head = NULL;
3090ccb96312Sdlg 	rxr->rxr_m_tail = &rxr->rxr_m_head;
3091ccb96312Sdlg 	rxr->rxr_maps = maps;
3092ccb96312Sdlg 
3093ccb96312Sdlg 	rxr->rxr_tail = I40E_QRX_TAIL(qid);
3094ccb96312Sdlg 	rxr->rxr_qid = qid;
3095ccb96312Sdlg 
3096ccb96312Sdlg 	return (rxr);
3097ccb96312Sdlg 
3098ccb96312Sdlg uncreate:
3099ccb96312Sdlg 	for (i = 0; i < sc->sc_rx_ring_ndescs; i++) {
3100ccb96312Sdlg 		rxm = &maps[i];
3101ccb96312Sdlg 
3102ccb96312Sdlg 		if (rxm->rxm_map == NULL)
3103ccb96312Sdlg 			continue;
3104ccb96312Sdlg 
3105ccb96312Sdlg 		bus_dmamap_destroy(sc->sc_dmat, rxm->rxm_map);
3106ccb96312Sdlg 	}
3107ccb96312Sdlg 
3108ccb96312Sdlg 	ixl_dmamem_free(sc, &rxr->rxr_mem);
3109ccb96312Sdlg freemap:
3110ccb96312Sdlg 	free(maps, M_DEVBUF, sizeof(*maps) * sc->sc_rx_ring_ndescs);
3111ccb96312Sdlg free:
3112ccb96312Sdlg 	free(rxr, M_DEVBUF, sizeof(*rxr));
3113ccb96312Sdlg 	return (NULL);
3114ccb96312Sdlg }
3115ccb96312Sdlg 
3116ccb96312Sdlg static void
ixl_rxr_clean(struct ixl_softc * sc,struct ixl_rx_ring * rxr)3117ccb96312Sdlg ixl_rxr_clean(struct ixl_softc *sc, struct ixl_rx_ring *rxr)
3118ccb96312Sdlg {
3119ccb96312Sdlg 	struct ixl_rx_map *maps, *rxm;
3120ccb96312Sdlg 	bus_dmamap_t map;
3121ccb96312Sdlg 	unsigned int i;
3122ccb96312Sdlg 
3123c87f73ddSvisa 	timeout_del_barrier(&rxr->rxr_refill);
3124ccb96312Sdlg 
3125ccb96312Sdlg 	maps = rxr->rxr_maps;
3126ccb96312Sdlg 	for (i = 0; i < sc->sc_rx_ring_ndescs; i++) {
3127ccb96312Sdlg 		rxm = &maps[i];
3128ccb96312Sdlg 
3129ccb96312Sdlg 		if (rxm->rxm_m == NULL)
3130ccb96312Sdlg 			continue;
3131ccb96312Sdlg 
3132ccb96312Sdlg 		map = rxm->rxm_map;
3133ccb96312Sdlg 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
3134ccb96312Sdlg 		    BUS_DMASYNC_POSTWRITE);
3135ccb96312Sdlg 		bus_dmamap_unload(sc->sc_dmat, map);
3136ccb96312Sdlg 
3137ccb96312Sdlg 		m_freem(rxm->rxm_m);
3138ccb96312Sdlg 		rxm->rxm_m = NULL;
3139ccb96312Sdlg 	}
3140ccb96312Sdlg 
3141ccb96312Sdlg 	m_freem(rxr->rxr_m_head);
3142ccb96312Sdlg 	rxr->rxr_m_head = NULL;
3143ccb96312Sdlg 	rxr->rxr_m_tail = &rxr->rxr_m_head;
3144ccb96312Sdlg 
3145ccb96312Sdlg 	rxr->rxr_prod = rxr->rxr_cons = 0;
3146ccb96312Sdlg }
3147ccb96312Sdlg 
3148ccb96312Sdlg static int
ixl_rxr_enabled(struct ixl_softc * sc,struct ixl_rx_ring * rxr)3149eb1b42e4Sdlg ixl_rxr_enabled(struct ixl_softc *sc, struct ixl_rx_ring *rxr)
3150ccb96312Sdlg {
3151ccb96312Sdlg 	bus_size_t ena = I40E_QRX_ENA(rxr->rxr_qid);
3152ccb96312Sdlg 	uint32_t reg;
3153ccb96312Sdlg 	int i;
3154ccb96312Sdlg 
3155ccb96312Sdlg 	for (i = 0; i < 10; i++) {
3156ccb96312Sdlg 		reg = ixl_rd(sc, ena);
3157ccb96312Sdlg 		if (ISSET(reg, I40E_QRX_ENA_QENA_STAT_MASK))
3158ccb96312Sdlg 			return (0);
3159ccb96312Sdlg 
3160ccb96312Sdlg 		delaymsec(10);
3161ccb96312Sdlg 	}
3162ccb96312Sdlg 
3163ccb96312Sdlg 	return (ETIMEDOUT);
3164ccb96312Sdlg }
3165ccb96312Sdlg 
3166eb1b42e4Sdlg static int
ixl_rxr_disabled(struct ixl_softc * sc,struct ixl_rx_ring * rxr)3167eb1b42e4Sdlg ixl_rxr_disabled(struct ixl_softc *sc, struct ixl_rx_ring *rxr)
3168eb1b42e4Sdlg {
3169eb1b42e4Sdlg 	bus_size_t ena = I40E_QRX_ENA(rxr->rxr_qid);
3170eb1b42e4Sdlg 	uint32_t reg;
3171eb1b42e4Sdlg 	int i;
3172eb1b42e4Sdlg 
3173eb1b42e4Sdlg 	for (i = 0; i < 20; i++) {
3174eb1b42e4Sdlg 		reg = ixl_rd(sc, ena);
3175eb1b42e4Sdlg 		if (ISSET(reg, I40E_QRX_ENA_QENA_STAT_MASK) == 0)
3176eb1b42e4Sdlg 			return (0);
3177eb1b42e4Sdlg 
3178eb1b42e4Sdlg 		delaymsec(10);
3179eb1b42e4Sdlg 	}
3180eb1b42e4Sdlg 
3181eb1b42e4Sdlg 	return (ETIMEDOUT);
3182eb1b42e4Sdlg }
3183eb1b42e4Sdlg 
3184ccb96312Sdlg static void
ixl_rxr_config(struct ixl_softc * sc,struct ixl_rx_ring * rxr)3185ccb96312Sdlg ixl_rxr_config(struct ixl_softc *sc, struct ixl_rx_ring *rxr)
3186ccb96312Sdlg {
3187ccb96312Sdlg 	struct ixl_hmc_rxq rxq;
3188ccb96312Sdlg 	void *hmc;
3189ccb96312Sdlg 
3190ccb96312Sdlg 	memset(&rxq, 0, sizeof(rxq));
3191ccb96312Sdlg 
3192ccb96312Sdlg 	rxq.head = htole16(0);
3193ccb96312Sdlg 	htolem64(&rxq.base,
319400cd24f1Sdlg 	    IXL_DMA_DVA(&rxr->rxr_mem) / IXL_HMC_RXQ_BASE_UNIT);
3195ccb96312Sdlg 	htolem16(&rxq.qlen, sc->sc_rx_ring_ndescs);
3196eb1b42e4Sdlg 	rxq.dbuff = htole16(MCLBYTES / IXL_HMC_RXQ_DBUFF_UNIT);
3197ccb96312Sdlg 	rxq.hbuff = 0;
3198ccb96312Sdlg 	rxq.dtype = IXL_HMC_RXQ_DTYPE_NOSPLIT;
3199ccb96312Sdlg 	rxq.dsize = IXL_HMC_RXQ_DSIZE_16;
3200ccb96312Sdlg 	rxq.crcstrip = 1;
3201555fd15dSdlg 	rxq.l2tsel = IXL_HMC_RXQ_L2TSEL_1ST_TAG_TO_L2TAG1;
3202ccb96312Sdlg 	rxq.showiv = 0;
3203bf059df2Sjmatthew 	rxq.rxmax = htole16(IXL_HARDMTU);
3204eb1b42e4Sdlg 	rxq.tphrdesc_ena = 0;
3205eb1b42e4Sdlg 	rxq.tphwdesc_ena = 0;
3206ccb96312Sdlg 	rxq.tphdata_ena = 0;
3207ccb96312Sdlg 	rxq.tphhead_ena = 0;
3208eb1b42e4Sdlg 	rxq.lrxqthresh = 0;
3209ccb96312Sdlg 	rxq.prefena = 1;
3210ccb96312Sdlg 
3211ccb96312Sdlg 	hmc = ixl_hmc_kva(sc, IXL_HMC_LAN_RX, rxr->rxr_qid);
3212ccb96312Sdlg 	memset(hmc, 0, ixl_hmc_len(sc, IXL_HMC_LAN_RX));
3213ccb96312Sdlg 	ixl_hmc_pack(hmc, &rxq, ixl_hmc_pack_rxq, nitems(ixl_hmc_pack_rxq));
3214ccb96312Sdlg }
3215ccb96312Sdlg 
3216ccb96312Sdlg static void
ixl_rxr_unconfig(struct ixl_softc * sc,struct ixl_rx_ring * rxr)3217ccb96312Sdlg ixl_rxr_unconfig(struct ixl_softc *sc, struct ixl_rx_ring *rxr)
3218ccb96312Sdlg {
3219ccb96312Sdlg 	void *hmc;
3220ccb96312Sdlg 
3221ccb96312Sdlg 	hmc = ixl_hmc_kva(sc, IXL_HMC_LAN_RX, rxr->rxr_qid);
3222ccb96312Sdlg 	memset(hmc, 0, ixl_hmc_len(sc, IXL_HMC_LAN_RX));
3223ccb96312Sdlg }
3224ccb96312Sdlg 
3225ccb96312Sdlg static void
ixl_rxr_free(struct ixl_softc * sc,struct ixl_rx_ring * rxr)3226ccb96312Sdlg ixl_rxr_free(struct ixl_softc *sc, struct ixl_rx_ring *rxr)
3227ccb96312Sdlg {
3228ccb96312Sdlg 	struct ixl_rx_map *maps, *rxm;
3229ccb96312Sdlg 	unsigned int i;
3230ccb96312Sdlg 
3231ccb96312Sdlg 	maps = rxr->rxr_maps;
3232ccb96312Sdlg 	for (i = 0; i < sc->sc_rx_ring_ndescs; i++) {
3233ccb96312Sdlg 		rxm = &maps[i];
3234ccb96312Sdlg 
3235ccb96312Sdlg 		bus_dmamap_destroy(sc->sc_dmat, rxm->rxm_map);
3236ccb96312Sdlg 	}
3237ccb96312Sdlg 
3238ccb96312Sdlg 	ixl_dmamem_free(sc, &rxr->rxr_mem);
3239ccb96312Sdlg 	free(maps, M_DEVBUF, sizeof(*maps) * sc->sc_rx_ring_ndescs);
3240ccb96312Sdlg 	free(rxr, M_DEVBUF, sizeof(*rxr));
3241ccb96312Sdlg }
3242ccb96312Sdlg 
3243ccb96312Sdlg static int
ixl_rxeof(struct ixl_softc * sc,struct ixl_rx_ring * rxr)3244e01adc04Sdlg ixl_rxeof(struct ixl_softc *sc, struct ixl_rx_ring *rxr)
3245ccb96312Sdlg {
3246e01adc04Sdlg 	struct ifiqueue *ifiq = rxr->rxr_ifiq;
3247ccb96312Sdlg 	struct ifnet *ifp = &sc->sc_ac.ac_if;
3248ccb96312Sdlg 	struct ixl_rx_wb_desc_16 *ring, *rxd;
3249ccb96312Sdlg 	struct ixl_rx_map *rxm;
3250ccb96312Sdlg 	bus_dmamap_t map;
3251ccb96312Sdlg 	unsigned int cons, prod;
3252ccb96312Sdlg 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
3253ccb96312Sdlg 	struct mbuf *m;
3254ccb96312Sdlg 	uint64_t word;
3255ccb96312Sdlg 	unsigned int len;
3256ccb96312Sdlg 	unsigned int mask;
3257ccb96312Sdlg 	int done = 0;
3258ccb96312Sdlg 
3259ccb96312Sdlg 	prod = rxr->rxr_prod;
3260ccb96312Sdlg 	cons = rxr->rxr_cons;
3261ccb96312Sdlg 
3262ccb96312Sdlg 	if (cons == prod)
3263ccb96312Sdlg 		return (0);
3264ccb96312Sdlg 
3265ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&rxr->rxr_mem),
3266ccb96312Sdlg 	    0, IXL_DMA_LEN(&rxr->rxr_mem),
3267ccb96312Sdlg 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
3268ccb96312Sdlg 
3269ccb96312Sdlg 	ring = IXL_DMA_KVA(&rxr->rxr_mem);
3270ccb96312Sdlg 	mask = sc->sc_rx_ring_ndescs - 1;
3271ccb96312Sdlg 
3272ccb96312Sdlg 	do {
3273ccb96312Sdlg 		rxd = &ring[cons];
3274ccb96312Sdlg 
3275ccb96312Sdlg 		word = lemtoh64(&rxd->qword1);
3276ccb96312Sdlg 		if (!ISSET(word, IXL_RX_DESC_DD))
3277ccb96312Sdlg 			break;
3278ccb96312Sdlg 
3279ccb96312Sdlg 		if_rxr_put(&rxr->rxr_acct, 1);
3280ccb96312Sdlg 
3281ccb96312Sdlg 		rxm = &rxr->rxr_maps[cons];
3282ccb96312Sdlg 
3283ccb96312Sdlg 		map = rxm->rxm_map;
3284ccb96312Sdlg 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
3285ccb96312Sdlg 		    BUS_DMASYNC_POSTREAD);
3286ccb96312Sdlg 		bus_dmamap_unload(sc->sc_dmat, map);
3287ccb96312Sdlg 
3288ccb96312Sdlg 		m = rxm->rxm_m;
3289ccb96312Sdlg 		rxm->rxm_m = NULL;
3290ccb96312Sdlg 
3291ccb96312Sdlg 		len = (word & IXL_RX_DESC_PLEN_MASK) >> IXL_RX_DESC_PLEN_SHIFT;
3292ccb96312Sdlg 		m->m_len = len;
3293ccb96312Sdlg 		m->m_pkthdr.len = 0;
3294ccb96312Sdlg 
3295ccb96312Sdlg 		m->m_next = NULL;
3296ccb96312Sdlg 		*rxr->rxr_m_tail = m;
3297ccb96312Sdlg 		rxr->rxr_m_tail = &m->m_next;
3298ccb96312Sdlg 
3299ccb96312Sdlg 		m = rxr->rxr_m_head;
3300ccb96312Sdlg 		m->m_pkthdr.len += len;
3301ccb96312Sdlg 
3302ccb96312Sdlg 		if (ISSET(word, IXL_RX_DESC_EOP)) {
3303ccb96312Sdlg 			if (!ISSET(word,
3304ccb96312Sdlg 			    IXL_RX_DESC_RXE | IXL_RX_DESC_OVERSIZE)) {
33056850335aSdlg 				if ((word & IXL_RX_DESC_FLTSTAT_MASK) ==
33066850335aSdlg 				    IXL_RX_DESC_FLTSTAT_RSS) {
33076850335aSdlg 					m->m_pkthdr.ph_flowid =
33086850335aSdlg 					    lemtoh32(&rxd->filter_status);
33096850335aSdlg 					m->m_pkthdr.csum_flags |= M_FLOWID;
33106850335aSdlg 				}
33116850335aSdlg 
3312555fd15dSdlg 				if (ISSET(word, IXL_RX_DESC_L2TAG1P)) {
3313555fd15dSdlg 					m->m_pkthdr.ether_vtag =
3314555fd15dSdlg 					    lemtoh16(&rxd->l2tag1);
3315555fd15dSdlg 					SET(m->m_flags, M_VLANTAG);
3316555fd15dSdlg 				}
3317555fd15dSdlg 
331889760ddfSbluhm 				ixl_rx_checksum(m, word);
3319ccb96312Sdlg 				ml_enqueue(&ml, m);
3320ccb96312Sdlg 			} else {
3321ccb96312Sdlg 				ifp->if_ierrors++; /* XXX */
3322ccb96312Sdlg 				m_freem(m);
3323ccb96312Sdlg 			}
3324ccb96312Sdlg 
3325ccb96312Sdlg 			rxr->rxr_m_head = NULL;
3326ccb96312Sdlg 			rxr->rxr_m_tail = &rxr->rxr_m_head;
3327ccb96312Sdlg 		}
3328ccb96312Sdlg 
3329ccb96312Sdlg 		cons++;
3330ccb96312Sdlg 		cons &= mask;
3331ccb96312Sdlg 
3332ccb96312Sdlg 		done = 1;
3333ccb96312Sdlg 	} while (cons != prod);
3334ccb96312Sdlg 
3335ccb96312Sdlg 	if (done) {
3336ccb96312Sdlg 		rxr->rxr_cons = cons;
33374cc26fbaSdlg 		if (ifiq_input(ifiq, &ml))
33384cc26fbaSdlg 			if_rxr_livelocked(&rxr->rxr_acct);
3339eb1b42e4Sdlg 		ixl_rxfill(sc, rxr);
3340ccb96312Sdlg 	}
3341ccb96312Sdlg 
3342ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&rxr->rxr_mem),
3343ccb96312Sdlg 	    0, IXL_DMA_LEN(&rxr->rxr_mem),
3344ccb96312Sdlg 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
3345ccb96312Sdlg 
3346ccb96312Sdlg 	return (done);
3347ccb96312Sdlg }
3348ccb96312Sdlg 
3349ccb96312Sdlg static void
ixl_rxfill(struct ixl_softc * sc,struct ixl_rx_ring * rxr)3350ccb96312Sdlg ixl_rxfill(struct ixl_softc *sc, struct ixl_rx_ring *rxr)
3351ccb96312Sdlg {
3352ccb96312Sdlg 	struct ixl_rx_rd_desc_16 *ring, *rxd;
3353ccb96312Sdlg 	struct ixl_rx_map *rxm;
3354ccb96312Sdlg 	bus_dmamap_t map;
3355ccb96312Sdlg 	struct mbuf *m;
3356ccb96312Sdlg 	unsigned int prod;
3357ccb96312Sdlg 	unsigned int slots;
3358ccb96312Sdlg 	unsigned int mask;
3359ccb96312Sdlg 	int post = 0;
3360ccb96312Sdlg 
3361ccb96312Sdlg 	slots = if_rxr_get(&rxr->rxr_acct, sc->sc_rx_ring_ndescs);
3362ccb96312Sdlg 	if (slots == 0)
3363ccb96312Sdlg 		return;
3364ccb96312Sdlg 
3365ccb96312Sdlg 	prod = rxr->rxr_prod;
3366ccb96312Sdlg 
3367ccb96312Sdlg 	ring = IXL_DMA_KVA(&rxr->rxr_mem);
3368ccb96312Sdlg 	mask = sc->sc_rx_ring_ndescs - 1;
3369ccb96312Sdlg 
3370ccb96312Sdlg 	do {
3371ccb96312Sdlg 		rxm = &rxr->rxr_maps[prod];
3372ccb96312Sdlg 
3373471f2571Sjan 		m = MCLGETL(NULL, M_DONTWAIT, MCLBYTES + ETHER_ALIGN);
3374ccb96312Sdlg 		if (m == NULL)
3375ccb96312Sdlg 			break;
3376b7d259d9Sdlg 		m->m_data += (m->m_ext.ext_size - (MCLBYTES + ETHER_ALIGN));
3377ccb96312Sdlg 		m->m_len = m->m_pkthdr.len = MCLBYTES + ETHER_ALIGN;
3378ccb96312Sdlg 
3379ccb96312Sdlg 		map = rxm->rxm_map;
3380ccb96312Sdlg 
3381ccb96312Sdlg 		if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
3382ccb96312Sdlg 		    BUS_DMA_NOWAIT) != 0) {
3383ccb96312Sdlg 			m_freem(m);
3384ccb96312Sdlg 			break;
3385ccb96312Sdlg 		}
3386ccb96312Sdlg 
3387ccb96312Sdlg 		rxm->rxm_m = m;
3388ccb96312Sdlg 
3389ccb96312Sdlg 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
3390ccb96312Sdlg 		    BUS_DMASYNC_PREREAD);
3391ccb96312Sdlg 
3392ccb96312Sdlg 		rxd = &ring[prod];
3393ccb96312Sdlg 
3394ccb96312Sdlg 		htolem64(&rxd->paddr, map->dm_segs[0].ds_addr);
3395ccb96312Sdlg 		rxd->haddr = htole64(0);
3396ccb96312Sdlg 
3397ccb96312Sdlg 		prod++;
3398ccb96312Sdlg 		prod &= mask;
3399ccb96312Sdlg 
3400ccb96312Sdlg 		post = 1;
3401ccb96312Sdlg 	} while (--slots);
3402ccb96312Sdlg 
3403ccb96312Sdlg 	if_rxr_put(&rxr->rxr_acct, slots);
3404ccb96312Sdlg 
3405ccb96312Sdlg 	if (if_rxr_inuse(&rxr->rxr_acct) == 0)
3406ccb96312Sdlg 		timeout_add(&rxr->rxr_refill, 1);
3407ccb96312Sdlg 	else if (post) {
3408ccb96312Sdlg 		rxr->rxr_prod = prod;
3409ccb96312Sdlg 		ixl_wr(sc, rxr->rxr_tail, prod);
3410ccb96312Sdlg 	}
3411ccb96312Sdlg }
3412ccb96312Sdlg 
3413ccb96312Sdlg void
ixl_rxrefill(void * arg)3414ccb96312Sdlg ixl_rxrefill(void *arg)
3415ccb96312Sdlg {
3416ccb96312Sdlg 	struct ixl_rx_ring *rxr = arg;
3417ccb96312Sdlg 	struct ixl_softc *sc = rxr->rxr_sc;
3418ccb96312Sdlg 
3419ccb96312Sdlg 	ixl_rxfill(sc, rxr);
3420ccb96312Sdlg }
3421ccb96312Sdlg 
3422ccb96312Sdlg static int
ixl_rxrinfo(struct ixl_softc * sc,struct if_rxrinfo * ifri)342396438522Sjmatthew ixl_rxrinfo(struct ixl_softc *sc, struct if_rxrinfo *ifri)
342496438522Sjmatthew {
342596438522Sjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
342696438522Sjmatthew 	struct if_rxring_info *ifr;
342796438522Sjmatthew 	struct ixl_rx_ring *ring;
342896438522Sjmatthew 	int i, rv;
342996438522Sjmatthew 
343096438522Sjmatthew 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
343196438522Sjmatthew 		return (ENOTTY);
343296438522Sjmatthew 
343396438522Sjmatthew 	ifr = mallocarray(sizeof(*ifr), ixl_nqueues(sc), M_TEMP,
343496438522Sjmatthew 	    M_WAITOK|M_CANFAIL|M_ZERO);
343596438522Sjmatthew 	if (ifr == NULL)
343696438522Sjmatthew 		return (ENOMEM);
343796438522Sjmatthew 
343896438522Sjmatthew 	for (i = 0; i < ixl_nqueues(sc); i++) {
343996438522Sjmatthew 		ring = ifp->if_iqs[i]->ifiq_softc;
3440bf059df2Sjmatthew 		ifr[i].ifr_size = MCLBYTES;
34417c56c775Sdlg 		snprintf(ifr[i].ifr_name, sizeof(ifr[i].ifr_name), "%d", i);
344296438522Sjmatthew 		ifr[i].ifr_info = ring->rxr_acct;
344396438522Sjmatthew 	}
344496438522Sjmatthew 
344596438522Sjmatthew 	rv = if_rxr_info_ioctl(ifri, ixl_nqueues(sc), ifr);
344696438522Sjmatthew 	free(ifr, M_TEMP, ixl_nqueues(sc) * sizeof(*ifr));
344796438522Sjmatthew 
344896438522Sjmatthew 	return (rv);
344996438522Sjmatthew }
345096438522Sjmatthew 
345189760ddfSbluhm static void
ixl_rx_checksum(struct mbuf * m,uint64_t word)345289760ddfSbluhm ixl_rx_checksum(struct mbuf *m, uint64_t word)
345389760ddfSbluhm {
345489760ddfSbluhm 	if (!ISSET(word, IXL_RX_DESC_L3L4P))
345589760ddfSbluhm 		return;
345689760ddfSbluhm 
345789760ddfSbluhm 	if (ISSET(word, IXL_RX_DESC_IPE))
345889760ddfSbluhm 		return;
345989760ddfSbluhm 
346089760ddfSbluhm 	m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
346189760ddfSbluhm 
346289760ddfSbluhm 	if (ISSET(word, IXL_RX_DESC_L4E))
346389760ddfSbluhm 		return;
346489760ddfSbluhm 
346589760ddfSbluhm 	m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK;
346689760ddfSbluhm }
346789760ddfSbluhm 
346896438522Sjmatthew static int
ixl_intr0(void * xsc)34699b0c6e1eSjmatthew ixl_intr0(void *xsc)
3470ccb96312Sdlg {
3471ccb96312Sdlg 	struct ixl_softc *sc = xsc;
347200cd24f1Sdlg 	struct ifnet *ifp = &sc->sc_ac.ac_if;
3473ccb96312Sdlg 	uint32_t icr;
3474ccb96312Sdlg 	int rv = 0;
3475ccb96312Sdlg 
3476646632e9Sjmatthew 	ixl_intr_enable(sc);
3477ccb96312Sdlg 	icr = ixl_rd(sc, I40E_PFINT_ICR0);
3478ccb96312Sdlg 
3479eb1b42e4Sdlg 	if (ISSET(icr, I40E_PFINT_ICR0_ADMINQ_MASK)) {
3480eb1b42e4Sdlg 		ixl_atq_done(sc);
3481ccb96312Sdlg 		task_add(systq, &sc->sc_arq_task);
3482ccb96312Sdlg 		rv = 1;
3483eb1b42e4Sdlg 	}
3484ccb96312Sdlg 
348510e66d97Sjmatthew 	if (ISSET(icr, I40E_PFINT_ICR0_LINK_STAT_CHANGE_MASK)) {
348610e66d97Sjmatthew 		task_add(systq, &sc->sc_link_state_task);
348710e66d97Sjmatthew 		rv = 1;
348810e66d97Sjmatthew 	}
348910e66d97Sjmatthew 
3490e01adc04Sdlg 	if (ISSET(ifp->if_flags, IFF_RUNNING)) {
3491e01adc04Sdlg 		struct ixl_vector *iv = sc->sc_vectors;
3492eb1b42e4Sdlg 		if (ISSET(icr, I40E_INTR_NOTX_RX_MASK))
3493e01adc04Sdlg 			rv |= ixl_rxeof(sc, iv->iv_rxr);
3494eb1b42e4Sdlg 		if (ISSET(icr, I40E_INTR_NOTX_TX_MASK))
3495e01adc04Sdlg 			rv |= ixl_txeof(sc, iv->iv_txr);
3496e01adc04Sdlg 	}
3497ccb96312Sdlg 
3498ccb96312Sdlg 	return (rv);
3499ccb96312Sdlg }
3500ccb96312Sdlg 
35019b0c6e1eSjmatthew static int
ixl_intr_vector(void * v)3502e01adc04Sdlg ixl_intr_vector(void *v)
35039b0c6e1eSjmatthew {
3504e01adc04Sdlg 	struct ixl_vector *iv = v;
3505e01adc04Sdlg 	struct ixl_softc *sc = iv->iv_sc;
3506e01adc04Sdlg 	struct ifnet *ifp = &sc->sc_ac.ac_if;
35079b0c6e1eSjmatthew 	int rv = 0;
35089b0c6e1eSjmatthew 
3509e01adc04Sdlg 	if (ISSET(ifp->if_flags, IFF_RUNNING)) {
3510e01adc04Sdlg 		rv |= ixl_rxeof(sc, iv->iv_rxr);
3511e01adc04Sdlg 		rv |= ixl_txeof(sc, iv->iv_txr);
3512e01adc04Sdlg 	}
35139b0c6e1eSjmatthew 
3514e01adc04Sdlg 	ixl_wr(sc, I40E_PFINT_DYN_CTLN(iv->iv_qid),
35159b0c6e1eSjmatthew 	    I40E_PFINT_DYN_CTLN_INTENA_MASK |
35169b0c6e1eSjmatthew 	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
35179b0c6e1eSjmatthew 	    (IXL_NOITR << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT));
35189b0c6e1eSjmatthew 
35199b0c6e1eSjmatthew 	return (rv);
35209b0c6e1eSjmatthew }
35219b0c6e1eSjmatthew 
3522ccb96312Sdlg static void
ixl_link_state_update_iaq(struct ixl_softc * sc,void * arg)352335e06836Sdlg ixl_link_state_update_iaq(struct ixl_softc *sc, void *arg)
352410e66d97Sjmatthew {
352535e06836Sdlg 	struct ifnet *ifp = &sc->sc_ac.ac_if;
352635e06836Sdlg 	struct ixl_aq_desc *iaq = arg;
352735e06836Sdlg 	uint16_t retval;
352835e06836Sdlg 	int link_state;
35298014a50bSdlg 	int change = 0;
353035e06836Sdlg 
353135e06836Sdlg 	retval = lemtoh16(&iaq->iaq_retval);
353235e06836Sdlg 	if (retval != IXL_AQ_RC_OK) {
353335e06836Sdlg 		printf("%s: LINK STATUS error %u\n", DEVNAME(sc), retval);
353435e06836Sdlg 		return;
353535e06836Sdlg 	}
353635e06836Sdlg 
353735e06836Sdlg 	link_state = ixl_set_link_status(sc, iaq);
35388014a50bSdlg 	mtx_enter(&sc->sc_link_state_mtx);
353935e06836Sdlg 	if (ifp->if_link_state != link_state) {
354035e06836Sdlg 		ifp->if_link_state = link_state;
35418014a50bSdlg 		change = 1;
354235e06836Sdlg 	}
35438014a50bSdlg 	mtx_leave(&sc->sc_link_state_mtx);
35448014a50bSdlg 
35458014a50bSdlg 	if (change)
35468014a50bSdlg 		if_link_state_change(ifp);
354710e66d97Sjmatthew }
354810e66d97Sjmatthew 
354910e66d97Sjmatthew static void
ixl_link_state_update(void * xsc)355010e66d97Sjmatthew ixl_link_state_update(void *xsc)
355110e66d97Sjmatthew {
355210e66d97Sjmatthew 	struct ixl_softc *sc = xsc;
355310e66d97Sjmatthew 	struct ixl_aq_desc *iaq;
355410e66d97Sjmatthew 	struct ixl_aq_link_param *param;
355510e66d97Sjmatthew 
355610e66d97Sjmatthew 	memset(&sc->sc_link_state_atq, 0, sizeof(sc->sc_link_state_atq));
355710e66d97Sjmatthew 	iaq = &sc->sc_link_state_atq.iatq_desc;
355810e66d97Sjmatthew 	iaq->iaq_opcode = htole16(IXL_AQ_OP_PHY_LINK_STATUS);
355910e66d97Sjmatthew 	param = (struct ixl_aq_link_param *)iaq->iaq_param;
356010e66d97Sjmatthew 	param->notify = IXL_AQ_LINK_NOTIFY;
356110e66d97Sjmatthew 
356235e06836Sdlg 	ixl_atq_set(&sc->sc_link_state_atq, ixl_link_state_update_iaq, iaq);
356310e66d97Sjmatthew 	ixl_atq_post(sc, &sc->sc_link_state_atq);
356410e66d97Sjmatthew }
356510e66d97Sjmatthew 
3566ccb96312Sdlg #if 0
3567ccb96312Sdlg static void
3568ccb96312Sdlg ixl_aq_dump(const struct ixl_softc *sc, const struct ixl_aq_desc *iaq)
3569ccb96312Sdlg {
3570ccb96312Sdlg 	printf("%s: flags %b opcode %04x\n", DEVNAME(sc),
3571ccb96312Sdlg 	    lemtoh16(&iaq->iaq_flags), IXL_AQ_FLAGS_FMT,
3572ccb96312Sdlg 	    lemtoh16(&iaq->iaq_opcode));
3573ccb96312Sdlg 	printf("%s: datalen %u retval %u\n", DEVNAME(sc),
3574ccb96312Sdlg 	    lemtoh16(&iaq->iaq_datalen), lemtoh16(&iaq->iaq_retval));
3575ccb96312Sdlg 	printf("%s: cookie %016llx\n", DEVNAME(sc), iaq->iaq_cookie);
3576ccb96312Sdlg 	printf("%s: %08x %08x %08x %08x\n", DEVNAME(sc),
3577ccb96312Sdlg 	    lemtoh32(&iaq->iaq_param[0]), lemtoh32(&iaq->iaq_param[1]),
3578ccb96312Sdlg 	    lemtoh32(&iaq->iaq_param[2]), lemtoh32(&iaq->iaq_param[3]));
3579ccb96312Sdlg }
3580ccb96312Sdlg #endif
3581ccb96312Sdlg 
3582ccb96312Sdlg static void
ixl_arq(void * xsc)3583ccb96312Sdlg ixl_arq(void *xsc)
3584ccb96312Sdlg {
3585ccb96312Sdlg 	struct ixl_softc *sc = xsc;
3586ccb96312Sdlg 	struct ixl_aq_desc *arq, *iaq;
3587ccb96312Sdlg 	struct ixl_aq_buf *aqb;
3588ccb96312Sdlg 	unsigned int cons = sc->sc_arq_cons;
3589ccb96312Sdlg 	unsigned int prod;
3590ccb96312Sdlg 	int done = 0;
3591ccb96312Sdlg 
3592ccb96312Sdlg 	prod = ixl_rd(sc, sc->sc_aq_regs->arq_head) &
3593ccb96312Sdlg 	    sc->sc_aq_regs->arq_head_mask;
3594ccb96312Sdlg 
3595ccb96312Sdlg 	if (cons == prod)
3596ccb96312Sdlg 		goto done;
3597ccb96312Sdlg 
3598ccb96312Sdlg 	arq = IXL_DMA_KVA(&sc->sc_arq);
3599ccb96312Sdlg 
3600ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_arq),
3601ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_arq),
3602ccb96312Sdlg 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
3603ccb96312Sdlg 
3604ccb96312Sdlg 	do {
3605ccb96312Sdlg 		iaq = &arq[cons];
3606ccb96312Sdlg 
3607ccb96312Sdlg 		aqb = SIMPLEQ_FIRST(&sc->sc_arq_live);
360865ab43f2Syasuoka 		SIMPLEQ_REMOVE_HEAD(&sc->sc_arq_live, aqb_entry);
3609ccb96312Sdlg 		bus_dmamap_sync(sc->sc_dmat, aqb->aqb_map, 0, IXL_AQ_BUFLEN,
3610ccb96312Sdlg 		    BUS_DMASYNC_POSTREAD);
3611ccb96312Sdlg 
3612ccb96312Sdlg 		switch (iaq->iaq_opcode) {
3613ccb96312Sdlg 		case HTOLE16(IXL_AQ_OP_PHY_LINK_STATUS):
361435e06836Sdlg 			ixl_link_state_update_iaq(sc, iaq);
3615ccb96312Sdlg 			break;
3616ccb96312Sdlg 		}
3617ccb96312Sdlg 
3618ccb96312Sdlg 		memset(iaq, 0, sizeof(*iaq));
3619ccb96312Sdlg 		SIMPLEQ_INSERT_TAIL(&sc->sc_arq_idle, aqb, aqb_entry);
3620ccb96312Sdlg 		if_rxr_put(&sc->sc_arq_ring, 1);
3621ccb96312Sdlg 
3622ccb96312Sdlg 		cons++;
3623ccb96312Sdlg 		cons &= IXL_AQ_MASK;
3624ccb96312Sdlg 
3625ccb96312Sdlg 		done = 1;
3626ccb96312Sdlg 	} while (cons != prod);
3627ccb96312Sdlg 
3628ccb96312Sdlg 	if (done && ixl_arq_fill(sc))
3629ccb96312Sdlg 		ixl_wr(sc, sc->sc_aq_regs->arq_tail, sc->sc_arq_prod);
3630ccb96312Sdlg 
3631ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_arq),
3632ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_arq),
3633ccb96312Sdlg 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
3634ccb96312Sdlg 
3635ccb96312Sdlg 	sc->sc_arq_cons = cons;
3636ccb96312Sdlg 
3637ccb96312Sdlg done:
3638ccb96312Sdlg 	ixl_intr_enable(sc);
3639ccb96312Sdlg }
3640ccb96312Sdlg 
3641ccb96312Sdlg static void
ixl_atq_set(struct ixl_atq * iatq,void (* fn)(struct ixl_softc *,void *),void * arg)3642ccb96312Sdlg ixl_atq_set(struct ixl_atq *iatq,
3643ccb96312Sdlg     void (*fn)(struct ixl_softc *, void *), void *arg)
3644ccb96312Sdlg {
3645ccb96312Sdlg 	iatq->iatq_fn = fn;
3646ccb96312Sdlg 	iatq->iatq_arg = arg;
3647ccb96312Sdlg }
3648ccb96312Sdlg 
3649ccb96312Sdlg static void
ixl_atq_post(struct ixl_softc * sc,struct ixl_atq * iatq)3650ccb96312Sdlg ixl_atq_post(struct ixl_softc *sc, struct ixl_atq *iatq)
3651ccb96312Sdlg {
3652ccb96312Sdlg 	struct ixl_aq_desc *atq, *slot;
3653ccb96312Sdlg 	unsigned int prod;
3654ccb96312Sdlg 
365595f940dfSjan 	mtx_enter(&sc->sc_atq_mtx);
3656ccb96312Sdlg 
3657ccb96312Sdlg 	atq = IXL_DMA_KVA(&sc->sc_atq);
3658ccb96312Sdlg 	prod = sc->sc_atq_prod;
3659ccb96312Sdlg 	slot = atq + prod;
3660ccb96312Sdlg 
3661ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_atq),
3662ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_atq), BUS_DMASYNC_POSTWRITE);
3663ccb96312Sdlg 
3664ccb96312Sdlg 	*slot = iatq->iatq_desc;
3665ccb96312Sdlg 	slot->iaq_cookie = (uint64_t)iatq;
3666ccb96312Sdlg 
3667ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_atq),
3668ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_atq), BUS_DMASYNC_PREWRITE);
3669ccb96312Sdlg 
3670ccb96312Sdlg 	prod++;
3671ccb96312Sdlg 	prod &= IXL_AQ_MASK;
3672ccb96312Sdlg 	sc->sc_atq_prod = prod;
3673ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->atq_tail, prod);
367495f940dfSjan 
367595f940dfSjan 	mtx_leave(&sc->sc_atq_mtx);
3676ccb96312Sdlg }
3677ccb96312Sdlg 
3678ccb96312Sdlg static void
ixl_atq_done(struct ixl_softc * sc)3679ccb96312Sdlg ixl_atq_done(struct ixl_softc *sc)
3680ccb96312Sdlg {
3681ccb96312Sdlg 	struct ixl_aq_desc *atq, *slot;
3682ccb96312Sdlg 	struct ixl_atq *iatq;
3683ccb96312Sdlg 	unsigned int cons;
3684ccb96312Sdlg 	unsigned int prod;
3685ccb96312Sdlg 
368695f940dfSjan 	mtx_enter(&sc->sc_atq_mtx);
368795f940dfSjan 
3688ccb96312Sdlg 	prod = sc->sc_atq_prod;
3689ccb96312Sdlg 	cons = sc->sc_atq_cons;
3690ccb96312Sdlg 
369195f940dfSjan 	if (prod == cons) {
369295f940dfSjan 		mtx_leave(&sc->sc_atq_mtx);
3693ccb96312Sdlg 		return;
369495f940dfSjan 	}
3695ccb96312Sdlg 
3696ccb96312Sdlg 	atq = IXL_DMA_KVA(&sc->sc_atq);
3697ccb96312Sdlg 
3698ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_atq),
3699ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_atq),
3700ccb96312Sdlg 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
3701ccb96312Sdlg 
3702ccb96312Sdlg 	do {
3703ccb96312Sdlg 		slot = &atq[cons];
37043701157fSdlg 		if (!ISSET(slot->iaq_flags, htole16(IXL_AQ_DD)))
37053701157fSdlg 			break;
3706ccb96312Sdlg 
370795f940dfSjan 		KASSERT(slot->iaq_cookie != 0);
3708ccb96312Sdlg 		iatq = (struct ixl_atq *)slot->iaq_cookie;
3709ccb96312Sdlg 		iatq->iatq_desc = *slot;
3710ccb96312Sdlg 
3711ccb96312Sdlg 		memset(slot, 0, sizeof(*slot));
3712ccb96312Sdlg 
37138434af05Sdlg 		(*iatq->iatq_fn)(sc, iatq->iatq_arg);
37148434af05Sdlg 
3715ccb96312Sdlg 		cons++;
3716ccb96312Sdlg 		cons &= IXL_AQ_MASK;
3717ccb96312Sdlg 	} while (cons != prod);
3718ccb96312Sdlg 
3719ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_atq),
3720ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_atq),
3721ccb96312Sdlg 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
3722ccb96312Sdlg 
3723ccb96312Sdlg 	sc->sc_atq_cons = cons;
372495f940dfSjan 
372595f940dfSjan 	mtx_leave(&sc->sc_atq_mtx);
3726ccb96312Sdlg }
3727ccb96312Sdlg 
3728ccb96312Sdlg static void
ixl_wakeup(struct ixl_softc * sc,void * arg)3729ccb96312Sdlg ixl_wakeup(struct ixl_softc *sc, void *arg)
3730ccb96312Sdlg {
3731b661852cSdlg 	struct cond *c = arg;
3732ccb96312Sdlg 
3733b661852cSdlg 	cond_signal(c);
3734ccb96312Sdlg }
3735ccb96312Sdlg 
3736ccb96312Sdlg static void
ixl_atq_exec(struct ixl_softc * sc,struct ixl_atq * iatq,const char * wmesg)3737ccb96312Sdlg ixl_atq_exec(struct ixl_softc *sc, struct ixl_atq *iatq, const char *wmesg)
3738ccb96312Sdlg {
3739b661852cSdlg 	struct cond c = COND_INITIALIZER();
3740ccb96312Sdlg 
3741ccb96312Sdlg 	KASSERT(iatq->iatq_desc.iaq_cookie == 0);
3742ccb96312Sdlg 
3743b661852cSdlg 	ixl_atq_set(iatq, ixl_wakeup, &c);
3744ccb96312Sdlg 	ixl_atq_post(sc, iatq);
3745ccb96312Sdlg 
3746b661852cSdlg 	cond_wait(&c, wmesg);
3747ccb96312Sdlg }
3748ccb96312Sdlg 
3749ccb96312Sdlg static int
ixl_atq_poll(struct ixl_softc * sc,struct ixl_aq_desc * iaq,unsigned int tm)3750ccb96312Sdlg ixl_atq_poll(struct ixl_softc *sc, struct ixl_aq_desc *iaq, unsigned int tm)
3751ccb96312Sdlg {
3752ccb96312Sdlg 	struct ixl_aq_desc *atq, *slot;
3753ccb96312Sdlg 	unsigned int prod;
3754ccb96312Sdlg 	unsigned int t = 0;
3755ccb96312Sdlg 
375695f940dfSjan 	mtx_enter(&sc->sc_atq_mtx);
375795f940dfSjan 
3758ccb96312Sdlg 	atq = IXL_DMA_KVA(&sc->sc_atq);
3759ccb96312Sdlg 	prod = sc->sc_atq_prod;
3760ccb96312Sdlg 	slot = atq + prod;
3761ccb96312Sdlg 
3762ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_atq),
3763ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_atq), BUS_DMASYNC_POSTWRITE);
3764ccb96312Sdlg 
3765ccb96312Sdlg 	*slot = *iaq;
3766ccb96312Sdlg 	slot->iaq_flags |= htole16(IXL_AQ_SI);
3767ccb96312Sdlg 
3768ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_atq),
3769ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_atq), BUS_DMASYNC_PREWRITE);
3770ccb96312Sdlg 
3771ccb96312Sdlg 	prod++;
3772ccb96312Sdlg 	prod &= IXL_AQ_MASK;
3773ccb96312Sdlg 	sc->sc_atq_prod = prod;
3774ccb96312Sdlg 	ixl_wr(sc, sc->sc_aq_regs->atq_tail, prod);
3775ccb96312Sdlg 
3776ccb96312Sdlg 	while (ixl_rd(sc, sc->sc_aq_regs->atq_head) != prod) {
3777ccb96312Sdlg 		delaymsec(1);
3778ccb96312Sdlg 
377995f940dfSjan 		if (t++ > tm) {
378095f940dfSjan 			mtx_leave(&sc->sc_atq_mtx);
3781ccb96312Sdlg 			return (ETIMEDOUT);
3782ccb96312Sdlg 		}
378395f940dfSjan 	}
3784ccb96312Sdlg 
3785ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_atq),
3786ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_atq), BUS_DMASYNC_POSTREAD);
3787ccb96312Sdlg 	*iaq = *slot;
3788ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_atq),
3789ccb96312Sdlg 	    0, IXL_DMA_LEN(&sc->sc_atq), BUS_DMASYNC_PREREAD);
3790ccb96312Sdlg 
3791ccb96312Sdlg 	sc->sc_atq_cons = prod;
3792ccb96312Sdlg 
379395f940dfSjan 	mtx_leave(&sc->sc_atq_mtx);
3794ccb96312Sdlg 	return (0);
3795ccb96312Sdlg }
3796ccb96312Sdlg 
3797ccb96312Sdlg static int
ixl_get_version(struct ixl_softc * sc)3798ccb96312Sdlg ixl_get_version(struct ixl_softc *sc)
3799ccb96312Sdlg {
3800ccb96312Sdlg 	struct ixl_aq_desc iaq;
3801ccb96312Sdlg 	uint32_t fwbuild, fwver, apiver;
3802ccb96312Sdlg 
3803ccb96312Sdlg 	memset(&iaq, 0, sizeof(iaq));
3804ccb96312Sdlg 	iaq.iaq_opcode = htole16(IXL_AQ_OP_GET_VERSION);
3805ccb96312Sdlg 
3806ccb96312Sdlg 	if (ixl_atq_poll(sc, &iaq, 2000) != 0)
3807ccb96312Sdlg 		return (ETIMEDOUT);
3808ccb96312Sdlg 	if (iaq.iaq_retval != htole16(IXL_AQ_RC_OK))
3809ccb96312Sdlg 		return (EIO);
3810ccb96312Sdlg 
3811ccb96312Sdlg 	fwbuild = lemtoh32(&iaq.iaq_param[1]);
3812ccb96312Sdlg 	fwver = lemtoh32(&iaq.iaq_param[2]);
3813ccb96312Sdlg 	apiver = lemtoh32(&iaq.iaq_param[3]);
3814ccb96312Sdlg 
3815f5777d33Sdlg 	sc->sc_api_major = apiver & 0xffff;
3816f5777d33Sdlg 	sc->sc_api_minor = (apiver >> 16) & 0xffff;
3817f5777d33Sdlg 
3818ccb96312Sdlg 	printf(", FW %hu.%hu.%05u API %hu.%hu", (uint16_t)fwver,
3819f5777d33Sdlg 	    (uint16_t)(fwver >> 16), fwbuild,
3820f5777d33Sdlg 	    sc->sc_api_major, sc->sc_api_minor);
3821ccb96312Sdlg 
3822ccb96312Sdlg 	return (0);
3823ccb96312Sdlg }
3824ccb96312Sdlg 
3825ccb96312Sdlg static int
ixl_pxe_clear(struct ixl_softc * sc)3826ccb96312Sdlg ixl_pxe_clear(struct ixl_softc *sc)
3827ccb96312Sdlg {
3828ccb96312Sdlg 	struct ixl_aq_desc iaq;
3829ccb96312Sdlg 
3830ccb96312Sdlg 	memset(&iaq, 0, sizeof(iaq));
3831ccb96312Sdlg 	iaq.iaq_opcode = htole16(IXL_AQ_OP_CLEAR_PXE_MODE);
3832ccb96312Sdlg 	iaq.iaq_param[0] = htole32(0x2);
3833ccb96312Sdlg 
3834ccb96312Sdlg 	if (ixl_atq_poll(sc, &iaq, 250) != 0) {
3835ccb96312Sdlg 		printf(", CLEAR PXE MODE timeout\n");
3836ccb96312Sdlg 		return (-1);
3837ccb96312Sdlg 	}
3838ccb96312Sdlg 
3839ccb96312Sdlg 	switch (iaq.iaq_retval) {
3840ccb96312Sdlg 	case HTOLE16(IXL_AQ_RC_OK):
3841ccb96312Sdlg 	case HTOLE16(IXL_AQ_RC_EEXIST):
3842ccb96312Sdlg 		break;
3843ccb96312Sdlg 	default:
3844ccb96312Sdlg 		printf(", CLEAR PXE MODE error\n");
3845ccb96312Sdlg 		return (-1);
3846ccb96312Sdlg 	}
3847ccb96312Sdlg 
3848ccb96312Sdlg 	return (0);
3849ccb96312Sdlg }
3850ccb96312Sdlg 
3851ccb96312Sdlg static int
ixl_lldp_shut(struct ixl_softc * sc)3852ccb96312Sdlg ixl_lldp_shut(struct ixl_softc *sc)
3853ccb96312Sdlg {
3854ccb96312Sdlg 	struct ixl_aq_desc iaq;
3855ccb96312Sdlg 
3856ccb96312Sdlg 	memset(&iaq, 0, sizeof(iaq));
3857ccb96312Sdlg 	iaq.iaq_opcode = htole16(IXL_AQ_OP_LLDP_STOP_AGENT);
3858ccb96312Sdlg 	iaq.iaq_param[0] = htole32(IXL_LLDP_SHUTDOWN);
3859ccb96312Sdlg 
3860ccb96312Sdlg 	if (ixl_atq_poll(sc, &iaq, 250) != 0) {
3861ccb96312Sdlg 		printf(", STOP LLDP AGENT timeout\n");
3862ccb96312Sdlg 		return (-1);
3863ccb96312Sdlg 	}
3864ccb96312Sdlg 
3865ccb96312Sdlg 	switch (iaq.iaq_retval) {
3866ccb96312Sdlg 	case HTOLE16(IXL_AQ_RC_EMODE):
3867ccb96312Sdlg 	case HTOLE16(IXL_AQ_RC_EPERM):
3868ccb96312Sdlg 		/* ignore silently */
3869ccb96312Sdlg 	default:
3870ccb96312Sdlg 		break;
3871ccb96312Sdlg 	}
3872ccb96312Sdlg 
3873ccb96312Sdlg 	return (0);
3874ccb96312Sdlg }
3875ccb96312Sdlg 
3876ccb96312Sdlg static int
ixl_get_mac(struct ixl_softc * sc)3877ccb96312Sdlg ixl_get_mac(struct ixl_softc *sc)
3878ccb96312Sdlg {
3879ccb96312Sdlg 	struct ixl_dmamem idm;
3880ccb96312Sdlg 	struct ixl_aq_desc iaq;
3881ccb96312Sdlg 	struct ixl_aq_mac_addresses *addrs;
3882ccb96312Sdlg 	int rv;
3883ccb96312Sdlg 
388412b3627cSjmatthew #ifdef __sparc64__
388512b3627cSjmatthew 	if (OF_getprop(PCITAG_NODE(sc->sc_tag), "local-mac-address",
388612b3627cSjmatthew 	    sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN) == ETHER_ADDR_LEN)
388712b3627cSjmatthew 		return (0);
388812b3627cSjmatthew #endif
388912b3627cSjmatthew 
3890ccb96312Sdlg 	if (ixl_dmamem_alloc(sc, &idm, sizeof(*addrs), 0) != 0) {
3891ccb96312Sdlg 		printf(", unable to allocate mac addresses\n");
3892ccb96312Sdlg 		return (-1);
3893ccb96312Sdlg 	}
3894ccb96312Sdlg 
3895ccb96312Sdlg 	memset(&iaq, 0, sizeof(iaq));
3896ccb96312Sdlg 	iaq.iaq_flags = htole16(IXL_AQ_BUF);
3897ccb96312Sdlg 	iaq.iaq_opcode = htole16(IXL_AQ_OP_MAC_ADDRESS_READ);
3898ccb96312Sdlg 	iaq.iaq_datalen = htole16(sizeof(*addrs));
3899ccb96312Sdlg 	ixl_aq_dva(&iaq, IXL_DMA_DVA(&idm));
3900ccb96312Sdlg 
3901ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&idm), 0, IXL_DMA_LEN(&idm),
3902ccb96312Sdlg 	    BUS_DMASYNC_PREREAD);
3903ccb96312Sdlg 
3904ccb96312Sdlg 	rv = ixl_atq_poll(sc, &iaq, 250);
3905ccb96312Sdlg 
3906ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&idm), 0, IXL_DMA_LEN(&idm),
3907ccb96312Sdlg 	    BUS_DMASYNC_POSTREAD);
3908ccb96312Sdlg 
3909ccb96312Sdlg 	if (rv != 0) {
3910ccb96312Sdlg 		printf(", MAC ADDRESS READ timeout\n");
3911ccb96312Sdlg 		rv = -1;
3912ccb96312Sdlg 		goto done;
3913ccb96312Sdlg 	}
3914ccb96312Sdlg 	if (iaq.iaq_retval != htole16(IXL_AQ_RC_OK)) {
3915ccb96312Sdlg 		printf(", MAC ADDRESS READ error\n");
3916ccb96312Sdlg 		rv = -1;
3917ccb96312Sdlg 		goto done;
3918ccb96312Sdlg 	}
3919ccb96312Sdlg 
3920ccb96312Sdlg 	addrs = IXL_DMA_KVA(&idm);
3921ccb96312Sdlg 	if (!ISSET(iaq.iaq_param[0], htole32(IXL_AQ_MAC_PORT_VALID))) {
3922ccb96312Sdlg 		printf(", port address is not valid\n");
3923ccb96312Sdlg 		goto done;
3924ccb96312Sdlg 	}
3925ccb96312Sdlg 
3926ccb96312Sdlg 	memcpy(sc->sc_ac.ac_enaddr, addrs->port, ETHER_ADDR_LEN);
3927ccb96312Sdlg 	rv = 0;
3928ccb96312Sdlg 
3929ccb96312Sdlg done:
3930ccb96312Sdlg 	ixl_dmamem_free(sc, &idm);
3931ccb96312Sdlg 	return (rv);
3932ccb96312Sdlg }
3933ccb96312Sdlg 
3934ccb96312Sdlg static int
ixl_get_switch_config(struct ixl_softc * sc)3935ccb96312Sdlg ixl_get_switch_config(struct ixl_softc *sc)
3936ccb96312Sdlg {
3937ccb96312Sdlg 	struct ixl_dmamem idm;
3938ccb96312Sdlg 	struct ixl_aq_desc iaq;
3939ccb96312Sdlg 	struct ixl_aq_switch_config *hdr;
3940ccb96312Sdlg 	struct ixl_aq_switch_config_element *elms, *elm;
3941ccb96312Sdlg 	unsigned int nelm;
3942ccb96312Sdlg 	int rv;
3943ccb96312Sdlg 
3944ccb96312Sdlg 	if (ixl_dmamem_alloc(sc, &idm, IXL_AQ_BUFLEN, 0) != 0) {
3945ccb96312Sdlg 		printf("%s: unable to allocate switch config buffer\n",
3946ccb96312Sdlg 		    DEVNAME(sc));
3947ccb96312Sdlg 		return (-1);
3948ccb96312Sdlg 	}
3949ccb96312Sdlg 
3950ccb96312Sdlg 	memset(&iaq, 0, sizeof(iaq));
3951ccb96312Sdlg 	iaq.iaq_flags = htole16(IXL_AQ_BUF |
3952ccb96312Sdlg 	    (IXL_AQ_BUFLEN > I40E_AQ_LARGE_BUF ? IXL_AQ_LB : 0));
3953ccb96312Sdlg 	iaq.iaq_opcode = htole16(IXL_AQ_OP_SWITCH_GET_CONFIG);
3954ccb96312Sdlg 	iaq.iaq_datalen = htole16(IXL_AQ_BUFLEN);
3955ccb96312Sdlg 	ixl_aq_dva(&iaq, IXL_DMA_DVA(&idm));
3956ccb96312Sdlg 
3957ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&idm), 0, IXL_DMA_LEN(&idm),
3958ccb96312Sdlg 	    BUS_DMASYNC_PREREAD);
3959ccb96312Sdlg 
3960ccb96312Sdlg 	rv = ixl_atq_poll(sc, &iaq, 250);
3961ccb96312Sdlg 
3962ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&idm), 0, IXL_DMA_LEN(&idm),
3963ccb96312Sdlg 	    BUS_DMASYNC_POSTREAD);
3964ccb96312Sdlg 
3965ccb96312Sdlg 	if (rv != 0) {
3966ccb96312Sdlg 		printf("%s: GET SWITCH CONFIG timeout\n", DEVNAME(sc));
3967ccb96312Sdlg 		rv = -1;
3968ccb96312Sdlg 		goto done;
3969ccb96312Sdlg 	}
3970ccb96312Sdlg 	if (iaq.iaq_retval != htole16(IXL_AQ_RC_OK)) {
3971ccb96312Sdlg 		printf("%s: GET SWITCH CONFIG error\n", DEVNAME(sc));
3972ccb96312Sdlg 		rv = -1;
3973ccb96312Sdlg 		goto done;
3974ccb96312Sdlg 	}
3975ccb96312Sdlg 
3976ccb96312Sdlg 	hdr = IXL_DMA_KVA(&idm);
3977ccb96312Sdlg 	elms = (struct ixl_aq_switch_config_element *)(hdr + 1);
3978ccb96312Sdlg 
3979ccb96312Sdlg 	nelm = lemtoh16(&hdr->num_reported);
3980ccb96312Sdlg 	if (nelm < 1) {
3981ccb96312Sdlg 		printf("%s: no switch config available\n", DEVNAME(sc));
3982ccb96312Sdlg 		rv = -1;
3983ccb96312Sdlg 		goto done;
3984ccb96312Sdlg 	}
3985ccb96312Sdlg 
3986ccb96312Sdlg #if 0
3987ccb96312Sdlg 	for (i = 0; i < nelm; i++) {
3988ccb96312Sdlg 		elm = &elms[i];
3989ccb96312Sdlg 
3990ccb96312Sdlg 		printf("%s: type %x revision %u seid %04x\n", DEVNAME(sc),
3991ccb96312Sdlg 		    elm->type, elm->revision, lemtoh16(&elm->seid));
3992ccb96312Sdlg 		printf("%s: uplink %04x downlink %04x\n", DEVNAME(sc),
3993ccb96312Sdlg 		    lemtoh16(&elm->uplink_seid),
3994ccb96312Sdlg 		    lemtoh16(&elm->downlink_seid));
3995ccb96312Sdlg 		printf("%s: conntype %x scheduler %04x extra %04x\n",
3996ccb96312Sdlg 		    DEVNAME(sc), elm->connection_type,
3997ccb96312Sdlg 		    lemtoh16(&elm->scheduler_id),
3998ccb96312Sdlg 		    lemtoh16(&elm->element_info));
3999ccb96312Sdlg 	}
4000ccb96312Sdlg #endif
4001ccb96312Sdlg 
4002ccb96312Sdlg 	elm = &elms[0];
4003ccb96312Sdlg 
4004ccb96312Sdlg 	sc->sc_uplink_seid = elm->uplink_seid;
4005ccb96312Sdlg 	sc->sc_downlink_seid = elm->downlink_seid;
4006ccb96312Sdlg 	sc->sc_seid = elm->seid;
4007ccb96312Sdlg 
4008ccb96312Sdlg 	if ((sc->sc_uplink_seid == htole16(0)) !=
4009ccb96312Sdlg 	    (sc->sc_downlink_seid == htole16(0))) {
4010ccb96312Sdlg 		printf("%s: SEIDs are misconfigured\n", DEVNAME(sc));
4011ccb96312Sdlg 		rv = -1;
4012ccb96312Sdlg 		goto done;
4013ccb96312Sdlg 	}
4014ccb96312Sdlg 
4015ccb96312Sdlg done:
4016ccb96312Sdlg 	ixl_dmamem_free(sc, &idm);
4017ccb96312Sdlg 	return (rv);
4018ccb96312Sdlg }
4019ccb96312Sdlg 
4020ccb96312Sdlg static int
ixl_phy_mask_ints(struct ixl_softc * sc)4021ccb96312Sdlg ixl_phy_mask_ints(struct ixl_softc *sc)
4022ccb96312Sdlg {
4023ccb96312Sdlg 	struct ixl_aq_desc iaq;
4024ccb96312Sdlg 
4025ccb96312Sdlg 	memset(&iaq, 0, sizeof(iaq));
4026ccb96312Sdlg 	iaq.iaq_opcode = htole16(IXL_AQ_OP_PHY_SET_EVENT_MASK);
4027ccb96312Sdlg 	iaq.iaq_param[2] = htole32(IXL_AQ_PHY_EV_MASK &
4028ccb96312Sdlg 	    ~(IXL_AQ_PHY_EV_LINK_UPDOWN | IXL_AQ_PHY_EV_MODULE_QUAL_FAIL |
4029ccb96312Sdlg 	      IXL_AQ_PHY_EV_MEDIA_NA));
4030ccb96312Sdlg 
4031ccb96312Sdlg 	if (ixl_atq_poll(sc, &iaq, 250) != 0) {
4032ccb96312Sdlg 		printf("%s: SET PHY EVENT MASK timeout\n", DEVNAME(sc));
4033ccb96312Sdlg 		return (-1);
4034ccb96312Sdlg 	}
4035ccb96312Sdlg 	if (iaq.iaq_retval != htole16(IXL_AQ_RC_OK)) {
4036ccb96312Sdlg 		printf("%s: SET PHY EVENT MASK error\n", DEVNAME(sc));
4037ccb96312Sdlg 		return (-1);
4038ccb96312Sdlg 	}
4039ccb96312Sdlg 
4040ccb96312Sdlg 	return (0);
4041ccb96312Sdlg }
4042ccb96312Sdlg 
4043ccb96312Sdlg static int
ixl_get_phy_abilities(struct ixl_softc * sc,struct ixl_dmamem * idm)404425fbbcc0Sdlg ixl_get_phy_abilities(struct ixl_softc *sc,struct ixl_dmamem *idm)
404525fbbcc0Sdlg {
404625fbbcc0Sdlg 	struct ixl_aq_desc iaq;
404725fbbcc0Sdlg 	int rv;
404825fbbcc0Sdlg 
404925fbbcc0Sdlg 	memset(&iaq, 0, sizeof(iaq));
405025fbbcc0Sdlg 	iaq.iaq_flags = htole16(IXL_AQ_BUF |
405125fbbcc0Sdlg 	    (IXL_DMA_LEN(idm) > I40E_AQ_LARGE_BUF ? IXL_AQ_LB : 0));
405225fbbcc0Sdlg 	iaq.iaq_opcode = htole16(IXL_AQ_OP_PHY_GET_ABILITIES);
405325fbbcc0Sdlg 	htolem16(&iaq.iaq_datalen, IXL_DMA_LEN(idm));
405425fbbcc0Sdlg 	iaq.iaq_param[0] = htole32(IXL_AQ_PHY_REPORT_INIT);
405525fbbcc0Sdlg 	ixl_aq_dva(&iaq, IXL_DMA_DVA(idm));
405625fbbcc0Sdlg 
405725fbbcc0Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(idm), 0, IXL_DMA_LEN(idm),
405825fbbcc0Sdlg 	    BUS_DMASYNC_PREREAD);
405925fbbcc0Sdlg 
406025fbbcc0Sdlg 	rv = ixl_atq_poll(sc, &iaq, 250);
406125fbbcc0Sdlg 
406225fbbcc0Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(idm), 0, IXL_DMA_LEN(idm),
406325fbbcc0Sdlg 	    BUS_DMASYNC_POSTREAD);
406425fbbcc0Sdlg 
406525fbbcc0Sdlg 	if (rv != 0)
406625fbbcc0Sdlg 		return (-1);
406725fbbcc0Sdlg 
406825fbbcc0Sdlg 	return (lemtoh16(&iaq.iaq_retval));
406925fbbcc0Sdlg }
407025fbbcc0Sdlg 
407125fbbcc0Sdlg static int
ixl_get_phy_types(struct ixl_softc * sc,uint64_t * phy_types_ptr)407225fbbcc0Sdlg ixl_get_phy_types(struct ixl_softc *sc, uint64_t *phy_types_ptr)
4073ccb96312Sdlg {
4074ccb96312Sdlg 	struct ixl_dmamem idm;
4075ccb96312Sdlg 	struct ixl_aq_phy_abilities *phy;
4076ccb96312Sdlg 	uint64_t phy_types;
4077ccb96312Sdlg 	int rv;
4078ccb96312Sdlg 
4079ccb96312Sdlg 	if (ixl_dmamem_alloc(sc, &idm, IXL_AQ_BUFLEN, 0) != 0) {
4080ae4c4765Sdlg 		printf("%s: unable to allocate phy abilities buffer\n",
4081ccb96312Sdlg 		    DEVNAME(sc));
4082ccb96312Sdlg 		return (-1);
4083ccb96312Sdlg 	}
4084ccb96312Sdlg 
408525fbbcc0Sdlg 	rv = ixl_get_phy_abilities(sc, &idm);
408625fbbcc0Sdlg 	switch (rv) {
408725fbbcc0Sdlg 	case -1:
4088ccb96312Sdlg 		printf("%s: GET PHY ABILITIES timeout\n", DEVNAME(sc));
40894497d183Sdlg 		goto err;
409025fbbcc0Sdlg 	case IXL_AQ_RC_OK:
4091ccb96312Sdlg 		break;
409225fbbcc0Sdlg 	case IXL_AQ_RC_EIO:
40934497d183Sdlg 		/* API is too old to handle this command */
40944497d183Sdlg 		phy_types = 0;
40954497d183Sdlg 		goto done;
4096ccb96312Sdlg 	default:
40974b1a56afSjsg 		printf("%s: GET PHY ABILITIES error %u\n", DEVNAME(sc), rv);
40984497d183Sdlg 		goto err;
4099ccb96312Sdlg 	}
4100ccb96312Sdlg 
4101ccb96312Sdlg 	phy = IXL_DMA_KVA(&idm);
4102ccb96312Sdlg 
4103ccb96312Sdlg 	phy_types = lemtoh32(&phy->phy_type);
41047e7a8c99Sdlg 	phy_types |= (uint64_t)phy->phy_type_ext << 32;
4105ccb96312Sdlg 
41064497d183Sdlg done:
4107ccb96312Sdlg 	*phy_types_ptr = phy_types;
4108ccb96312Sdlg 
4109ccb96312Sdlg 	rv = 0;
4110ccb96312Sdlg 
41114497d183Sdlg err:
4112ccb96312Sdlg 	ixl_dmamem_free(sc, &idm);
4113ccb96312Sdlg 	return (rv);
4114ccb96312Sdlg }
4115ccb96312Sdlg 
41161d70c39eSdlg /*
41171d70c39eSdlg  * this returns -2 on software/driver failure, -1 for problems
41181d70c39eSdlg  * talking to the hardware, or the sff module type.
41191d70c39eSdlg  */
41201d70c39eSdlg 
412125fbbcc0Sdlg static int
ixl_get_module_type(struct ixl_softc * sc)412225fbbcc0Sdlg ixl_get_module_type(struct ixl_softc *sc)
412325fbbcc0Sdlg {
412425fbbcc0Sdlg 	struct ixl_dmamem idm;
412525fbbcc0Sdlg 	struct ixl_aq_phy_abilities *phy;
412625fbbcc0Sdlg 	int rv;
412725fbbcc0Sdlg 
412825fbbcc0Sdlg 	if (ixl_dmamem_alloc(sc, &idm, IXL_AQ_BUFLEN, 0) != 0)
41291d70c39eSdlg 		return (-2);
413025fbbcc0Sdlg 
413125fbbcc0Sdlg 	rv = ixl_get_phy_abilities(sc, &idm);
413225fbbcc0Sdlg 	if (rv != IXL_AQ_RC_OK) {
413325fbbcc0Sdlg 		rv = -1;
413425fbbcc0Sdlg 		goto done;
413525fbbcc0Sdlg 	}
413625fbbcc0Sdlg 
413725fbbcc0Sdlg 	phy = IXL_DMA_KVA(&idm);
413825fbbcc0Sdlg 
413925fbbcc0Sdlg 	rv = phy->module_type[0];
414025fbbcc0Sdlg 
414125fbbcc0Sdlg done:
414225fbbcc0Sdlg 	ixl_dmamem_free(sc, &idm);
414325fbbcc0Sdlg 	return (rv);
414425fbbcc0Sdlg }
414525fbbcc0Sdlg 
4146ccb96312Sdlg static int
ixl_get_link_status(struct ixl_softc * sc)4147ccb96312Sdlg ixl_get_link_status(struct ixl_softc *sc)
4148ccb96312Sdlg {
4149ccb96312Sdlg 	struct ixl_aq_desc iaq;
41507f4b2a0fSjmatthew 	struct ixl_aq_link_param *param;
4151ccb96312Sdlg 
4152ccb96312Sdlg 	memset(&iaq, 0, sizeof(iaq));
4153ccb96312Sdlg 	iaq.iaq_opcode = htole16(IXL_AQ_OP_PHY_LINK_STATUS);
41547f4b2a0fSjmatthew 	param = (struct ixl_aq_link_param *)iaq.iaq_param;
41557f4b2a0fSjmatthew 	param->notify = IXL_AQ_LINK_NOTIFY;
4156ccb96312Sdlg 
4157ccb96312Sdlg 	if (ixl_atq_poll(sc, &iaq, 250) != 0) {
4158ccb96312Sdlg 		printf("%s: GET LINK STATUS timeout\n", DEVNAME(sc));
4159ccb96312Sdlg 		return (-1);
4160ccb96312Sdlg 	}
4161ccb96312Sdlg 	if (iaq.iaq_retval != htole16(IXL_AQ_RC_OK)) {
4162ccb96312Sdlg 		printf("%s: GET LINK STATUS error\n", DEVNAME(sc));
4163ccb96312Sdlg 		return (0);
4164ccb96312Sdlg 	}
4165ccb96312Sdlg 
4166ccb96312Sdlg 	sc->sc_ac.ac_if.if_link_state = ixl_set_link_status(sc, &iaq);
4167ccb96312Sdlg 
4168ccb96312Sdlg 	return (0);
4169ccb96312Sdlg }
4170ccb96312Sdlg 
417125fbbcc0Sdlg struct ixl_sff_ops {
417225fbbcc0Sdlg 	int (*open)(struct ixl_softc *sc, struct if_sffpage *, uint8_t *);
417325fbbcc0Sdlg 	int (*get)(struct ixl_softc *sc, struct if_sffpage *, size_t);
417425fbbcc0Sdlg 	int (*close)(struct ixl_softc *sc, struct if_sffpage *, uint8_t);
417525fbbcc0Sdlg };
417625fbbcc0Sdlg 
417725fbbcc0Sdlg static int
ixl_sfp_open(struct ixl_softc * sc,struct if_sffpage * sff,uint8_t * page)417825fbbcc0Sdlg ixl_sfp_open(struct ixl_softc *sc, struct if_sffpage *sff, uint8_t *page)
417925fbbcc0Sdlg {
418025fbbcc0Sdlg 	int error;
418125fbbcc0Sdlg 
418225fbbcc0Sdlg 	if (sff->sff_addr != IFSFF_ADDR_EEPROM)
418325fbbcc0Sdlg 		return (0);
418425fbbcc0Sdlg 
418525fbbcc0Sdlg 	error = ixl_sff_get_byte(sc, IFSFF_ADDR_EEPROM, 127, page);
418625fbbcc0Sdlg 	if (error != 0)
418725fbbcc0Sdlg 		return (error);
418825fbbcc0Sdlg 	if (*page == sff->sff_page)
418925fbbcc0Sdlg 		return (0);
419025fbbcc0Sdlg 	error = ixl_sff_set_byte(sc, IFSFF_ADDR_EEPROM, 127, sff->sff_page);
419125fbbcc0Sdlg 	if (error != 0)
419225fbbcc0Sdlg 		return (error);
419325fbbcc0Sdlg 
419425fbbcc0Sdlg 	return (0);
419525fbbcc0Sdlg }
419625fbbcc0Sdlg 
419725fbbcc0Sdlg static int
ixl_sfp_get(struct ixl_softc * sc,struct if_sffpage * sff,size_t i)419825fbbcc0Sdlg ixl_sfp_get(struct ixl_softc *sc, struct if_sffpage *sff, size_t i)
419925fbbcc0Sdlg {
420025fbbcc0Sdlg 	return (ixl_sff_get_byte(sc, sff->sff_addr, i, &sff->sff_data[i]));
420125fbbcc0Sdlg }
420225fbbcc0Sdlg 
420325fbbcc0Sdlg static int
ixl_sfp_close(struct ixl_softc * sc,struct if_sffpage * sff,uint8_t page)420425fbbcc0Sdlg ixl_sfp_close(struct ixl_softc *sc, struct if_sffpage *sff, uint8_t page)
420525fbbcc0Sdlg {
420625fbbcc0Sdlg 	int error;
420725fbbcc0Sdlg 
420825fbbcc0Sdlg 	if (sff->sff_addr != IFSFF_ADDR_EEPROM)
420925fbbcc0Sdlg 		return (0);
421025fbbcc0Sdlg 
421125fbbcc0Sdlg 	if (page == sff->sff_page)
421225fbbcc0Sdlg 		return (0);
421325fbbcc0Sdlg 
421425fbbcc0Sdlg 	error = ixl_sff_set_byte(sc, IFSFF_ADDR_EEPROM, 127, page);
421525fbbcc0Sdlg 	if (error != 0)
421625fbbcc0Sdlg 		return (error);
421725fbbcc0Sdlg 
421825fbbcc0Sdlg 	return (0);
421925fbbcc0Sdlg }
422025fbbcc0Sdlg 
422125fbbcc0Sdlg static const struct ixl_sff_ops ixl_sfp_ops = {
422225fbbcc0Sdlg 	ixl_sfp_open,
422325fbbcc0Sdlg 	ixl_sfp_get,
422425fbbcc0Sdlg 	ixl_sfp_close,
422525fbbcc0Sdlg };
422625fbbcc0Sdlg 
422725fbbcc0Sdlg static int
ixl_qsfp_open(struct ixl_softc * sc,struct if_sffpage * sff,uint8_t * page)422825fbbcc0Sdlg ixl_qsfp_open(struct ixl_softc *sc, struct if_sffpage *sff, uint8_t *page)
422925fbbcc0Sdlg {
423025fbbcc0Sdlg 	if (sff->sff_addr != IFSFF_ADDR_EEPROM)
423125fbbcc0Sdlg 		return (EIO);
423225fbbcc0Sdlg 
423325fbbcc0Sdlg 	return (0);
423425fbbcc0Sdlg }
423525fbbcc0Sdlg 
423625fbbcc0Sdlg static int
ixl_qsfp_get(struct ixl_softc * sc,struct if_sffpage * sff,size_t i)423725fbbcc0Sdlg ixl_qsfp_get(struct ixl_softc *sc, struct if_sffpage *sff, size_t i)
423825fbbcc0Sdlg {
423925fbbcc0Sdlg 	return (ixl_sff_get_byte(sc, sff->sff_page, i, &sff->sff_data[i]));
424025fbbcc0Sdlg }
424125fbbcc0Sdlg 
424225fbbcc0Sdlg static int
ixl_qsfp_close(struct ixl_softc * sc,struct if_sffpage * sff,uint8_t page)424325fbbcc0Sdlg ixl_qsfp_close(struct ixl_softc *sc, struct if_sffpage *sff, uint8_t page)
424425fbbcc0Sdlg {
424525fbbcc0Sdlg 	return (0);
424625fbbcc0Sdlg }
424725fbbcc0Sdlg 
424825fbbcc0Sdlg static const struct ixl_sff_ops ixl_qsfp_ops = {
424925fbbcc0Sdlg 	ixl_qsfp_open,
425025fbbcc0Sdlg 	ixl_qsfp_get,
425125fbbcc0Sdlg 	ixl_qsfp_close,
425225fbbcc0Sdlg };
425325fbbcc0Sdlg 
4254ccb96312Sdlg static int
ixl_get_sffpage(struct ixl_softc * sc,struct if_sffpage * sff)42554eec9beaSdlg ixl_get_sffpage(struct ixl_softc *sc, struct if_sffpage *sff)
42564eec9beaSdlg {
425725fbbcc0Sdlg 	const struct ixl_sff_ops *ops;
425825fbbcc0Sdlg 	uint8_t page;
42594eec9beaSdlg 	size_t i;
42604eec9beaSdlg 	int error;
42614eec9beaSdlg 
426225fbbcc0Sdlg 	switch (ixl_get_module_type(sc)) {
42631d70c39eSdlg 	case -2:
42641d70c39eSdlg 		return (ENOMEM);
426525fbbcc0Sdlg 	case -1:
42661d70c39eSdlg 		return (ENXIO);
426725fbbcc0Sdlg 	case IXL_SFF8024_ID_SFP:
426825fbbcc0Sdlg 		ops = &ixl_sfp_ops;
426925fbbcc0Sdlg 		break;
427025fbbcc0Sdlg 	case IXL_SFF8024_ID_QSFP:
427125fbbcc0Sdlg 	case IXL_SFF8024_ID_QSFP_PLUS:
427225fbbcc0Sdlg 	case IXL_SFF8024_ID_QSFP28:
427325fbbcc0Sdlg 		ops = &ixl_qsfp_ops;
427425fbbcc0Sdlg 		break;
427525fbbcc0Sdlg 	default:
427625fbbcc0Sdlg 		return (EOPNOTSUPP);
427725fbbcc0Sdlg 	}
427825fbbcc0Sdlg 
427925fbbcc0Sdlg 	error = (*ops->open)(sc, sff, &page);
42804eec9beaSdlg 	if (error != 0)
42814eec9beaSdlg 		return (error);
42824eec9beaSdlg 
42834eec9beaSdlg 	for (i = 0; i < sizeof(sff->sff_data); i++) {
428425fbbcc0Sdlg 		error = (*ops->get)(sc, sff, i);
42854eec9beaSdlg 		if (error != 0)
42864eec9beaSdlg 			return (error);
42874eec9beaSdlg 	}
42884eec9beaSdlg 
428925fbbcc0Sdlg 	error = (*ops->close)(sc, sff, page);
42904eec9beaSdlg 
42914eec9beaSdlg 	return (0);
42924eec9beaSdlg }
42934eec9beaSdlg 
42944eec9beaSdlg static int
ixl_sff_get_byte(struct ixl_softc * sc,uint8_t dev,uint32_t reg,uint8_t * p)42954eec9beaSdlg ixl_sff_get_byte(struct ixl_softc *sc, uint8_t dev, uint32_t reg, uint8_t *p)
42964eec9beaSdlg {
42974eec9beaSdlg 	struct ixl_atq iatq;
42984eec9beaSdlg 	struct ixl_aq_desc *iaq;
42994eec9beaSdlg 	struct ixl_aq_phy_reg_access *param;
43004eec9beaSdlg 
43014eec9beaSdlg 	memset(&iatq, 0, sizeof(iatq));
43024eec9beaSdlg 	iaq = &iatq.iatq_desc;
43034eec9beaSdlg 	iaq->iaq_opcode = htole16(IXL_AQ_OP_PHY_GET_REGISTER);
43044eec9beaSdlg 	param = (struct ixl_aq_phy_reg_access *)iaq->iaq_param;
43054eec9beaSdlg 	param->phy_iface = IXL_AQ_PHY_IF_MODULE;
43064eec9beaSdlg 	param->dev_addr = dev;
43074eec9beaSdlg 	htolem32(&param->reg, reg);
43084eec9beaSdlg 
43094eec9beaSdlg 	ixl_atq_exec(sc, &iatq, "ixlsffget");
43104eec9beaSdlg 
431199da00d3Sdlg 	if (ISSET(sc->sc_ac.ac_if.if_flags, IFF_DEBUG)) {
431299da00d3Sdlg 		printf("%s: %s(dev 0x%02x, reg 0x%02x) -> %04x\n",
431399da00d3Sdlg 		    DEVNAME(sc), __func__,
431499da00d3Sdlg 		    dev, reg, lemtoh16(&iaq->iaq_retval));
431599da00d3Sdlg 	}
431699da00d3Sdlg 
43174eec9beaSdlg 	switch (iaq->iaq_retval) {
43184eec9beaSdlg 	case htole16(IXL_AQ_RC_OK):
43194eec9beaSdlg 		break;
43204eec9beaSdlg 	case htole16(IXL_AQ_RC_EBUSY):
43214eec9beaSdlg 		return (EBUSY);
43224eec9beaSdlg 	case htole16(IXL_AQ_RC_ESRCH):
43234eec9beaSdlg 		return (ENODEV);
43244eec9beaSdlg 	case htole16(IXL_AQ_RC_EIO):
43254eec9beaSdlg 	case htole16(IXL_AQ_RC_EINVAL):
43264eec9beaSdlg 	default:
43274eec9beaSdlg 		return (EIO);
43284eec9beaSdlg 	}
43294eec9beaSdlg 
43304eec9beaSdlg 	*p = lemtoh32(&param->val);
43314eec9beaSdlg 
43324eec9beaSdlg 	return (0);
43334eec9beaSdlg }
43344eec9beaSdlg 
43354eec9beaSdlg static int
ixl_sff_set_byte(struct ixl_softc * sc,uint8_t dev,uint32_t reg,uint8_t v)43364eec9beaSdlg ixl_sff_set_byte(struct ixl_softc *sc, uint8_t dev, uint32_t reg, uint8_t v)
43374eec9beaSdlg {
43384eec9beaSdlg 	struct ixl_atq iatq;
43394eec9beaSdlg 	struct ixl_aq_desc *iaq;
43404eec9beaSdlg 	struct ixl_aq_phy_reg_access *param;
43414eec9beaSdlg 
43424eec9beaSdlg 	memset(&iatq, 0, sizeof(iatq));
43434eec9beaSdlg 	iaq = &iatq.iatq_desc;
43444eec9beaSdlg 	iaq->iaq_opcode = htole16(IXL_AQ_OP_PHY_SET_REGISTER);
43454eec9beaSdlg 	param = (struct ixl_aq_phy_reg_access *)iaq->iaq_param;
43464eec9beaSdlg 	param->phy_iface = IXL_AQ_PHY_IF_MODULE;
43474eec9beaSdlg 	param->dev_addr = dev;
43484eec9beaSdlg 	htolem32(&param->reg, reg);
43494eec9beaSdlg 	htolem32(&param->val, v);
43504eec9beaSdlg 
43514eec9beaSdlg 	ixl_atq_exec(sc, &iatq, "ixlsffset");
43524eec9beaSdlg 
435399da00d3Sdlg 	if (ISSET(sc->sc_ac.ac_if.if_flags, IFF_DEBUG)) {
435499da00d3Sdlg 		printf("%s: %s(dev 0x%02x, reg 0x%02x, val 0x%02x) -> %04x\n",
435599da00d3Sdlg 		    DEVNAME(sc), __func__,
435699da00d3Sdlg 		    dev, reg, v, lemtoh16(&iaq->iaq_retval));
435799da00d3Sdlg 	}
435899da00d3Sdlg 
43594eec9beaSdlg 	switch (iaq->iaq_retval) {
43604eec9beaSdlg 	case htole16(IXL_AQ_RC_OK):
43614eec9beaSdlg 		break;
43624eec9beaSdlg 	case htole16(IXL_AQ_RC_EBUSY):
43634eec9beaSdlg 		return (EBUSY);
43644eec9beaSdlg 	case htole16(IXL_AQ_RC_ESRCH):
43654eec9beaSdlg 		return (ENODEV);
43664eec9beaSdlg 	case htole16(IXL_AQ_RC_EIO):
43674eec9beaSdlg 	case htole16(IXL_AQ_RC_EINVAL):
43684eec9beaSdlg 	default:
43694eec9beaSdlg 		return (EIO);
43704eec9beaSdlg 	}
43714eec9beaSdlg 
43724eec9beaSdlg 	return (0);
43734eec9beaSdlg }
43744eec9beaSdlg 
43754eec9beaSdlg static int
ixl_get_vsi(struct ixl_softc * sc)4376ccb96312Sdlg ixl_get_vsi(struct ixl_softc *sc)
4377ccb96312Sdlg {
43782bb8400cSjmatthew 	struct ixl_dmamem *vsi = &sc->sc_scratch;
4379ccb96312Sdlg 	struct ixl_aq_desc iaq;
4380ccb96312Sdlg 	struct ixl_aq_vsi_param *param;
4381ccb96312Sdlg 	struct ixl_aq_vsi_reply *reply;
4382ccb96312Sdlg 	int rv;
4383ccb96312Sdlg 
4384ccb96312Sdlg 	/* grumble, vsi info isn't "known" at compile time */
4385ccb96312Sdlg 
4386ccb96312Sdlg 	memset(&iaq, 0, sizeof(iaq));
4387ccb96312Sdlg 	htolem16(&iaq.iaq_flags, IXL_AQ_BUF |
4388ccb96312Sdlg 	    (IXL_DMA_LEN(vsi) > I40E_AQ_LARGE_BUF ? IXL_AQ_LB : 0));
4389ccb96312Sdlg 	iaq.iaq_opcode = htole16(IXL_AQ_OP_GET_VSI_PARAMS);
4390ccb96312Sdlg 	htolem16(&iaq.iaq_datalen, IXL_DMA_LEN(vsi));
4391ccb96312Sdlg 	ixl_aq_dva(&iaq, IXL_DMA_DVA(vsi));
4392ccb96312Sdlg 
4393ccb96312Sdlg 	param = (struct ixl_aq_vsi_param *)iaq.iaq_param;
4394ccb96312Sdlg 	param->uplink_seid = sc->sc_seid;
4395ccb96312Sdlg 
4396ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(vsi), 0, IXL_DMA_LEN(vsi),
4397ccb96312Sdlg 	    BUS_DMASYNC_PREREAD);
4398ccb96312Sdlg 
4399ccb96312Sdlg 	rv = ixl_atq_poll(sc, &iaq, 250);
4400ccb96312Sdlg 
4401ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(vsi), 0, IXL_DMA_LEN(vsi),
4402ccb96312Sdlg 	    BUS_DMASYNC_POSTREAD);
4403ccb96312Sdlg 
4404ccb96312Sdlg 	if (rv != 0) {
4405ccb96312Sdlg 		printf("%s: GET VSI timeout\n", DEVNAME(sc));
4406ccb96312Sdlg 		return (-1);
4407ccb96312Sdlg 	}
4408ccb96312Sdlg 
4409ccb96312Sdlg 	if (iaq.iaq_retval != htole16(IXL_AQ_RC_OK)) {
4410ccb96312Sdlg 		printf("%s: GET VSI error %u\n", DEVNAME(sc),
4411ccb96312Sdlg 		    lemtoh16(&iaq.iaq_retval));
4412ccb96312Sdlg 		return (-1);
4413ccb96312Sdlg 	}
4414ccb96312Sdlg 
4415ccb96312Sdlg 	reply = (struct ixl_aq_vsi_reply *)iaq.iaq_param;
4416ccb96312Sdlg 	sc->sc_vsi_number = reply->vsi_number;
4417ccb96312Sdlg 
4418ccb96312Sdlg 	return (0);
4419ccb96312Sdlg }
4420ccb96312Sdlg 
4421ccb96312Sdlg static int
ixl_set_vsi(struct ixl_softc * sc)4422ccb96312Sdlg ixl_set_vsi(struct ixl_softc *sc)
4423ccb96312Sdlg {
44242bb8400cSjmatthew 	struct ixl_dmamem *vsi = &sc->sc_scratch;
4425ccb96312Sdlg 	struct ixl_aq_desc iaq;
4426ccb96312Sdlg 	struct ixl_aq_vsi_param *param;
4427ccb96312Sdlg 	struct ixl_aq_vsi_data *data = IXL_DMA_KVA(vsi);
4428ccb96312Sdlg 	int rv;
4429ccb96312Sdlg 
4430ccb96312Sdlg 	data->valid_sections = htole16(IXL_AQ_VSI_VALID_QUEUE_MAP |
4431ccb96312Sdlg 	    IXL_AQ_VSI_VALID_VLAN);
4432ccb96312Sdlg 
4433ccb96312Sdlg 	CLR(data->mapping_flags, htole16(IXL_AQ_VSI_QUE_MAP_MASK));
4434ccb96312Sdlg 	SET(data->mapping_flags, htole16(IXL_AQ_VSI_QUE_MAP_CONTIG));
4435eb1b42e4Sdlg 	data->queue_mapping[0] = htole16(0);
4436ccb96312Sdlg 	data->tc_mapping[0] = htole16((0 << IXL_AQ_VSI_TC_Q_OFFSET_SHIFT) |
4437ccb96312Sdlg 	    (sc->sc_nqueues << IXL_AQ_VSI_TC_Q_NUMBER_SHIFT));
4438ccb96312Sdlg 
4439ccb96312Sdlg 	CLR(data->port_vlan_flags,
4440ccb96312Sdlg 	    htole16(IXL_AQ_VSI_PVLAN_MODE_MASK | IXL_AQ_VSI_PVLAN_EMOD_MASK));
4441555fd15dSdlg 	SET(data->port_vlan_flags, htole16(IXL_AQ_VSI_PVLAN_MODE_ALL |
4442555fd15dSdlg 	    IXL_AQ_VSI_PVLAN_EMOD_STR_BOTH));
4443ccb96312Sdlg 
4444ccb96312Sdlg 	/* grumble, vsi info isn't "known" at compile time */
4445ccb96312Sdlg 
4446ccb96312Sdlg 	memset(&iaq, 0, sizeof(iaq));
4447ccb96312Sdlg 	htolem16(&iaq.iaq_flags, IXL_AQ_BUF | IXL_AQ_RD |
4448ccb96312Sdlg 	    (IXL_DMA_LEN(vsi) > I40E_AQ_LARGE_BUF ? IXL_AQ_LB : 0));
4449ccb96312Sdlg 	iaq.iaq_opcode = htole16(IXL_AQ_OP_UPD_VSI_PARAMS);
4450ccb96312Sdlg 	htolem16(&iaq.iaq_datalen, IXL_DMA_LEN(vsi));
4451ccb96312Sdlg 	ixl_aq_dva(&iaq, IXL_DMA_DVA(vsi));
4452ccb96312Sdlg 
4453ccb96312Sdlg 	param = (struct ixl_aq_vsi_param *)iaq.iaq_param;
4454ccb96312Sdlg 	param->uplink_seid = sc->sc_seid;
4455ccb96312Sdlg 
4456ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(vsi), 0, IXL_DMA_LEN(vsi),
4457ccb96312Sdlg 	    BUS_DMASYNC_PREWRITE);
4458ccb96312Sdlg 
4459ccb96312Sdlg 	rv = ixl_atq_poll(sc, &iaq, 250);
4460ccb96312Sdlg 
4461ccb96312Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(vsi), 0, IXL_DMA_LEN(vsi),
4462ccb96312Sdlg 	    BUS_DMASYNC_POSTWRITE);
4463ccb96312Sdlg 
4464ccb96312Sdlg 	if (rv != 0) {
4465ccb96312Sdlg 		printf("%s: UPDATE VSI timeout\n", DEVNAME(sc));
4466ccb96312Sdlg 		return (-1);
4467ccb96312Sdlg 	}
4468ccb96312Sdlg 
4469ccb96312Sdlg 	if (iaq.iaq_retval != htole16(IXL_AQ_RC_OK)) {
4470ccb96312Sdlg 		printf("%s: UPDATE VSI error %u\n", DEVNAME(sc),
4471ccb96312Sdlg 		    lemtoh16(&iaq.iaq_retval));
4472ccb96312Sdlg 		return (-1);
4473ccb96312Sdlg 	}
4474ccb96312Sdlg 
4475ccb96312Sdlg 	return (0);
4476ccb96312Sdlg }
4477ccb96312Sdlg 
4478ccb96312Sdlg static const struct ixl_phy_type *
ixl_search_phy_type(uint8_t phy_type)4479ccb96312Sdlg ixl_search_phy_type(uint8_t phy_type)
4480ccb96312Sdlg {
4481ccb96312Sdlg 	const struct ixl_phy_type *itype;
4482ccb96312Sdlg 	uint64_t mask;
4483ccb96312Sdlg 	unsigned int i;
4484ccb96312Sdlg 
4485ccb96312Sdlg 	if (phy_type >= 64)
4486ccb96312Sdlg 		return (NULL);
4487ccb96312Sdlg 
4488ccb96312Sdlg 	mask = 1ULL << phy_type;
4489ccb96312Sdlg 
4490ccb96312Sdlg 	for (i = 0; i < nitems(ixl_phy_type_map); i++) {
4491ccb96312Sdlg 		itype = &ixl_phy_type_map[i];
4492ccb96312Sdlg 
4493ccb96312Sdlg 		if (ISSET(itype->phy_type, mask))
4494ccb96312Sdlg 			return (itype);
4495ccb96312Sdlg 	}
4496ccb96312Sdlg 
4497ccb96312Sdlg 	return (NULL);
4498ccb96312Sdlg }
4499ccb96312Sdlg 
4500ccb96312Sdlg static uint64_t
ixl_search_link_speed(uint8_t link_speed)4501ccb96312Sdlg ixl_search_link_speed(uint8_t link_speed)
4502ccb96312Sdlg {
4503ccb96312Sdlg 	const struct ixl_speed_type *type;
4504ccb96312Sdlg 	unsigned int i;
4505ccb96312Sdlg 
4506be3123b0Sjsg 	for (i = 0; i < nitems(ixl_speed_type_map); i++) {
4507ccb96312Sdlg 		type = &ixl_speed_type_map[i];
4508ccb96312Sdlg 
4509ccb96312Sdlg 		if (ISSET(type->dev_speed, link_speed))
4510ccb96312Sdlg 			return (type->net_speed);
4511ccb96312Sdlg 	}
4512ccb96312Sdlg 
4513ccb96312Sdlg 	return (0);
4514ccb96312Sdlg }
4515ccb96312Sdlg 
4516ccb96312Sdlg static int
ixl_set_link_status(struct ixl_softc * sc,const struct ixl_aq_desc * iaq)4517ccb96312Sdlg ixl_set_link_status(struct ixl_softc *sc, const struct ixl_aq_desc *iaq)
4518ccb96312Sdlg {
4519ccb96312Sdlg 	const struct ixl_aq_link_status *status;
4520ccb96312Sdlg 	const struct ixl_phy_type *itype;
4521ccb96312Sdlg 	uint64_t ifm_active = IFM_ETHER;
4522ccb96312Sdlg 	uint64_t ifm_status = IFM_AVALID;
4523ccb96312Sdlg 	int link_state = LINK_STATE_DOWN;
4524ccb96312Sdlg 	uint64_t baudrate = 0;
4525ccb96312Sdlg 
4526ccb96312Sdlg 	status = (const struct ixl_aq_link_status *)iaq->iaq_param;
4527ccb96312Sdlg 	if (!ISSET(status->link_info, IXL_AQ_LINK_UP_FUNCTION))
4528ccb96312Sdlg 		goto done;
4529ccb96312Sdlg 
4530ccb96312Sdlg 	ifm_active |= IFM_FDX;
4531ccb96312Sdlg 	ifm_status |= IFM_ACTIVE;
4532ccb96312Sdlg 	link_state = LINK_STATE_FULL_DUPLEX;
4533ccb96312Sdlg 
4534ccb96312Sdlg 	itype = ixl_search_phy_type(status->phy_type);
4535ccb96312Sdlg 	if (itype != NULL)
4536ccb96312Sdlg 		ifm_active |= itype->ifm_type;
4537ccb96312Sdlg 
4538ccb96312Sdlg 	if (ISSET(status->an_info, IXL_AQ_LINK_PAUSE_TX))
4539ccb96312Sdlg 		ifm_active |= IFM_ETH_TXPAUSE;
4540ccb96312Sdlg 	if (ISSET(status->an_info, IXL_AQ_LINK_PAUSE_RX))
4541ccb96312Sdlg 		ifm_active |= IFM_ETH_RXPAUSE;
4542ccb96312Sdlg 
4543ccb96312Sdlg 	baudrate = ixl_search_link_speed(status->link_speed);
4544ccb96312Sdlg 
4545ccb96312Sdlg done:
4546fea9c2abSbluhm 	mtx_enter(&sc->sc_link_state_mtx);
4547ccb96312Sdlg 	sc->sc_media_active = ifm_active;
4548ccb96312Sdlg 	sc->sc_media_status = ifm_status;
4549ccb96312Sdlg 	sc->sc_ac.ac_if.if_baudrate = baudrate;
4550fea9c2abSbluhm 	mtx_leave(&sc->sc_link_state_mtx);
4551ccb96312Sdlg 
4552ccb96312Sdlg 	return (link_state);
4553ccb96312Sdlg }
4554ccb96312Sdlg 
4555ccb96312Sdlg static int
ixl_restart_an(struct ixl_softc * sc)4556ccb96312Sdlg ixl_restart_an(struct ixl_softc *sc)
4557ccb96312Sdlg {
4558ccb96312Sdlg 	struct ixl_aq_desc iaq;
4559ccb96312Sdlg 
4560ccb96312Sdlg 	memset(&iaq, 0, sizeof(iaq));
4561ccb96312Sdlg 	iaq.iaq_opcode = htole16(IXL_AQ_OP_PHY_RESTART_AN);
4562ccb96312Sdlg 	iaq.iaq_param[0] =
4563ccb96312Sdlg 	    htole32(IXL_AQ_PHY_RESTART_AN | IXL_AQ_PHY_LINK_ENABLE);
4564ccb96312Sdlg 
4565ccb96312Sdlg 	if (ixl_atq_poll(sc, &iaq, 250) != 0) {
4566ccb96312Sdlg 		printf("%s: RESTART AN timeout\n", DEVNAME(sc));
4567ccb96312Sdlg 		return (-1);
4568ccb96312Sdlg 	}
4569ccb96312Sdlg 	if (iaq.iaq_retval != htole16(IXL_AQ_RC_OK)) {
4570ccb96312Sdlg 		printf("%s: RESTART AN error\n", DEVNAME(sc));
4571ccb96312Sdlg 		return (-1);
4572ccb96312Sdlg 	}
4573ccb96312Sdlg 
4574ccb96312Sdlg 	return (0);
4575ccb96312Sdlg }
4576ccb96312Sdlg 
4577ccb96312Sdlg static int
ixl_add_macvlan(struct ixl_softc * sc,uint8_t * macaddr,uint16_t vlan,uint16_t flags)45782bb8400cSjmatthew ixl_add_macvlan(struct ixl_softc *sc, uint8_t *macaddr, uint16_t vlan, uint16_t flags)
45792bb8400cSjmatthew {
45802bb8400cSjmatthew 	struct ixl_aq_desc iaq;
45812bb8400cSjmatthew 	struct ixl_aq_add_macvlan *param;
45822bb8400cSjmatthew 	struct ixl_aq_add_macvlan_elem *elem;
45832bb8400cSjmatthew 
45842bb8400cSjmatthew 	memset(&iaq, 0, sizeof(iaq));
45852bb8400cSjmatthew 	iaq.iaq_flags = htole16(IXL_AQ_BUF | IXL_AQ_RD);
45862bb8400cSjmatthew 	iaq.iaq_opcode = htole16(IXL_AQ_OP_ADD_MACVLAN);
45872bb8400cSjmatthew 	iaq.iaq_datalen = htole16(sizeof(*elem));
45882bb8400cSjmatthew 	ixl_aq_dva(&iaq, IXL_DMA_DVA(&sc->sc_scratch));
45892bb8400cSjmatthew 
45902bb8400cSjmatthew 	param = (struct ixl_aq_add_macvlan *)&iaq.iaq_param;
45912bb8400cSjmatthew 	param->num_addrs = htole16(1);
45922bb8400cSjmatthew 	param->seid0 = htole16(0x8000) | sc->sc_seid;
45932bb8400cSjmatthew 	param->seid1 = 0;
45942bb8400cSjmatthew 	param->seid2 = 0;
45952bb8400cSjmatthew 
45962bb8400cSjmatthew 	elem = IXL_DMA_KVA(&sc->sc_scratch);
45972bb8400cSjmatthew 	memset(elem, 0, sizeof(*elem));
45982bb8400cSjmatthew 	memcpy(elem->macaddr, macaddr, ETHER_ADDR_LEN);
45992bb8400cSjmatthew 	elem->flags = htole16(IXL_AQ_OP_ADD_MACVLAN_PERFECT_MATCH | flags);
46002bb8400cSjmatthew 	elem->vlan = htole16(vlan);
46012bb8400cSjmatthew 
46022bb8400cSjmatthew 	if (ixl_atq_poll(sc, &iaq, 250) != 0) {
46032bb8400cSjmatthew 		printf("%s: ADD_MACVLAN timeout\n", DEVNAME(sc));
46042bb8400cSjmatthew 		return (IXL_AQ_RC_EINVAL);
46052bb8400cSjmatthew 	}
46062bb8400cSjmatthew 
46072bb8400cSjmatthew 	return letoh16(iaq.iaq_retval);
46082bb8400cSjmatthew }
46092bb8400cSjmatthew 
46102bb8400cSjmatthew static int
ixl_remove_macvlan(struct ixl_softc * sc,uint8_t * macaddr,uint16_t vlan,uint16_t flags)46112bb8400cSjmatthew ixl_remove_macvlan(struct ixl_softc *sc, uint8_t *macaddr, uint16_t vlan, uint16_t flags)
46122bb8400cSjmatthew {
46132bb8400cSjmatthew 	struct ixl_aq_desc iaq;
46142bb8400cSjmatthew 	struct ixl_aq_remove_macvlan *param;
46152bb8400cSjmatthew 	struct ixl_aq_remove_macvlan_elem *elem;
46162bb8400cSjmatthew 
46172bb8400cSjmatthew 	memset(&iaq, 0, sizeof(iaq));
46182bb8400cSjmatthew 	iaq.iaq_flags = htole16(IXL_AQ_BUF | IXL_AQ_RD);
46192bb8400cSjmatthew 	iaq.iaq_opcode = htole16(IXL_AQ_OP_REMOVE_MACVLAN);
46202bb8400cSjmatthew 	iaq.iaq_datalen = htole16(sizeof(*elem));
46212bb8400cSjmatthew 	ixl_aq_dva(&iaq, IXL_DMA_DVA(&sc->sc_scratch));
46222bb8400cSjmatthew 
46232bb8400cSjmatthew 	param = (struct ixl_aq_remove_macvlan *)&iaq.iaq_param;
46242bb8400cSjmatthew 	param->num_addrs = htole16(1);
46252bb8400cSjmatthew 	param->seid0 = htole16(0x8000) | sc->sc_seid;
46262bb8400cSjmatthew 	param->seid1 = 0;
46272bb8400cSjmatthew 	param->seid2 = 0;
46282bb8400cSjmatthew 
46292bb8400cSjmatthew 	elem = IXL_DMA_KVA(&sc->sc_scratch);
46302bb8400cSjmatthew 	memset(elem, 0, sizeof(*elem));
46312bb8400cSjmatthew 	memcpy(elem->macaddr, macaddr, ETHER_ADDR_LEN);
46322bb8400cSjmatthew 	elem->flags = htole16(IXL_AQ_OP_REMOVE_MACVLAN_PERFECT_MATCH | flags);
46332bb8400cSjmatthew 	elem->vlan = htole16(vlan);
46342bb8400cSjmatthew 
46352bb8400cSjmatthew 	if (ixl_atq_poll(sc, &iaq, 250) != 0) {
46362bb8400cSjmatthew 		printf("%s: REMOVE_MACVLAN timeout\n", DEVNAME(sc));
46372bb8400cSjmatthew 		return (IXL_AQ_RC_EINVAL);
46382bb8400cSjmatthew 	}
46392bb8400cSjmatthew 
46402bb8400cSjmatthew 	return letoh16(iaq.iaq_retval);
46412bb8400cSjmatthew }
46422bb8400cSjmatthew 
46432bb8400cSjmatthew static int
ixl_hmc(struct ixl_softc * sc)4644ccb96312Sdlg ixl_hmc(struct ixl_softc *sc)
4645ccb96312Sdlg {
4646ccb96312Sdlg 	struct {
4647eb1b42e4Sdlg 		uint32_t   count;
4648ccb96312Sdlg 		uint32_t   minsize;
4649ccb96312Sdlg 		bus_size_t maxcnt;
4650ccb96312Sdlg 		bus_size_t setoff;
4651ccb96312Sdlg 		bus_size_t setcnt;
4652eb1b42e4Sdlg 	} regs[] = {
4653ccb96312Sdlg 		{
4654eb1b42e4Sdlg 			0,
4655ccb96312Sdlg 			IXL_HMC_TXQ_MINSIZE,
4656ccb96312Sdlg 			I40E_GLHMC_LANTXOBJSZ,
4657ccb96312Sdlg 			I40E_GLHMC_LANTXBASE(sc->sc_pf_id),
4658ccb96312Sdlg 			I40E_GLHMC_LANTXCNT(sc->sc_pf_id),
4659ccb96312Sdlg 		},
4660ccb96312Sdlg 		{
4661eb1b42e4Sdlg 			0,
4662ccb96312Sdlg 			IXL_HMC_RXQ_MINSIZE,
4663ccb96312Sdlg 			I40E_GLHMC_LANRXOBJSZ,
4664ccb96312Sdlg 			I40E_GLHMC_LANRXBASE(sc->sc_pf_id),
4665ccb96312Sdlg 			I40E_GLHMC_LANRXCNT(sc->sc_pf_id),
4666eb1b42e4Sdlg 		},
4667eb1b42e4Sdlg 		{
4668eb1b42e4Sdlg 			0,
4669eb1b42e4Sdlg 			0,
4670eb1b42e4Sdlg 			I40E_GLHMC_FCOEMAX,
4671eb1b42e4Sdlg 			I40E_GLHMC_FCOEDDPBASE(sc->sc_pf_id),
4672eb1b42e4Sdlg 			I40E_GLHMC_FCOEDDPCNT(sc->sc_pf_id),
4673eb1b42e4Sdlg 		},
4674eb1b42e4Sdlg 		{
4675eb1b42e4Sdlg 			0,
4676eb1b42e4Sdlg 			0,
4677eb1b42e4Sdlg 			I40E_GLHMC_FCOEFMAX,
4678eb1b42e4Sdlg 			I40E_GLHMC_FCOEFBASE(sc->sc_pf_id),
4679eb1b42e4Sdlg 			I40E_GLHMC_FCOEFCNT(sc->sc_pf_id),
4680eb1b42e4Sdlg 		},
4681ccb96312Sdlg 	};
4682ccb96312Sdlg 	struct ixl_hmc_entry *e;
4683eb1b42e4Sdlg 	uint64_t size, dva;
4684ccb96312Sdlg 	uint8_t *kva;
4685ccb96312Sdlg 	uint64_t *sdpage;
4686ccb96312Sdlg 	unsigned int i;
4687ccb96312Sdlg 	int npages, tables;
4688ccb96312Sdlg 
4689ccb96312Sdlg 	CTASSERT(nitems(regs) <= nitems(sc->sc_hmc_entries));
4690ccb96312Sdlg 
4691eb1b42e4Sdlg 	regs[IXL_HMC_LAN_TX].count = regs[IXL_HMC_LAN_RX].count =
4692eb1b42e4Sdlg 	    ixl_rd(sc, I40E_GLHMC_LANQMAX);
4693ccb96312Sdlg 
4694ccb96312Sdlg 	size = 0;
4695ccb96312Sdlg 	for (i = 0; i < nitems(regs); i++) {
4696ccb96312Sdlg 		e = &sc->sc_hmc_entries[i];
4697ccb96312Sdlg 
4698eb1b42e4Sdlg 		e->hmc_count = regs[i].count;
4699ccb96312Sdlg 		e->hmc_size = 1U << ixl_rd(sc, regs[i].maxcnt);
4700ccb96312Sdlg 		e->hmc_base = size;
4701ccb96312Sdlg 
4702ccb96312Sdlg 		if ((e->hmc_size * 8) < regs[i].minsize) {
4703ccb96312Sdlg 			printf("%s: kernel hmc entry is too big\n",
4704ccb96312Sdlg 			    DEVNAME(sc));
4705ccb96312Sdlg 			return (-1);
4706ccb96312Sdlg 		}
4707ccb96312Sdlg 
4708ccb96312Sdlg 		size += roundup(e->hmc_size * e->hmc_count, IXL_HMC_ROUNDUP);
4709ccb96312Sdlg 	}
4710ccb96312Sdlg 	size = roundup(size, IXL_HMC_PGSIZE);
4711ccb96312Sdlg 	npages = size / IXL_HMC_PGSIZE;
4712ccb96312Sdlg 
4713eb1b42e4Sdlg 	tables = roundup(size, IXL_HMC_L2SZ) / IXL_HMC_L2SZ;
4714eb1b42e4Sdlg 
4715eb1b42e4Sdlg 	if (ixl_dmamem_alloc(sc, &sc->sc_hmc_pd, size, IXL_HMC_PGSIZE) != 0) {
4716eb1b42e4Sdlg 		printf("%s: unable to allocate hmc pd memory\n", DEVNAME(sc));
4717ccb96312Sdlg 		return (-1);
4718ccb96312Sdlg 	}
4719ccb96312Sdlg 
4720eb1b42e4Sdlg 	if (ixl_dmamem_alloc(sc, &sc->sc_hmc_sd, tables * IXL_HMC_PGSIZE,
4721eb1b42e4Sdlg 	    IXL_HMC_PGSIZE) != 0) {
4722eb1b42e4Sdlg 		printf("%s: unable to allocate hmc sd memory\n", DEVNAME(sc));
4723eb1b42e4Sdlg 		ixl_dmamem_free(sc, &sc->sc_hmc_pd);
4724eb1b42e4Sdlg 		return (-1);
4725ccb96312Sdlg 	}
4726ccb96312Sdlg 
4727eb1b42e4Sdlg 	kva = IXL_DMA_KVA(&sc->sc_hmc_pd);
4728eb1b42e4Sdlg 	memset(kva, 0, IXL_DMA_LEN(&sc->sc_hmc_pd));
4729eb1b42e4Sdlg 
4730eb1b42e4Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_hmc_pd),
4731eb1b42e4Sdlg 	    0, IXL_DMA_LEN(&sc->sc_hmc_pd),
4732ccb96312Sdlg 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
4733ccb96312Sdlg 
4734eb1b42e4Sdlg 	dva = IXL_DMA_DVA(&sc->sc_hmc_pd);
4735eb1b42e4Sdlg 	sdpage = IXL_DMA_KVA(&sc->sc_hmc_sd);
4736eb1b42e4Sdlg 	for (i = 0; i < npages; i++) {
4737eb1b42e4Sdlg 		htolem64(sdpage++, dva | IXL_HMC_PDVALID);
4738eb1b42e4Sdlg 
4739eb1b42e4Sdlg 		dva += IXL_HMC_PGSIZE;
4740eb1b42e4Sdlg 	}
4741eb1b42e4Sdlg 
4742eb1b42e4Sdlg 	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_hmc_sd),
4743eb1b42e4Sdlg 	    0, IXL_DMA_LEN(&sc->sc_hmc_sd),
4744eb1b42e4Sdlg 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
4745eb1b42e4Sdlg 
4746eb1b42e4Sdlg 	dva = IXL_DMA_DVA(&sc->sc_hmc_sd);
4747ccb96312Sdlg 	for (i = 0; i < tables; i++) {
4748ccb96312Sdlg 		uint32_t count;
4749ccb96312Sdlg 
4750ccb96312Sdlg 		KASSERT(npages >= 0);
4751ccb96312Sdlg 
4752ccb96312Sdlg 		count = (npages > IXL_HMC_PGS) ? IXL_HMC_PGS : npages;
4753ccb96312Sdlg 
4754eb1b42e4Sdlg 		ixl_wr(sc, I40E_PFHMC_SDDATAHIGH, dva >> 32);
4755eb1b42e4Sdlg 		ixl_wr(sc, I40E_PFHMC_SDDATALOW, dva |
4756ccb96312Sdlg 		    (count << I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) |
4757ccb96312Sdlg 		    (1U << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT));
4758ccb96312Sdlg 		ixl_barrier(sc, 0, sc->sc_mems, BUS_SPACE_BARRIER_WRITE);
4759ccb96312Sdlg 		ixl_wr(sc, I40E_PFHMC_SDCMD,
4760ccb96312Sdlg 		    (1U << I40E_PFHMC_SDCMD_PMSDWR_SHIFT) | i);
4761ccb96312Sdlg 
4762ccb96312Sdlg 		npages -= IXL_HMC_PGS;
4763eb1b42e4Sdlg 		dva += IXL_HMC_PGSIZE;
4764ccb96312Sdlg 	}
4765ccb96312Sdlg 
4766ccb96312Sdlg 	for (i = 0; i < nitems(regs); i++) {
4767ccb96312Sdlg 		e = &sc->sc_hmc_entries[i];
4768ccb96312Sdlg 
4769ccb96312Sdlg 		ixl_wr(sc, regs[i].setoff, e->hmc_base / IXL_HMC_ROUNDUP);
4770ccb96312Sdlg 		ixl_wr(sc, regs[i].setcnt, e->hmc_count);
4771ccb96312Sdlg 	}
4772ccb96312Sdlg 
4773ccb96312Sdlg 	return (0);
4774ccb96312Sdlg }
4775ccb96312Sdlg 
4776ccb96312Sdlg static void
ixl_hmc_free(struct ixl_softc * sc)4777eb1b42e4Sdlg ixl_hmc_free(struct ixl_softc *sc)
4778eb1b42e4Sdlg {
4779eb1b42e4Sdlg 	ixl_dmamem_free(sc, &sc->sc_hmc_sd);
4780eb1b42e4Sdlg 	ixl_dmamem_free(sc, &sc->sc_hmc_pd);
4781eb1b42e4Sdlg }
4782eb1b42e4Sdlg 
4783eb1b42e4Sdlg static void
ixl_hmc_pack(void * d,const void * s,const struct ixl_hmc_pack * packing,unsigned int npacking)4784ccb96312Sdlg ixl_hmc_pack(void *d, const void *s, const struct ixl_hmc_pack *packing,
4785ccb96312Sdlg     unsigned int npacking)
4786ccb96312Sdlg {
4787ccb96312Sdlg 	uint8_t *dst = d;
4788ccb96312Sdlg 	const uint8_t *src = s;
4789ccb96312Sdlg 	unsigned int i;
4790ccb96312Sdlg 
4791ccb96312Sdlg 	for (i = 0; i < npacking; i++) {
4792ccb96312Sdlg 		const struct ixl_hmc_pack *pack = &packing[i];
4793ccb96312Sdlg 		unsigned int offset = pack->lsb / 8;
4794ccb96312Sdlg 		unsigned int align = pack->lsb % 8;
4795ccb96312Sdlg 		const uint8_t *in = src + pack->offset;
4796ccb96312Sdlg 		uint8_t *out = dst + offset;
4797ccb96312Sdlg 		int width = pack->width;
4798ccb96312Sdlg 		unsigned int inbits = 0;
4799ccb96312Sdlg 
4800ccb96312Sdlg 		if (align) {
480185fe2b3fSjmatthew 			inbits = (*in++) << align;
480285fe2b3fSjmatthew 			*out++ |= (inbits & 0xff);
480385fe2b3fSjmatthew 			inbits >>= 8;
4804ccb96312Sdlg 
4805ccb96312Sdlg 			width -= 8 - align;
4806ccb96312Sdlg 		}
4807ccb96312Sdlg 
4808ccb96312Sdlg 		while (width >= 8) {
480985fe2b3fSjmatthew 			inbits |= (*in++) << align;
481085fe2b3fSjmatthew 			*out++ = (inbits & 0xff);
481185fe2b3fSjmatthew 			inbits >>= 8;
4812ccb96312Sdlg 
4813ccb96312Sdlg 			width -= 8;
4814ccb96312Sdlg 		}
4815ccb96312Sdlg 
481685fe2b3fSjmatthew 		if (width > 0) {
481785fe2b3fSjmatthew 			inbits |= (*in) << align;
481885fe2b3fSjmatthew 			*out |= (inbits & ((1 << width) - 1));
481985fe2b3fSjmatthew 		}
4820ccb96312Sdlg 	}
4821ccb96312Sdlg }
4822ccb96312Sdlg 
4823ccb96312Sdlg static struct ixl_aq_buf *
ixl_aqb_alloc(struct ixl_softc * sc)4824ccb96312Sdlg ixl_aqb_alloc(struct ixl_softc *sc)
4825ccb96312Sdlg {
4826ccb96312Sdlg 	struct ixl_aq_buf *aqb;
4827ccb96312Sdlg 
4828ccb96312Sdlg 	aqb = malloc(sizeof(*aqb), M_DEVBUF, M_WAITOK);
4829ccb96312Sdlg 	if (aqb == NULL)
4830ccb96312Sdlg 		return (NULL);
4831ccb96312Sdlg 
4832ccb96312Sdlg 	aqb->aqb_data = dma_alloc(IXL_AQ_BUFLEN, PR_WAITOK);
4833ccb96312Sdlg 	if (aqb->aqb_data == NULL)
4834ccb96312Sdlg 		goto free;
4835ccb96312Sdlg 
4836ccb96312Sdlg 	if (bus_dmamap_create(sc->sc_dmat, IXL_AQ_BUFLEN, 1,
4837ccb96312Sdlg 	    IXL_AQ_BUFLEN, 0,
4838ccb96312Sdlg 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
4839ccb96312Sdlg 	    &aqb->aqb_map) != 0)
4840ccb96312Sdlg 		goto dma_free;
4841ccb96312Sdlg 
4842ccb96312Sdlg 	if (bus_dmamap_load(sc->sc_dmat, aqb->aqb_map, aqb->aqb_data,
4843ccb96312Sdlg 	    IXL_AQ_BUFLEN, NULL, BUS_DMA_WAITOK) != 0)
4844ccb96312Sdlg 		goto destroy;
4845ccb96312Sdlg 
4846ccb96312Sdlg 	return (aqb);
4847ccb96312Sdlg 
4848ccb96312Sdlg destroy:
4849ccb96312Sdlg 	bus_dmamap_destroy(sc->sc_dmat, aqb->aqb_map);
4850ccb96312Sdlg dma_free:
4851ccb96312Sdlg 	dma_free(aqb->aqb_data, IXL_AQ_BUFLEN);
4852ccb96312Sdlg free:
4853ccb96312Sdlg 	free(aqb, M_DEVBUF, sizeof(*aqb));
4854ccb96312Sdlg 
4855ccb96312Sdlg 	return (NULL);
4856ccb96312Sdlg }
4857ccb96312Sdlg 
4858ccb96312Sdlg static void
ixl_aqb_free(struct ixl_softc * sc,struct ixl_aq_buf * aqb)4859ccb96312Sdlg ixl_aqb_free(struct ixl_softc *sc, struct ixl_aq_buf *aqb)
4860ccb96312Sdlg {
4861ccb96312Sdlg 	bus_dmamap_unload(sc->sc_dmat, aqb->aqb_map);
4862ccb96312Sdlg 	bus_dmamap_destroy(sc->sc_dmat, aqb->aqb_map);
4863ccb96312Sdlg 	dma_free(aqb->aqb_data, IXL_AQ_BUFLEN);
4864ccb96312Sdlg 	free(aqb, M_DEVBUF, sizeof(*aqb));
4865ccb96312Sdlg }
4866ccb96312Sdlg 
4867ccb96312Sdlg static int
ixl_arq_fill(struct ixl_softc * sc)4868ccb96312Sdlg ixl_arq_fill(struct ixl_softc *sc)
4869ccb96312Sdlg {
4870ccb96312Sdlg 	struct ixl_aq_buf *aqb;
4871ccb96312Sdlg 	struct ixl_aq_desc *arq, *iaq;
4872ccb96312Sdlg 	unsigned int prod = sc->sc_arq_prod;
4873ccb96312Sdlg 	unsigned int n;
4874ccb96312Sdlg 	int post = 0;
4875ccb96312Sdlg 
4876ccb96312Sdlg 	n = if_rxr_get(&sc->sc_arq_ring, IXL_AQ_NUM);
4877ccb96312Sdlg 	arq = IXL_DMA_KVA(&sc->sc_arq);
4878ccb96312Sdlg 
4879ccb96312Sdlg 	while (n > 0) {
4880ccb96312Sdlg 		aqb = SIMPLEQ_FIRST(&sc->sc_arq_idle);
4881ccb96312Sdlg 		if (aqb != NULL)
4882ccb96312Sdlg 			SIMPLEQ_REMOVE_HEAD(&sc->sc_arq_idle, aqb_entry);
4883ccb96312Sdlg 		else if ((aqb = ixl_aqb_alloc(sc)) == NULL)
4884ccb96312Sdlg 			break;
4885ccb96312Sdlg 
4886ccb96312Sdlg 		memset(aqb->aqb_data, 0, IXL_AQ_BUFLEN);
4887ccb96312Sdlg 
4888ccb96312Sdlg 		bus_dmamap_sync(sc->sc_dmat, aqb->aqb_map, 0, IXL_AQ_BUFLEN,
4889ccb96312Sdlg 		    BUS_DMASYNC_PREREAD);
4890ccb96312Sdlg 
4891ccb96312Sdlg 		iaq = &arq[prod];
4892ccb96312Sdlg 		iaq->iaq_flags = htole16(IXL_AQ_BUF |
4893ccb96312Sdlg 		    (IXL_AQ_BUFLEN > I40E_AQ_LARGE_BUF ? IXL_AQ_LB : 0));
4894ccb96312Sdlg 		iaq->iaq_opcode = 0;
4895ccb96312Sdlg 		iaq->iaq_datalen = htole16(IXL_AQ_BUFLEN);
4896ccb96312Sdlg 		iaq->iaq_retval = 0;
4897ccb96312Sdlg 		iaq->iaq_cookie = 0;
4898ccb96312Sdlg 		iaq->iaq_param[0] = 0;
4899ccb96312Sdlg 		iaq->iaq_param[1] = 0;
4900ccb96312Sdlg 		ixl_aq_dva(iaq, aqb->aqb_map->dm_segs[0].ds_addr);
4901ccb96312Sdlg 
4902ccb96312Sdlg 		SIMPLEQ_INSERT_TAIL(&sc->sc_arq_live, aqb, aqb_entry);
4903ccb96312Sdlg 
4904ccb96312Sdlg 		prod++;
4905ccb96312Sdlg 		prod &= IXL_AQ_MASK;
4906ccb96312Sdlg 
4907ccb96312Sdlg 		post = 1;
4908ccb96312Sdlg 
4909ccb96312Sdlg 		n--;
4910ccb96312Sdlg 	}
4911ccb96312Sdlg 
4912ccb96312Sdlg 	if_rxr_put(&sc->sc_arq_ring, n);
4913ccb96312Sdlg 	sc->sc_arq_prod = prod;
4914ccb96312Sdlg 
4915ccb96312Sdlg 	return (post);
4916ccb96312Sdlg }
4917ccb96312Sdlg 
4918ccb96312Sdlg static void
ixl_arq_unfill(struct ixl_softc * sc)4919ccb96312Sdlg ixl_arq_unfill(struct ixl_softc *sc)
4920ccb96312Sdlg {
4921ccb96312Sdlg 	struct ixl_aq_buf *aqb;
4922ccb96312Sdlg 
4923ccb96312Sdlg 	while ((aqb = SIMPLEQ_FIRST(&sc->sc_arq_live)) != NULL) {
4924ccb96312Sdlg 		SIMPLEQ_REMOVE_HEAD(&sc->sc_arq_live, aqb_entry);
4925ccb96312Sdlg 
4926ccb96312Sdlg 		bus_dmamap_sync(sc->sc_dmat, aqb->aqb_map, 0, IXL_AQ_BUFLEN,
4927ccb96312Sdlg 		    BUS_DMASYNC_POSTREAD);
4928ccb96312Sdlg 		ixl_aqb_free(sc, aqb);
4929ccb96312Sdlg 	}
4930ccb96312Sdlg }
4931ccb96312Sdlg 
4932ccb96312Sdlg static void
ixl_clear_hw(struct ixl_softc * sc)4933ccb96312Sdlg ixl_clear_hw(struct ixl_softc *sc)
4934ccb96312Sdlg {
4935ccb96312Sdlg 	uint32_t num_queues, base_queue;
4936ccb96312Sdlg 	uint32_t num_pf_int;
4937ccb96312Sdlg 	uint32_t num_vf_int;
4938ccb96312Sdlg 	uint32_t num_vfs;
4939ccb96312Sdlg 	uint32_t i, j;
4940ccb96312Sdlg 	uint32_t val;
4941ccb96312Sdlg 
4942ccb96312Sdlg 	/* get number of interrupts, queues, and vfs */
4943ccb96312Sdlg 	val = ixl_rd(sc, I40E_GLPCI_CNF2);
4944ccb96312Sdlg 	num_pf_int = (val & I40E_GLPCI_CNF2_MSI_X_PF_N_MASK) >>
4945ccb96312Sdlg 	    I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT;
4946ccb96312Sdlg 	num_vf_int = (val & I40E_GLPCI_CNF2_MSI_X_VF_N_MASK) >>
4947ccb96312Sdlg 	    I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT;
4948ccb96312Sdlg 
4949ccb96312Sdlg 	val = ixl_rd(sc, I40E_PFLAN_QALLOC);
4950ccb96312Sdlg 	base_queue = (val & I40E_PFLAN_QALLOC_FIRSTQ_MASK) >>
4951ccb96312Sdlg 	    I40E_PFLAN_QALLOC_FIRSTQ_SHIFT;
4952ccb96312Sdlg 	j = (val & I40E_PFLAN_QALLOC_LASTQ_MASK) >>
4953ccb96312Sdlg 	    I40E_PFLAN_QALLOC_LASTQ_SHIFT;
4954ccb96312Sdlg 	if (val & I40E_PFLAN_QALLOC_VALID_MASK)
4955ccb96312Sdlg 		num_queues = (j - base_queue) + 1;
4956ccb96312Sdlg 	else
4957ccb96312Sdlg 		num_queues = 0;
4958ccb96312Sdlg 
4959ccb96312Sdlg 	val = ixl_rd(sc, I40E_PF_VT_PFALLOC);
4960ccb96312Sdlg 	i = (val & I40E_PF_VT_PFALLOC_FIRSTVF_MASK) >>
4961ccb96312Sdlg 	    I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT;
4962ccb96312Sdlg 	j = (val & I40E_PF_VT_PFALLOC_LASTVF_MASK) >>
4963ccb96312Sdlg 	    I40E_PF_VT_PFALLOC_LASTVF_SHIFT;
4964ccb96312Sdlg 	if (val & I40E_PF_VT_PFALLOC_VALID_MASK)
4965ccb96312Sdlg 		num_vfs = (j - i) + 1;
4966ccb96312Sdlg 	else
4967ccb96312Sdlg 		num_vfs = 0;
4968ccb96312Sdlg 
4969ccb96312Sdlg 	/* stop all the interrupts */
4970ccb96312Sdlg 	ixl_wr(sc, I40E_PFINT_ICR0_ENA, 0);
4971ccb96312Sdlg 	val = 0x3 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
4972ccb96312Sdlg 	for (i = 0; i < num_pf_int - 2; i++)
4973ccb96312Sdlg 		ixl_wr(sc, I40E_PFINT_DYN_CTLN(i), val);
4974ccb96312Sdlg 
4975ccb96312Sdlg 	/* Set the FIRSTQ_INDX field to 0x7FF in PFINT_LNKLSTx */
497624f8ee69Smpi 	val = I40E_QUEUE_TYPE_EOL << I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT;
4977ccb96312Sdlg 	ixl_wr(sc, I40E_PFINT_LNKLST0, val);
4978ccb96312Sdlg 	for (i = 0; i < num_pf_int - 2; i++)
4979ccb96312Sdlg 		ixl_wr(sc, I40E_PFINT_LNKLSTN(i), val);
498024f8ee69Smpi 	val = I40E_QUEUE_TYPE_EOL << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT;
4981ccb96312Sdlg 	for (i = 0; i < num_vfs; i++)
4982ccb96312Sdlg 		ixl_wr(sc, I40E_VPINT_LNKLST0(i), val);
4983ccb96312Sdlg 	for (i = 0; i < num_vf_int - 2; i++)
4984ccb96312Sdlg 		ixl_wr(sc, I40E_VPINT_LNKLSTN(i), val);
4985ccb96312Sdlg 
4986ccb96312Sdlg 	/* warn the HW of the coming Tx disables */
4987ccb96312Sdlg 	for (i = 0; i < num_queues; i++) {
4988ccb96312Sdlg 		uint32_t abs_queue_idx = base_queue + i;
4989ccb96312Sdlg 		uint32_t reg_block = 0;
4990ccb96312Sdlg 
4991ccb96312Sdlg 		if (abs_queue_idx >= 128) {
4992ccb96312Sdlg 			reg_block = abs_queue_idx / 128;
4993ccb96312Sdlg 			abs_queue_idx %= 128;
4994ccb96312Sdlg 		}
4995ccb96312Sdlg 
4996ccb96312Sdlg 		val = ixl_rd(sc, I40E_GLLAN_TXPRE_QDIS(reg_block));
4997ccb96312Sdlg 		val &= ~I40E_GLLAN_TXPRE_QDIS_QINDX_MASK;
4998ccb96312Sdlg 		val |= (abs_queue_idx << I40E_GLLAN_TXPRE_QDIS_QINDX_SHIFT);
4999ccb96312Sdlg 		val |= I40E_GLLAN_TXPRE_QDIS_SET_QDIS_MASK;
5000ccb96312Sdlg 
5001ccb96312Sdlg 		ixl_wr(sc, I40E_GLLAN_TXPRE_QDIS(reg_block), val);
5002ccb96312Sdlg 	}
5003ccb96312Sdlg 	delaymsec(400);
5004ccb96312Sdlg 
5005ccb96312Sdlg 	/* stop all the queues */
5006ccb96312Sdlg 	for (i = 0; i < num_queues; i++) {
5007ccb96312Sdlg 		ixl_wr(sc, I40E_QINT_TQCTL(i), 0);
5008ccb96312Sdlg 		ixl_wr(sc, I40E_QTX_ENA(i), 0);
5009ccb96312Sdlg 		ixl_wr(sc, I40E_QINT_RQCTL(i), 0);
5010ccb96312Sdlg 		ixl_wr(sc, I40E_QRX_ENA(i), 0);
5011ccb96312Sdlg 	}
5012ccb96312Sdlg 
5013ccb96312Sdlg 	/* short wait for all queue disables to settle */
5014ccb96312Sdlg 	delaymsec(50);
5015ccb96312Sdlg }
5016ccb96312Sdlg 
5017ccb96312Sdlg static int
ixl_pf_reset(struct ixl_softc * sc)5018ccb96312Sdlg ixl_pf_reset(struct ixl_softc *sc)
5019ccb96312Sdlg {
5020ccb96312Sdlg 	uint32_t cnt = 0;
5021ccb96312Sdlg 	uint32_t cnt1 = 0;
5022ccb96312Sdlg 	uint32_t reg = 0;
5023ccb96312Sdlg 	uint32_t grst_del;
5024ccb96312Sdlg 
5025ccb96312Sdlg 	/*
5026ccb96312Sdlg 	 * Poll for Global Reset steady state in case of recent GRST.
5027ccb96312Sdlg 	 * The grst delay value is in 100ms units, and we'll wait a
5028ccb96312Sdlg 	 * couple counts longer to be sure we don't just miss the end.
5029ccb96312Sdlg 	 */
5030ccb96312Sdlg 	grst_del = ixl_rd(sc, I40E_GLGEN_RSTCTL);
5031ccb96312Sdlg 	grst_del &= I40E_GLGEN_RSTCTL_GRSTDEL_MASK;
5032ccb96312Sdlg 	grst_del >>= I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT;
5033ccb96312Sdlg 	grst_del += 10;
5034ccb96312Sdlg 
5035ccb96312Sdlg 	for (cnt = 0; cnt < grst_del; cnt++) {
5036ccb96312Sdlg 		reg = ixl_rd(sc, I40E_GLGEN_RSTAT);
5037ccb96312Sdlg 		if (!(reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK))
5038ccb96312Sdlg 			break;
5039ccb96312Sdlg 		delaymsec(100);
5040ccb96312Sdlg 	}
5041ccb96312Sdlg 	if (reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK) {
5042ccb96312Sdlg 		printf(", Global reset polling failed to complete\n");
5043ccb96312Sdlg 		return (-1);
5044ccb96312Sdlg 	}
5045ccb96312Sdlg 
5046ccb96312Sdlg 	/* Now Wait for the FW to be ready */
5047ccb96312Sdlg 	for (cnt1 = 0; cnt1 < I40E_PF_RESET_WAIT_COUNT; cnt1++) {
5048ccb96312Sdlg 		reg = ixl_rd(sc, I40E_GLNVM_ULD);
5049ccb96312Sdlg 		reg &= (I40E_GLNVM_ULD_CONF_CORE_DONE_MASK |
5050ccb96312Sdlg 		    I40E_GLNVM_ULD_CONF_GLOBAL_DONE_MASK);
5051ccb96312Sdlg 		if (reg == (I40E_GLNVM_ULD_CONF_CORE_DONE_MASK |
5052ccb96312Sdlg 		    I40E_GLNVM_ULD_CONF_GLOBAL_DONE_MASK))
5053ccb96312Sdlg 			break;
5054ccb96312Sdlg 
5055ccb96312Sdlg 		delaymsec(10);
5056ccb96312Sdlg 	}
5057ccb96312Sdlg 	if (!(reg & (I40E_GLNVM_ULD_CONF_CORE_DONE_MASK |
5058ccb96312Sdlg 	    I40E_GLNVM_ULD_CONF_GLOBAL_DONE_MASK))) {
5059ccb96312Sdlg 		printf(", wait for FW Reset complete timed out "
5060ccb96312Sdlg 		    "(I40E_GLNVM_ULD = 0x%x)\n", reg);
5061ccb96312Sdlg 		return (-1);
5062ccb96312Sdlg 	}
5063ccb96312Sdlg 
5064ccb96312Sdlg 	/*
5065ccb96312Sdlg 	 * If there was a Global Reset in progress when we got here,
5066ccb96312Sdlg 	 * we don't need to do the PF Reset
5067ccb96312Sdlg 	 */
5068ccb96312Sdlg 	if (cnt == 0) {
5069ccb96312Sdlg 		reg = ixl_rd(sc, I40E_PFGEN_CTRL);
5070ccb96312Sdlg 		ixl_wr(sc, I40E_PFGEN_CTRL, reg | I40E_PFGEN_CTRL_PFSWR_MASK);
5071ccb96312Sdlg 		for (cnt = 0; cnt < I40E_PF_RESET_WAIT_COUNT; cnt++) {
5072ccb96312Sdlg 			reg = ixl_rd(sc, I40E_PFGEN_CTRL);
5073ccb96312Sdlg 			if (!(reg & I40E_PFGEN_CTRL_PFSWR_MASK))
5074ccb96312Sdlg 				break;
5075ccb96312Sdlg 			delaymsec(1);
5076ccb96312Sdlg 		}
5077ccb96312Sdlg 		if (reg & I40E_PFGEN_CTRL_PFSWR_MASK) {
5078ccb96312Sdlg 			printf(", PF reset polling failed to complete"
5079ccb96312Sdlg 			    "(I40E_PFGEN_CTRL= 0x%x)\n", reg);
5080ccb96312Sdlg 			return (-1);
5081ccb96312Sdlg 		}
5082ccb96312Sdlg 	}
5083ccb96312Sdlg 
5084ccb96312Sdlg 	return (0);
5085ccb96312Sdlg }
5086ccb96312Sdlg 
5087819ac441Sdlg static uint32_t
ixl_710_rd_ctl(struct ixl_softc * sc,uint32_t r)5088819ac441Sdlg ixl_710_rd_ctl(struct ixl_softc *sc, uint32_t r)
5089819ac441Sdlg {
5090819ac441Sdlg 	struct ixl_atq iatq;
5091819ac441Sdlg 	struct ixl_aq_desc *iaq;
5092819ac441Sdlg 	uint16_t retval;
5093819ac441Sdlg 
5094819ac441Sdlg 	memset(&iatq, 0, sizeof(iatq));
5095819ac441Sdlg 	iaq = &iatq.iatq_desc;
5096819ac441Sdlg 	iaq->iaq_opcode = htole16(IXL_AQ_OP_RX_CTL_READ);
5097819ac441Sdlg 	htolem32(&iaq->iaq_param[1], r);
5098819ac441Sdlg 
5099819ac441Sdlg 	ixl_atq_exec(sc, &iatq, "ixl710rd");
5100819ac441Sdlg 
5101819ac441Sdlg 	retval = lemtoh16(&iaq->iaq_retval);
5102819ac441Sdlg 	if (retval != IXL_AQ_RC_OK) {
5103819ac441Sdlg 		printf("%s: %s failed (%u)\n", DEVNAME(sc), __func__, retval);
5104819ac441Sdlg 		return (~0U);
5105819ac441Sdlg 	}
5106819ac441Sdlg 
5107819ac441Sdlg 	return (lemtoh32(&iaq->iaq_param[3]));
5108819ac441Sdlg }
5109819ac441Sdlg 
5110819ac441Sdlg static void
ixl_710_wr_ctl(struct ixl_softc * sc,uint32_t r,uint32_t v)5111819ac441Sdlg ixl_710_wr_ctl(struct ixl_softc *sc, uint32_t r, uint32_t v)
5112819ac441Sdlg {
5113819ac441Sdlg 	struct ixl_atq iatq;
5114819ac441Sdlg 	struct ixl_aq_desc *iaq;
5115819ac441Sdlg 	uint16_t retval;
5116819ac441Sdlg 
5117819ac441Sdlg 	memset(&iatq, 0, sizeof(iatq));
5118819ac441Sdlg 	iaq = &iatq.iatq_desc;
5119819ac441Sdlg 	iaq->iaq_opcode = htole16(IXL_AQ_OP_RX_CTL_WRITE);
5120819ac441Sdlg 	htolem32(&iaq->iaq_param[1], r);
5121819ac441Sdlg 	htolem32(&iaq->iaq_param[3], v);
5122819ac441Sdlg 
5123819ac441Sdlg 	ixl_atq_exec(sc, &iatq, "ixl710wr");
5124819ac441Sdlg 
5125819ac441Sdlg 	retval = lemtoh16(&iaq->iaq_retval);
51260a1169f5Sdlg 	if (retval != IXL_AQ_RC_OK) {
51270a1169f5Sdlg 		printf("%s: %s %08x=%08x failed (%u)\n",
51280a1169f5Sdlg 		    DEVNAME(sc), __func__, r, v, retval);
51290a1169f5Sdlg 	}
5130819ac441Sdlg }
5131819ac441Sdlg 
5132819ac441Sdlg static int
ixl_710_set_rss_key(struct ixl_softc * sc,const struct ixl_rss_key * rsskey)5133819ac441Sdlg ixl_710_set_rss_key(struct ixl_softc *sc, const struct ixl_rss_key *rsskey)
5134819ac441Sdlg {
5135819ac441Sdlg 	unsigned int i;
5136819ac441Sdlg 
5137819ac441Sdlg 	for (i = 0; i < nitems(rsskey->key); i++)
5138f5777d33Sdlg 		ixl_wr_ctl(sc, I40E_PFQF_HKEY(i), rsskey->key[i]);
5139819ac441Sdlg 
5140819ac441Sdlg 	return (0);
5141819ac441Sdlg }
5142819ac441Sdlg 
5143819ac441Sdlg static int
ixl_710_set_rss_lut(struct ixl_softc * sc,const struct ixl_rss_lut_128 * lut)5144819ac441Sdlg ixl_710_set_rss_lut(struct ixl_softc *sc, const struct ixl_rss_lut_128 *lut)
5145819ac441Sdlg {
5146819ac441Sdlg 	unsigned int i;
5147819ac441Sdlg 
5148819ac441Sdlg 	for (i = 0; i < nitems(lut->entries); i++)
51490a1169f5Sdlg 		ixl_wr(sc, I40E_PFQF_HLUT(i), lut->entries[i]);
5150819ac441Sdlg 
5151819ac441Sdlg 	return (0);
5152819ac441Sdlg }
5153819ac441Sdlg 
5154819ac441Sdlg static uint32_t
ixl_722_rd_ctl(struct ixl_softc * sc,uint32_t r)5155819ac441Sdlg ixl_722_rd_ctl(struct ixl_softc *sc, uint32_t r)
5156819ac441Sdlg {
5157819ac441Sdlg 	return (ixl_rd(sc, r));
5158819ac441Sdlg }
5159819ac441Sdlg 
5160819ac441Sdlg static void
ixl_722_wr_ctl(struct ixl_softc * sc,uint32_t r,uint32_t v)5161819ac441Sdlg ixl_722_wr_ctl(struct ixl_softc *sc, uint32_t r, uint32_t v)
5162819ac441Sdlg {
5163819ac441Sdlg 	ixl_wr(sc, r, v);
5164819ac441Sdlg }
5165819ac441Sdlg 
5166819ac441Sdlg static int
ixl_722_set_rss_key(struct ixl_softc * sc,const struct ixl_rss_key * rsskey)5167819ac441Sdlg ixl_722_set_rss_key(struct ixl_softc *sc, const struct ixl_rss_key *rsskey)
5168819ac441Sdlg {
5169819ac441Sdlg 	/* XXX */
5170819ac441Sdlg 
5171819ac441Sdlg 	return (0);
5172819ac441Sdlg }
5173819ac441Sdlg 
5174819ac441Sdlg static int
ixl_722_set_rss_lut(struct ixl_softc * sc,const struct ixl_rss_lut_128 * lut)5175819ac441Sdlg ixl_722_set_rss_lut(struct ixl_softc *sc, const struct ixl_rss_lut_128 *lut)
5176819ac441Sdlg {
5177819ac441Sdlg 	/* XXX */
5178819ac441Sdlg 
5179819ac441Sdlg 	return (0);
5180819ac441Sdlg }
5181819ac441Sdlg 
5182ccb96312Sdlg static int
ixl_dmamem_alloc(struct ixl_softc * sc,struct ixl_dmamem * ixm,bus_size_t size,u_int align)5183ccb96312Sdlg ixl_dmamem_alloc(struct ixl_softc *sc, struct ixl_dmamem *ixm,
5184ccb96312Sdlg     bus_size_t size, u_int align)
5185ccb96312Sdlg {
5186ccb96312Sdlg 	ixm->ixm_size = size;
5187ccb96312Sdlg 
5188ccb96312Sdlg 	if (bus_dmamap_create(sc->sc_dmat, ixm->ixm_size, 1,
5189ccb96312Sdlg 	    ixm->ixm_size, 0,
5190ccb96312Sdlg 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
5191ccb96312Sdlg 	    &ixm->ixm_map) != 0)
5192ccb96312Sdlg 		return (1);
5193ccb96312Sdlg 	if (bus_dmamem_alloc(sc->sc_dmat, ixm->ixm_size,
5194ccb96312Sdlg 	    align, 0, &ixm->ixm_seg, 1, &ixm->ixm_nsegs,
5195ccb96312Sdlg 	    BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0)
5196ccb96312Sdlg 		goto destroy;
5197ccb96312Sdlg 	if (bus_dmamem_map(sc->sc_dmat, &ixm->ixm_seg, ixm->ixm_nsegs,
5198ccb96312Sdlg 	    ixm->ixm_size, &ixm->ixm_kva, BUS_DMA_WAITOK) != 0)
5199ccb96312Sdlg 		goto free;
5200ccb96312Sdlg 	if (bus_dmamap_load(sc->sc_dmat, ixm->ixm_map, ixm->ixm_kva,
5201ccb96312Sdlg 	    ixm->ixm_size, NULL, BUS_DMA_WAITOK) != 0)
5202ccb96312Sdlg 		goto unmap;
5203ccb96312Sdlg 
5204ccb96312Sdlg 	return (0);
5205ccb96312Sdlg unmap:
5206ccb96312Sdlg 	bus_dmamem_unmap(sc->sc_dmat, ixm->ixm_kva, ixm->ixm_size);
5207ccb96312Sdlg free:
5208ccb96312Sdlg 	bus_dmamem_free(sc->sc_dmat, &ixm->ixm_seg, 1);
5209ccb96312Sdlg destroy:
5210ccb96312Sdlg 	bus_dmamap_destroy(sc->sc_dmat, ixm->ixm_map);
5211ccb96312Sdlg 	return (1);
5212ccb96312Sdlg }
5213ccb96312Sdlg 
5214ccb96312Sdlg static void
ixl_dmamem_free(struct ixl_softc * sc,struct ixl_dmamem * ixm)5215ccb96312Sdlg ixl_dmamem_free(struct ixl_softc *sc, struct ixl_dmamem *ixm)
5216ccb96312Sdlg {
5217ccb96312Sdlg 	bus_dmamap_unload(sc->sc_dmat, ixm->ixm_map);
5218ccb96312Sdlg 	bus_dmamem_unmap(sc->sc_dmat, ixm->ixm_kva, ixm->ixm_size);
5219ccb96312Sdlg 	bus_dmamem_free(sc->sc_dmat, &ixm->ixm_seg, 1);
5220ccb96312Sdlg 	bus_dmamap_destroy(sc->sc_dmat, ixm->ixm_map);
5221ccb96312Sdlg }
52222ee1fcb3Sdlg 
52232ee1fcb3Sdlg #if NKSTAT > 0
52242ee1fcb3Sdlg 
52252ee1fcb3Sdlg CTASSERT(KSTAT_KV_U_NONE <= 0xffU);
52262ee1fcb3Sdlg CTASSERT(KSTAT_KV_U_PACKETS <= 0xffU);
52272ee1fcb3Sdlg CTASSERT(KSTAT_KV_U_BYTES <= 0xffU);
52282ee1fcb3Sdlg 
52292ee1fcb3Sdlg struct ixl_counter {
52302ee1fcb3Sdlg 	const char		*c_name;
52312ee1fcb3Sdlg 	uint32_t		 c_base;
52322ee1fcb3Sdlg 	uint8_t			 c_width;
52332ee1fcb3Sdlg 	uint8_t			 c_type;
52342ee1fcb3Sdlg };
52352ee1fcb3Sdlg 
52362ee1fcb3Sdlg const struct ixl_counter ixl_port_counters[] = {
52372ee1fcb3Sdlg 	/* GORC */
52382ee1fcb3Sdlg 	{ "rx bytes",		0x00300000, 48, KSTAT_KV_U_BYTES },
52392ee1fcb3Sdlg 	/* MLFC */
52402ee1fcb3Sdlg 	{ "mac local errs",	0x00300020, 32, KSTAT_KV_U_NONE },
52412ee1fcb3Sdlg 	/* MRFC */
52422ee1fcb3Sdlg 	{ "mac remote errs",	0x00300040, 32, KSTAT_KV_U_NONE },
52432ee1fcb3Sdlg 	/* MSPDC */
52442ee1fcb3Sdlg 	{ "mac short",		0x00300060, 32, KSTAT_KV_U_PACKETS },
52452ee1fcb3Sdlg 	/* CRCERRS */
52462ee1fcb3Sdlg 	{ "crc errs",		0x00300080, 32, KSTAT_KV_U_PACKETS },
52472ee1fcb3Sdlg 	/* RLEC */
52482ee1fcb3Sdlg 	{ "rx len errs",	0x003000a0, 32, KSTAT_KV_U_PACKETS },
52492ee1fcb3Sdlg 	/* ERRBC */
52502ee1fcb3Sdlg 	{ "byte errs",		0x003000c0, 32, KSTAT_KV_U_PACKETS },
52512ee1fcb3Sdlg 	/* ILLERRC */
52522ee1fcb3Sdlg 	{ "illegal byte",	0x003000d0, 32, KSTAT_KV_U_PACKETS },
52532ee1fcb3Sdlg 	/* RUC */
52542ee1fcb3Sdlg 	{ "rx undersize",	0x00300100, 32, KSTAT_KV_U_PACKETS },
52552ee1fcb3Sdlg 	/* ROC */
52562ee1fcb3Sdlg 	{ "rx oversize",	0x00300120, 32, KSTAT_KV_U_PACKETS },
52572ee1fcb3Sdlg 	/* LXONRXCNT */
52582ee1fcb3Sdlg 	{ "rx link xon",	0x00300140, 32, KSTAT_KV_U_PACKETS },
52592ee1fcb3Sdlg 	/* LXOFFRXCNT */
52602ee1fcb3Sdlg 	{ "rx link xoff",	0x00300160, 32, KSTAT_KV_U_PACKETS },
52612ee1fcb3Sdlg 
52622ee1fcb3Sdlg 	/* Priority XON Received Count */
52632ee1fcb3Sdlg 	/* Priority XOFF Received Count */
52642ee1fcb3Sdlg 	/* Priority XON to XOFF Count */
52652ee1fcb3Sdlg 
52662ee1fcb3Sdlg 	/* PRC64 */
52672ee1fcb3Sdlg 	{ "rx 64B",		0x00300480, 48, KSTAT_KV_U_PACKETS },
52682ee1fcb3Sdlg 	/* PRC127 */
52692ee1fcb3Sdlg 	{ "rx 65-127B",		0x003004A0, 48, KSTAT_KV_U_PACKETS },
52702ee1fcb3Sdlg 	/* PRC255 */
52712ee1fcb3Sdlg 	{ "rx 128-255B",	0x003004C0, 48, KSTAT_KV_U_PACKETS },
52722ee1fcb3Sdlg 	/* PRC511 */
52732ee1fcb3Sdlg 	{ "rx 256-511B",	0x003004E0, 48, KSTAT_KV_U_PACKETS },
52742ee1fcb3Sdlg 	/* PRC1023 */
52752ee1fcb3Sdlg 	{ "rx 512-1023B",	0x00300500, 48, KSTAT_KV_U_PACKETS },
52762ee1fcb3Sdlg 	/* PRC1522 */
52772ee1fcb3Sdlg 	{ "rx 1024-1522B",	0x00300520, 48, KSTAT_KV_U_PACKETS },
52782ee1fcb3Sdlg 	/* PRC9522 */
52792ee1fcb3Sdlg 	{ "rx 1523-9522B",	0x00300540, 48, KSTAT_KV_U_PACKETS },
52802ee1fcb3Sdlg 	/* ROC */
52812ee1fcb3Sdlg 	{ "rx fragment",	0x00300560, 32, KSTAT_KV_U_PACKETS },
52822ee1fcb3Sdlg 	/* RJC */
52832ee1fcb3Sdlg 	{ "rx jabber",		0x00300580, 32, KSTAT_KV_U_PACKETS },
52842ee1fcb3Sdlg 	/* UPRC */
52852ee1fcb3Sdlg 	{ "rx ucasts",		0x003005a0, 48, KSTAT_KV_U_PACKETS },
52862ee1fcb3Sdlg 	/* MPRC */
52872ee1fcb3Sdlg 	{ "rx mcasts",		0x003005c0, 48, KSTAT_KV_U_PACKETS },
52882ee1fcb3Sdlg 	/* BPRC */
52892ee1fcb3Sdlg 	{ "rx bcasts",		0x003005e0, 48, KSTAT_KV_U_PACKETS },
52902ee1fcb3Sdlg 	/* RDPC */
52912ee1fcb3Sdlg 	{ "rx discards",	0x00300600, 32, KSTAT_KV_U_PACKETS },
52922ee1fcb3Sdlg 	/* LDPC */
52932ee1fcb3Sdlg 	{ "rx lo discards",	0x00300620, 32, KSTAT_KV_U_PACKETS },
52942ee1fcb3Sdlg 	/* RUPP */
52952ee1fcb3Sdlg 	{ "rx no dest",		0x00300660, 32, KSTAT_KV_U_PACKETS },
52962ee1fcb3Sdlg 
52972ee1fcb3Sdlg 	/* GOTC */
52982ee1fcb3Sdlg 	{ "tx bytes",		0x00300680, 48, KSTAT_KV_U_BYTES },
52992ee1fcb3Sdlg 	/* PTC64 */
53002ee1fcb3Sdlg 	{ "tx 64B",		0x003006A0, 48, KSTAT_KV_U_PACKETS },
53012ee1fcb3Sdlg 	/* PTC127 */
53022ee1fcb3Sdlg 	{ "tx 65-127B",		0x003006C0, 48, KSTAT_KV_U_PACKETS },
53032ee1fcb3Sdlg 	/* PTC255 */
53042ee1fcb3Sdlg 	{ "tx 128-255B",	0x003006E0, 48, KSTAT_KV_U_PACKETS },
53052ee1fcb3Sdlg 	/* PTC511 */
53062ee1fcb3Sdlg 	{ "tx 256-511B",	0x00300700, 48, KSTAT_KV_U_PACKETS },
53072ee1fcb3Sdlg 	/* PTC1023 */
53082ee1fcb3Sdlg 	{ "tx 512-1023B",	0x00300720, 48, KSTAT_KV_U_PACKETS },
53092ee1fcb3Sdlg 	/* PTC1522 */
53102ee1fcb3Sdlg 	{ "tx 1024-1522B",	0x00300740, 48, KSTAT_KV_U_PACKETS },
53112ee1fcb3Sdlg 	/* PTC9522 */
53122ee1fcb3Sdlg 	{ "tx 1523-9522B",	0x00300760, 48, KSTAT_KV_U_PACKETS },
53132ee1fcb3Sdlg 
53142ee1fcb3Sdlg 	/* Priority XON Transmitted Count */
53152ee1fcb3Sdlg 	/* Priority XOFF Transmitted Count */
53162ee1fcb3Sdlg 
53172ee1fcb3Sdlg 	/* LXONTXC */
53182ee1fcb3Sdlg 	{ "tx link xon",	0x00300980, 48, KSTAT_KV_U_PACKETS },
53192ee1fcb3Sdlg 	/* LXOFFTXC */
53202ee1fcb3Sdlg 	{ "tx link xoff",	0x003009a0, 48, KSTAT_KV_U_PACKETS },
53212ee1fcb3Sdlg 	/* UPTC */
53222ee1fcb3Sdlg 	{ "tx ucasts",		0x003009c0, 48, KSTAT_KV_U_PACKETS },
53232ee1fcb3Sdlg 	/* MPTC */
53242ee1fcb3Sdlg 	{ "tx mcasts",		0x003009e0, 48, KSTAT_KV_U_PACKETS },
53252ee1fcb3Sdlg 	/* BPTC */
53262ee1fcb3Sdlg 	{ "tx bcasts",		0x00300a00, 48, KSTAT_KV_U_PACKETS },
53272ee1fcb3Sdlg 	/* TDOLD */
53282ee1fcb3Sdlg 	{ "tx link down",	0x00300a20, 48, KSTAT_KV_U_PACKETS },
53292ee1fcb3Sdlg };
53302ee1fcb3Sdlg 
53312ee1fcb3Sdlg const struct ixl_counter ixl_vsi_counters[] = {
53322ee1fcb3Sdlg 	/* VSI RDPC */
53332ee1fcb3Sdlg 	{ "rx discards",	0x00310000, 32, KSTAT_KV_U_PACKETS },
53342ee1fcb3Sdlg 	/* VSI GOTC */
53352ee1fcb3Sdlg 	{ "tx bytes",		0x00328000, 48, KSTAT_KV_U_BYTES },
53362ee1fcb3Sdlg 	/* VSI UPTC */
53372ee1fcb3Sdlg 	{ "tx ucasts",		0x0033c000, 48, KSTAT_KV_U_PACKETS },
53382ee1fcb3Sdlg 	/* VSI MPTC */
53392ee1fcb3Sdlg 	{ "tx mcasts",		0x0033cc00, 48, KSTAT_KV_U_PACKETS },
53402ee1fcb3Sdlg 	/* VSI BPTC */
53412ee1fcb3Sdlg 	{ "tx bcasts",		0x0033d800, 48, KSTAT_KV_U_PACKETS },
53422ee1fcb3Sdlg 	/* VSI TEPC */
53432ee1fcb3Sdlg 	{ "tx errs",		0x00344000, 48, KSTAT_KV_U_PACKETS },
53442ee1fcb3Sdlg 	/* VSI TDPC */
53452ee1fcb3Sdlg 	{ "tx discards",	0x00348000, 48, KSTAT_KV_U_PACKETS },
53462ee1fcb3Sdlg 	/* VSI GORC */
53472ee1fcb3Sdlg 	{ "rx bytes",		0x00358000, 48, KSTAT_KV_U_BYTES },
53482ee1fcb3Sdlg 	/* VSI UPRC */
53492ee1fcb3Sdlg 	{ "rx ucasts",		0x0036c000, 48, KSTAT_KV_U_PACKETS },
53502ee1fcb3Sdlg 	/* VSI MPRC */
53512ee1fcb3Sdlg 	{ "rx mcasts",		0x0036cc00, 48, KSTAT_KV_U_PACKETS },
53522ee1fcb3Sdlg 	/* VSI BPRC */
53532ee1fcb3Sdlg 	{ "rx bcasts",		0x0036d800, 48, KSTAT_KV_U_PACKETS },
53542ee1fcb3Sdlg 	/* VSI RUPP */
53552ee1fcb3Sdlg 	{ "rx noproto",		0x0036e400, 32, KSTAT_KV_U_PACKETS },
53562ee1fcb3Sdlg };
53572ee1fcb3Sdlg 
53582ee1fcb3Sdlg struct ixl_counter_state {
53592ee1fcb3Sdlg 	const struct ixl_counter
53602ee1fcb3Sdlg 				*counters;
53612ee1fcb3Sdlg 	uint64_t		*values;
53622ee1fcb3Sdlg 	size_t			 n;
53632ee1fcb3Sdlg 	uint32_t		 index;
53642ee1fcb3Sdlg 	unsigned int		 gen;
53652ee1fcb3Sdlg };
53662ee1fcb3Sdlg 
53672ee1fcb3Sdlg static void
ixl_rd_counters(struct ixl_softc * sc,const struct ixl_counter_state * state,uint64_t * vs)53682ee1fcb3Sdlg ixl_rd_counters(struct ixl_softc *sc, const struct ixl_counter_state *state,
53692ee1fcb3Sdlg     uint64_t *vs)
53702ee1fcb3Sdlg {
53712ee1fcb3Sdlg 	const struct ixl_counter *c;
53722ee1fcb3Sdlg 	bus_addr_t r;
53732ee1fcb3Sdlg 	uint64_t v;
53742ee1fcb3Sdlg 	size_t i;
53752ee1fcb3Sdlg 
53762ee1fcb3Sdlg 	for (i = 0; i < state->n; i++) {
53772ee1fcb3Sdlg 		c = &state->counters[i];
53782ee1fcb3Sdlg 
53792ee1fcb3Sdlg 		r = c->c_base + (state->index * 8);
53802ee1fcb3Sdlg 
53812ee1fcb3Sdlg 		if (c->c_width == 32)
53822ee1fcb3Sdlg 			v = bus_space_read_4(sc->sc_memt, sc->sc_memh, r);
53832ee1fcb3Sdlg 		else
53842ee1fcb3Sdlg 			v = bus_space_read_8(sc->sc_memt, sc->sc_memh, r);
53852ee1fcb3Sdlg 
53862ee1fcb3Sdlg 		vs[i] = v;
53872ee1fcb3Sdlg 	}
53882ee1fcb3Sdlg }
53892ee1fcb3Sdlg 
53902ee1fcb3Sdlg static int
ixl_kstat_read(struct kstat * ks)53912ee1fcb3Sdlg ixl_kstat_read(struct kstat *ks)
53922ee1fcb3Sdlg {
53932ee1fcb3Sdlg 	struct ixl_softc *sc = ks->ks_softc;
53942ee1fcb3Sdlg 	struct kstat_kv *kvs = ks->ks_data;
53952ee1fcb3Sdlg 	struct ixl_counter_state *state = ks->ks_ptr;
53962ee1fcb3Sdlg 	unsigned int gen = (state->gen++) & 1;
53972ee1fcb3Sdlg 	uint64_t *ovs = state->values + (gen * state->n);
53982ee1fcb3Sdlg 	uint64_t *nvs = state->values + (!gen * state->n);
53992ee1fcb3Sdlg 	size_t i;
54002ee1fcb3Sdlg 
54012ee1fcb3Sdlg 	ixl_rd_counters(sc, state, nvs);
54022ee1fcb3Sdlg 	getnanouptime(&ks->ks_updated);
54032ee1fcb3Sdlg 
54042ee1fcb3Sdlg 	for (i = 0; i < state->n; i++) {
54052ee1fcb3Sdlg 		const struct ixl_counter *c = &state->counters[i];
54062ee1fcb3Sdlg 		uint64_t n = nvs[i], o = ovs[i];
54072ee1fcb3Sdlg 
54082ee1fcb3Sdlg 		if (c->c_width < 64) {
54092ee1fcb3Sdlg 			if (n < o)
54102ee1fcb3Sdlg 				n += (1ULL << c->c_width);
54112ee1fcb3Sdlg 		}
54122ee1fcb3Sdlg 
54132ee1fcb3Sdlg 		kstat_kv_u64(&kvs[i]) += (n - o);
54142ee1fcb3Sdlg 	}
54152ee1fcb3Sdlg 
54162ee1fcb3Sdlg 	return (0);
54172ee1fcb3Sdlg }
54182ee1fcb3Sdlg 
54192ee1fcb3Sdlg static void
ixl_kstat_tick(void * arg)54202ee1fcb3Sdlg ixl_kstat_tick(void *arg)
54212ee1fcb3Sdlg {
54222ee1fcb3Sdlg 	struct ixl_softc *sc = arg;
54232ee1fcb3Sdlg 
54242ee1fcb3Sdlg 	timeout_add_sec(&sc->sc_kstat_tmo, 4);
54252ee1fcb3Sdlg 
5426cd21026bSdlg 	mtx_enter(&sc->sc_kstat_mtx);
54272ee1fcb3Sdlg 
54282ee1fcb3Sdlg 	ixl_kstat_read(sc->sc_port_kstat);
54292ee1fcb3Sdlg 	ixl_kstat_read(sc->sc_vsi_kstat);
54302ee1fcb3Sdlg 
54312ee1fcb3Sdlg 	mtx_leave(&sc->sc_kstat_mtx);
54322ee1fcb3Sdlg }
54332ee1fcb3Sdlg 
54342ee1fcb3Sdlg static struct kstat *
ixl_kstat_create(struct ixl_softc * sc,const char * name,const struct ixl_counter * counters,size_t n,uint32_t index)54352ee1fcb3Sdlg ixl_kstat_create(struct ixl_softc *sc, const char *name,
54362ee1fcb3Sdlg     const struct ixl_counter *counters, size_t n, uint32_t index)
54372ee1fcb3Sdlg {
54382ee1fcb3Sdlg 	struct kstat *ks;
54392ee1fcb3Sdlg 	struct kstat_kv *kvs;
54402ee1fcb3Sdlg 	struct ixl_counter_state *state;
54412ee1fcb3Sdlg 	const struct ixl_counter *c;
54422ee1fcb3Sdlg 	unsigned int i;
54432ee1fcb3Sdlg 
54442ee1fcb3Sdlg 	ks = kstat_create(DEVNAME(sc), 0, name, 0, KSTAT_T_KV, 0);
54452ee1fcb3Sdlg 	if (ks == NULL) {
54462ee1fcb3Sdlg 		/* unable to create kstats */
54472ee1fcb3Sdlg 		return (NULL);
54482ee1fcb3Sdlg 	}
54492ee1fcb3Sdlg 
54502ee1fcb3Sdlg 	kvs = mallocarray(n, sizeof(*kvs), M_DEVBUF, M_WAITOK|M_ZERO);
54512ee1fcb3Sdlg 	for (i = 0; i < n; i++) {
54522ee1fcb3Sdlg 		c = &counters[i];
54532ee1fcb3Sdlg 
54542ee1fcb3Sdlg 		kstat_kv_unit_init(&kvs[i], c->c_name,
54552ee1fcb3Sdlg 		    KSTAT_KV_T_COUNTER64, c->c_type);
54562ee1fcb3Sdlg 	}
54572ee1fcb3Sdlg 
54582ee1fcb3Sdlg 	ks->ks_data = kvs;
54592ee1fcb3Sdlg 	ks->ks_datalen = n * sizeof(*kvs);
54602ee1fcb3Sdlg 	ks->ks_read = ixl_kstat_read;
54612ee1fcb3Sdlg 
54622ee1fcb3Sdlg 	state = malloc(sizeof(*state), M_DEVBUF, M_WAITOK|M_ZERO);
54632ee1fcb3Sdlg 	state->counters = counters;
54642ee1fcb3Sdlg 	state->n = n;
54652ee1fcb3Sdlg 	state->values = mallocarray(n * 2, sizeof(*state->values),
54662ee1fcb3Sdlg 	    M_DEVBUF, M_WAITOK|M_ZERO);
54672ee1fcb3Sdlg 	state->index = index;
54682ee1fcb3Sdlg 	ks->ks_ptr = state;
54692ee1fcb3Sdlg 
54702ee1fcb3Sdlg 	kstat_set_mutex(ks, &sc->sc_kstat_mtx);
54712ee1fcb3Sdlg 	ks->ks_softc = sc;
54722ee1fcb3Sdlg 	kstat_install(ks);
54732ee1fcb3Sdlg 
54742ee1fcb3Sdlg 	/* fetch a baseline */
54752ee1fcb3Sdlg 	ixl_rd_counters(sc, state, state->values);
54762ee1fcb3Sdlg 
54772ee1fcb3Sdlg 	return (ks);
54782ee1fcb3Sdlg }
54792ee1fcb3Sdlg 
54802ee1fcb3Sdlg static void
ixl_kstat_attach(struct ixl_softc * sc)54812ee1fcb3Sdlg ixl_kstat_attach(struct ixl_softc *sc)
54822ee1fcb3Sdlg {
54832ee1fcb3Sdlg 	mtx_init(&sc->sc_kstat_mtx, IPL_SOFTCLOCK);
54842ee1fcb3Sdlg 	timeout_set(&sc->sc_kstat_tmo, ixl_kstat_tick, sc);
54852ee1fcb3Sdlg 
54862ee1fcb3Sdlg 	sc->sc_port_kstat = ixl_kstat_create(sc, "ixl-port",
54872ee1fcb3Sdlg 	    ixl_port_counters, nitems(ixl_port_counters), sc->sc_port);
54882ee1fcb3Sdlg 	sc->sc_vsi_kstat = ixl_kstat_create(sc, "ixl-vsi",
54892ee1fcb3Sdlg 	    ixl_vsi_counters, nitems(ixl_vsi_counters),
54902ee1fcb3Sdlg 	    lemtoh16(&sc->sc_vsi_number));
54912ee1fcb3Sdlg 
54922ee1fcb3Sdlg 	/* ixl counters go up even when the interface is down */
54932ee1fcb3Sdlg 	timeout_add_sec(&sc->sc_kstat_tmo, 4);
54942ee1fcb3Sdlg }
54952ee1fcb3Sdlg 
54962ee1fcb3Sdlg #endif /* NKSTAT > 0 */
5497