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