xref: /freebsd/sys/dev/aq/aq_main.c (revision 2b587c0c8a933cd110ae579366644a280c509b7f)
1493d26c5SEd Maste /*
2493d26c5SEd Maste  * aQuantia Corporation Network Driver
3493d26c5SEd Maste  * Copyright (C) 2019 aQuantia Corporation. All rights reserved
4493d26c5SEd Maste  *
5493d26c5SEd Maste  * Redistribution and use in source and binary forms, with or without
6493d26c5SEd Maste  * modification, are permitted provided that the following conditions
7493d26c5SEd Maste  * are met:
8493d26c5SEd Maste  *
9493d26c5SEd Maste  *   (1) Redistributions of source code must retain the above
10493d26c5SEd Maste  *   copyright notice, this list of conditions and the following
11493d26c5SEd Maste  *   disclaimer.
12493d26c5SEd Maste  *
13493d26c5SEd Maste  *   (2) Redistributions in binary form must reproduce the above
14493d26c5SEd Maste  *   copyright notice, this list of conditions and the following
15493d26c5SEd Maste  *   disclaimer in the documentation and/or other materials provided
16493d26c5SEd Maste  *   with the distribution.
17493d26c5SEd Maste  *
18493d26c5SEd Maste  *   (3)The name of the author may not be used to endorse or promote
19493d26c5SEd Maste  *   products derived from this software without specific prior
20493d26c5SEd Maste  *   written permission.
21493d26c5SEd Maste  *
22493d26c5SEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23493d26c5SEd Maste  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24493d26c5SEd Maste  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25493d26c5SEd Maste  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
26493d26c5SEd Maste  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27493d26c5SEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
28493d26c5SEd Maste  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29493d26c5SEd Maste  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30493d26c5SEd Maste  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31493d26c5SEd Maste  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32493d26c5SEd Maste  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33493d26c5SEd Maste  */
34493d26c5SEd Maste 
35493d26c5SEd Maste 
36493d26c5SEd Maste #include <sys/cdefs.h>
37493d26c5SEd Maste __FBSDID("$FreeBSD$");
38493d26c5SEd Maste 
39493d26c5SEd Maste #include <sys/param.h>
40493d26c5SEd Maste #include <sys/malloc.h>
41493d26c5SEd Maste #include <sys/socket.h>
42493d26c5SEd Maste #include <sys/kernel.h>
43493d26c5SEd Maste #include <sys/bus.h>
44493d26c5SEd Maste #include <sys/module.h>
45493d26c5SEd Maste #include <sys/rman.h>
46493d26c5SEd Maste #include <sys/endian.h>
47493d26c5SEd Maste #include <sys/sockio.h>
48493d26c5SEd Maste #include <sys/priv.h>
49493d26c5SEd Maste #include <sys/sysctl.h>
50493d26c5SEd Maste #include <sys/sbuf.h>
51493d26c5SEd Maste #include <sys/bitstring.h>
52493d26c5SEd Maste 
53493d26c5SEd Maste #include <machine/bus.h>
54493d26c5SEd Maste #include <machine/resource.h>
55493d26c5SEd Maste 
56493d26c5SEd Maste #include <dev/pci/pcireg.h>
57493d26c5SEd Maste #include <dev/pci/pcivar.h>
58493d26c5SEd Maste 
59493d26c5SEd Maste #include <net/if.h>
60493d26c5SEd Maste #include <net/if_media.h>
61493d26c5SEd Maste #include <net/if_var.h>
62493d26c5SEd Maste #include <net/if_dl.h>
63493d26c5SEd Maste #include <net/ethernet.h>
64493d26c5SEd Maste #include <net/iflib.h>
65493d26c5SEd Maste #include <net/rss_config.h>
66493d26c5SEd Maste 
67493d26c5SEd Maste #include "opt_inet.h"
68493d26c5SEd Maste #include "opt_inet6.h"
69493d26c5SEd Maste #include "opt_rss.h"
70493d26c5SEd Maste 
71493d26c5SEd Maste #include "ifdi_if.h"
72493d26c5SEd Maste 
73493d26c5SEd Maste #include "aq_device.h"
74493d26c5SEd Maste #include "aq_fw.h"
75493d26c5SEd Maste #include "aq_hw.h"
76493d26c5SEd Maste #include "aq_hw_llh.h"
77493d26c5SEd Maste #include "aq_ring.h"
78493d26c5SEd Maste #include "aq_dbg.h"
79493d26c5SEd Maste 
80493d26c5SEd Maste 
81493d26c5SEd Maste #define	AQ_XXX_UNIMPLEMENTED_FUNCTION	do {				\
82493d26c5SEd Maste 	printf("atlantic: unimplemented function: %s@%s:%d\n", __func__, 	\
83493d26c5SEd Maste 	    __FILE__, __LINE__);					\
84493d26c5SEd Maste } while (0)
85493d26c5SEd Maste 
86493d26c5SEd Maste MALLOC_DEFINE(M_AQ, "aq", "Aquantia");
87493d26c5SEd Maste 
88493d26c5SEd Maste char aq_driver_version[] = AQ_VER;
89493d26c5SEd Maste 
90493d26c5SEd Maste #define AQUANTIA_VENDOR_ID 0x1D6A
91493d26c5SEd Maste 
92493d26c5SEd Maste #define AQ_DEVICE_ID_0001	0x0001
93493d26c5SEd Maste #define AQ_DEVICE_ID_D100	0xD100
94493d26c5SEd Maste #define AQ_DEVICE_ID_D107	0xD107
95493d26c5SEd Maste #define AQ_DEVICE_ID_D108	0xD108
96493d26c5SEd Maste #define AQ_DEVICE_ID_D109	0xD109
97493d26c5SEd Maste 
98493d26c5SEd Maste #define AQ_DEVICE_ID_AQC100	0x00B1
99493d26c5SEd Maste #define AQ_DEVICE_ID_AQC107	0x07B1
100493d26c5SEd Maste #define AQ_DEVICE_ID_AQC108	0x08B1
101493d26c5SEd Maste #define AQ_DEVICE_ID_AQC109	0x09B1
102493d26c5SEd Maste #define AQ_DEVICE_ID_AQC111	0x11B1
103493d26c5SEd Maste #define AQ_DEVICE_ID_AQC112	0x12B1
104493d26c5SEd Maste 
105493d26c5SEd Maste #define AQ_DEVICE_ID_AQC100S	0x80B1
106493d26c5SEd Maste #define AQ_DEVICE_ID_AQC107S	0x87B1
107493d26c5SEd Maste #define AQ_DEVICE_ID_AQC108S	0x88B1
108493d26c5SEd Maste #define AQ_DEVICE_ID_AQC109S	0x89B1
109493d26c5SEd Maste #define AQ_DEVICE_ID_AQC111S	0x91B1
110493d26c5SEd Maste #define AQ_DEVICE_ID_AQC112S	0x92B1
111493d26c5SEd Maste 
112493d26c5SEd Maste static pci_vendor_info_t aq_vendor_info_array[] = {
113493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_0001, "Aquantia AQtion 10Gbit Network Adapter"),
114493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_D107, "Aquantia AQtion 10Gbit Network Adapter"),
115493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_D108, "Aquantia AQtion 5Gbit Network Adapter"),
116493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_D109, "Aquantia AQtion 2.5Gbit Network Adapter"),
117493d26c5SEd Maste 
118493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC107, "Aquantia AQtion 10Gbit Network Adapter"),
119493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC108, "Aquantia AQtion 5Gbit Network Adapter"),
120493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC109, "Aquantia AQtion 2.5Gbit Network Adapter"),
121493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC100, "Aquantia AQtion 10Gbit Network Adapter"),
122493d26c5SEd Maste 
123493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC107S, "Aquantia AQtion 10Gbit Network Adapter"),
124493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC108S, "Aquantia AQtion 5Gbit Network Adapter"),
125493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC109S, "Aquantia AQtion 2.5Gbit Network Adapter"),
126493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC100S, "Aquantia AQtion 10Gbit Network Adapter"),
127493d26c5SEd Maste 
128493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC111, "Aquantia AQtion 5Gbit Network Adapter"),
129493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC112, "Aquantia AQtion 2.5Gbit Network Adapter"),
130493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC111S, "Aquantia AQtion 5Gbit Network Adapter"),
131493d26c5SEd Maste 	PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC112S, "Aquantia AQtion 2.5Gbit Network Adapter"),
132493d26c5SEd Maste 
133493d26c5SEd Maste 	PVID_END
134493d26c5SEd Maste };
135493d26c5SEd Maste 
136493d26c5SEd Maste 
137493d26c5SEd Maste /* Device setup, teardown, etc */
138493d26c5SEd Maste static void *aq_register(device_t dev);
139493d26c5SEd Maste static int aq_if_attach_pre(if_ctx_t ctx);
140493d26c5SEd Maste static int aq_if_attach_post(if_ctx_t ctx);
141493d26c5SEd Maste static int aq_if_detach(if_ctx_t ctx);
142493d26c5SEd Maste static int aq_if_shutdown(if_ctx_t ctx);
143493d26c5SEd Maste static int aq_if_suspend(if_ctx_t ctx);
144493d26c5SEd Maste static int aq_if_resume(if_ctx_t ctx);
145493d26c5SEd Maste 
146493d26c5SEd Maste /* Soft queue setup and teardown */
147493d26c5SEd Maste static int aq_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs,
148493d26c5SEd Maste 		    uint64_t *paddrs, int ntxqs, int ntxqsets);
149493d26c5SEd Maste static int aq_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs,
150493d26c5SEd Maste 		    uint64_t *paddrs, int nrxqs, int nrxqsets);
151493d26c5SEd Maste static void aq_if_queues_free(if_ctx_t ctx);
152493d26c5SEd Maste 
153493d26c5SEd Maste /* Device configuration */
154493d26c5SEd Maste static void aq_if_init(if_ctx_t ctx);
155493d26c5SEd Maste static void aq_if_stop(if_ctx_t ctx);
156493d26c5SEd Maste static void aq_if_multi_set(if_ctx_t ctx);
157493d26c5SEd Maste static int aq_if_mtu_set(if_ctx_t ctx, uint32_t mtu);
158493d26c5SEd Maste static void aq_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr);
159493d26c5SEd Maste static int aq_if_media_change(if_ctx_t ctx);
160493d26c5SEd Maste static int aq_if_promisc_set(if_ctx_t ctx, int flags);
161493d26c5SEd Maste static uint64_t aq_if_get_counter(if_ctx_t ctx, ift_counter cnt);
162493d26c5SEd Maste static void aq_if_timer(if_ctx_t ctx, uint16_t qid);
163493d26c5SEd Maste static int aq_if_priv_ioctl(if_ctx_t ctx, u_long command, caddr_t data);
164493d26c5SEd Maste static int aq_hw_capabilities(struct aq_dev *softc);
165493d26c5SEd Maste static void aq_add_stats_sysctls(struct aq_dev *softc);
166493d26c5SEd Maste 
167493d26c5SEd Maste /* Interrupt enable / disable */
168493d26c5SEd Maste static void	aq_if_enable_intr(if_ctx_t ctx);
169493d26c5SEd Maste static void	aq_if_disable_intr(if_ctx_t ctx);
170493d26c5SEd Maste static int	aq_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid);
171493d26c5SEd Maste static int	aq_if_msix_intr_assign(if_ctx_t ctx, int msix);
172493d26c5SEd Maste 
173493d26c5SEd Maste /* VLAN support */
174493d26c5SEd Maste static bool aq_is_vlan_promisc_required(struct aq_dev *softc);
175493d26c5SEd Maste static void aq_update_vlan_filters(struct aq_dev *softc);
176493d26c5SEd Maste static void aq_if_vlan_register(if_ctx_t ctx, uint16_t vtag);
177493d26c5SEd Maste static void aq_if_vlan_unregister(if_ctx_t ctx, uint16_t vtag);
178493d26c5SEd Maste 
179493d26c5SEd Maste /* Informational/diagnostic */
180493d26c5SEd Maste static void	aq_if_debug(if_ctx_t ctx);
181493d26c5SEd Maste static void	aq_if_led_func(if_ctx_t ctx, int onoff);
182493d26c5SEd Maste 
183493d26c5SEd Maste static device_method_t aq_methods[] = {
184493d26c5SEd Maste 	DEVMETHOD(device_register, aq_register),
185493d26c5SEd Maste 	DEVMETHOD(device_probe, iflib_device_probe),
186493d26c5SEd Maste 	DEVMETHOD(device_attach, iflib_device_attach),
187493d26c5SEd Maste 	DEVMETHOD(device_detach, iflib_device_detach),
188493d26c5SEd Maste 	DEVMETHOD(device_shutdown, iflib_device_shutdown),
189493d26c5SEd Maste 	DEVMETHOD(device_suspend, iflib_device_suspend),
190493d26c5SEd Maste 	DEVMETHOD(device_resume, iflib_device_resume),
191493d26c5SEd Maste 
192493d26c5SEd Maste 	DEVMETHOD_END
193493d26c5SEd Maste };
194493d26c5SEd Maste 
195493d26c5SEd Maste static driver_t aq_driver = {
196493d26c5SEd Maste 	"aq", aq_methods, sizeof(struct aq_dev),
197493d26c5SEd Maste };
198493d26c5SEd Maste 
199*2b587c0cSJohn Baldwin #if __FreeBSD_version >= 1400058
200*2b587c0cSJohn Baldwin DRIVER_MODULE(atlantic, pci, aq_driver, 0, 0);
201*2b587c0cSJohn Baldwin #else
202493d26c5SEd Maste static devclass_t aq_devclass;
203493d26c5SEd Maste DRIVER_MODULE(atlantic, pci, aq_driver, aq_devclass, 0, 0);
204*2b587c0cSJohn Baldwin #endif
205493d26c5SEd Maste 
206493d26c5SEd Maste MODULE_DEPEND(atlantic, pci, 1, 1, 1);
207493d26c5SEd Maste MODULE_DEPEND(atlantic, ether, 1, 1, 1);
208493d26c5SEd Maste MODULE_DEPEND(atlantic, iflib, 1, 1, 1);
209493d26c5SEd Maste 
210493d26c5SEd Maste IFLIB_PNP_INFO(pci, atlantic, aq_vendor_info_array);
211493d26c5SEd Maste 
212493d26c5SEd Maste static device_method_t aq_if_methods[] = {
213493d26c5SEd Maste 	/* Device setup, teardown, etc */
214493d26c5SEd Maste 	DEVMETHOD(ifdi_attach_pre, aq_if_attach_pre),
215493d26c5SEd Maste 	DEVMETHOD(ifdi_attach_post, aq_if_attach_post),
216493d26c5SEd Maste 	DEVMETHOD(ifdi_detach, aq_if_detach),
217493d26c5SEd Maste 
218493d26c5SEd Maste 	DEVMETHOD(ifdi_shutdown, aq_if_shutdown),
219493d26c5SEd Maste 	DEVMETHOD(ifdi_suspend, aq_if_suspend),
220493d26c5SEd Maste 	DEVMETHOD(ifdi_resume, aq_if_resume),
221493d26c5SEd Maste 
222493d26c5SEd Maste 	/* Soft queue setup and teardown */
223493d26c5SEd Maste 	DEVMETHOD(ifdi_tx_queues_alloc, aq_if_tx_queues_alloc),
224493d26c5SEd Maste 	DEVMETHOD(ifdi_rx_queues_alloc, aq_if_rx_queues_alloc),
225493d26c5SEd Maste 	DEVMETHOD(ifdi_queues_free, aq_if_queues_free),
226493d26c5SEd Maste 
227493d26c5SEd Maste 	/* Device configuration */
228493d26c5SEd Maste 	DEVMETHOD(ifdi_init, aq_if_init),
229493d26c5SEd Maste 	DEVMETHOD(ifdi_stop, aq_if_stop),
230493d26c5SEd Maste 	DEVMETHOD(ifdi_multi_set, aq_if_multi_set),
231493d26c5SEd Maste 	DEVMETHOD(ifdi_mtu_set, aq_if_mtu_set),
232493d26c5SEd Maste 	DEVMETHOD(ifdi_media_status, aq_if_media_status),
233493d26c5SEd Maste 	DEVMETHOD(ifdi_media_change, aq_if_media_change),
234493d26c5SEd Maste 	DEVMETHOD(ifdi_promisc_set, aq_if_promisc_set),
235493d26c5SEd Maste 	DEVMETHOD(ifdi_get_counter, aq_if_get_counter),
236493d26c5SEd Maste 	DEVMETHOD(ifdi_update_admin_status, aq_if_update_admin_status),
237493d26c5SEd Maste 	DEVMETHOD(ifdi_timer, aq_if_timer),
238493d26c5SEd Maste //	DEVMETHOD(ifdi_priv_ioctl, aq_if_priv_ioctl),
239493d26c5SEd Maste 
240493d26c5SEd Maste 	/* Interrupt enable / disable */
241493d26c5SEd Maste 	DEVMETHOD(ifdi_intr_enable, aq_if_enable_intr),
242493d26c5SEd Maste 	DEVMETHOD(ifdi_intr_disable, aq_if_disable_intr),
243493d26c5SEd Maste 	DEVMETHOD(ifdi_rx_queue_intr_enable, aq_if_rx_queue_intr_enable),
244493d26c5SEd Maste 	DEVMETHOD(ifdi_tx_queue_intr_enable, aq_if_rx_queue_intr_enable),
245493d26c5SEd Maste 	DEVMETHOD(ifdi_msix_intr_assign, aq_if_msix_intr_assign),
246493d26c5SEd Maste 
247493d26c5SEd Maste 	/* VLAN support */
248493d26c5SEd Maste 	DEVMETHOD(ifdi_vlan_register, aq_if_vlan_register),
249493d26c5SEd Maste 	DEVMETHOD(ifdi_vlan_unregister, aq_if_vlan_unregister),
250493d26c5SEd Maste 
251493d26c5SEd Maste 	/* Informational/diagnostic */
252493d26c5SEd Maste 	DEVMETHOD(ifdi_led_func, aq_if_led_func),
253493d26c5SEd Maste //	DEVMETHOD(ifdi_debug, aq_if_debug),
254493d26c5SEd Maste 
255493d26c5SEd Maste 	DEVMETHOD_END
256493d26c5SEd Maste };
257493d26c5SEd Maste 
258493d26c5SEd Maste static driver_t aq_if_driver = {
259493d26c5SEd Maste 	"aq_if", aq_if_methods, sizeof(struct aq_dev)
260493d26c5SEd Maste };
261493d26c5SEd Maste 
262493d26c5SEd Maste static struct if_shared_ctx aq_sctx_init = {
263493d26c5SEd Maste 	.isc_magic = IFLIB_MAGIC,
264493d26c5SEd Maste 	.isc_q_align = PAGE_SIZE,
265493d26c5SEd Maste 	.isc_tx_maxsize = HW_ATL_B0_TSO_SIZE,
266493d26c5SEd Maste 	.isc_tx_maxsegsize = HW_ATL_B0_MTU_JUMBO,
267493d26c5SEd Maste #if __FreeBSD__ >= 12
268493d26c5SEd Maste 	.isc_tso_maxsize = HW_ATL_B0_TSO_SIZE,
269493d26c5SEd Maste 	.isc_tso_maxsegsize = HW_ATL_B0_MTU_JUMBO,
270493d26c5SEd Maste #endif
271493d26c5SEd Maste 	.isc_rx_maxsize = HW_ATL_B0_MTU_JUMBO,
272493d26c5SEd Maste 	.isc_rx_nsegments = 16,
273493d26c5SEd Maste 	.isc_rx_maxsegsize = PAGE_SIZE,
274493d26c5SEd Maste 	.isc_nfl = 1,
275493d26c5SEd Maste 	.isc_nrxqs = 1,
276493d26c5SEd Maste 	.isc_ntxqs = 1,
277493d26c5SEd Maste 	.isc_admin_intrcnt = 1,
278493d26c5SEd Maste 	.isc_vendor_info = aq_vendor_info_array,
279493d26c5SEd Maste 	.isc_driver_version = aq_driver_version,
280493d26c5SEd Maste 	.isc_driver = &aq_if_driver,
281493d26c5SEd Maste 	.isc_flags = IFLIB_NEED_SCRATCH | IFLIB_TSO_INIT_IP |
282493d26c5SEd Maste 	    IFLIB_NEED_ZERO_CSUM,
283493d26c5SEd Maste 
284493d26c5SEd Maste 	.isc_nrxd_min = {HW_ATL_B0_MIN_RXD},
285493d26c5SEd Maste 	.isc_ntxd_min = {HW_ATL_B0_MIN_TXD},
286493d26c5SEd Maste 	.isc_nrxd_max = {HW_ATL_B0_MAX_RXD},
287493d26c5SEd Maste 	.isc_ntxd_max = {HW_ATL_B0_MAX_TXD},
288493d26c5SEd Maste 	.isc_nrxd_default = {PAGE_SIZE / sizeof(aq_txc_desc_t) * 4},
289493d26c5SEd Maste 	.isc_ntxd_default = {PAGE_SIZE / sizeof(aq_txc_desc_t) * 4},
290493d26c5SEd Maste };
291493d26c5SEd Maste 
292493d26c5SEd Maste /*
293493d26c5SEd Maste  * TUNEABLE PARAMETERS:
294493d26c5SEd Maste  */
295493d26c5SEd Maste 
296493d26c5SEd Maste static SYSCTL_NODE(_hw, OID_AUTO, aq, CTLFLAG_RD, 0, "Atlantic driver parameters");
297493d26c5SEd Maste /* UDP Receive-Side Scaling */
298493d26c5SEd Maste static int aq_enable_rss_udp = 1;
299493d26c5SEd Maste SYSCTL_INT(_hw_aq, OID_AUTO, enable_rss_udp, CTLFLAG_RDTUN, &aq_enable_rss_udp, 0,
300493d26c5SEd Maste     "Enable Receive-Side Scaling (RSS) for UDP");
301493d26c5SEd Maste 
302493d26c5SEd Maste 
303493d26c5SEd Maste /*
304493d26c5SEd Maste  * Device Methods
305493d26c5SEd Maste  */
306493d26c5SEd Maste static void *aq_register(device_t dev)
307493d26c5SEd Maste {
308493d26c5SEd Maste 	return (&aq_sctx_init);
309493d26c5SEd Maste }
310493d26c5SEd Maste 
311493d26c5SEd Maste static int aq_if_attach_pre(if_ctx_t ctx)
312493d26c5SEd Maste {
313493d26c5SEd Maste 	struct aq_dev *softc;
314493d26c5SEd Maste 	struct aq_hw *hw;
315493d26c5SEd Maste 	if_softc_ctx_t scctx;
316493d26c5SEd Maste 	int rc;
317493d26c5SEd Maste 
318493d26c5SEd Maste 	AQ_DBG_ENTER();
319493d26c5SEd Maste 	softc = iflib_get_softc(ctx);
320493d26c5SEd Maste 	rc = 0;
321493d26c5SEd Maste 
322493d26c5SEd Maste 	softc->ctx = ctx;
323493d26c5SEd Maste 	softc->dev = iflib_get_dev(ctx);
324493d26c5SEd Maste 	softc->media = iflib_get_media(ctx);
325493d26c5SEd Maste 	softc->scctx = iflib_get_softc_ctx(ctx);
326493d26c5SEd Maste 	softc->sctx = iflib_get_sctx(ctx);
327493d26c5SEd Maste 	scctx = softc->scctx;
328493d26c5SEd Maste 
329493d26c5SEd Maste 	softc->mmio_rid = PCIR_BAR(0);
330493d26c5SEd Maste 	softc->mmio_res = bus_alloc_resource_any(softc->dev, SYS_RES_MEMORY,
331493d26c5SEd Maste 	    &softc->mmio_rid, RF_ACTIVE|RF_SHAREABLE);
332493d26c5SEd Maste 	if (softc->mmio_res == NULL) {
333493d26c5SEd Maste 		device_printf(softc->dev,
334493d26c5SEd Maste 		    "failed to allocate MMIO resources\n");
335493d26c5SEd Maste 		rc = ENXIO;
336493d26c5SEd Maste 		goto fail;
337493d26c5SEd Maste 	}
338493d26c5SEd Maste 
339493d26c5SEd Maste 	softc->mmio_tag = rman_get_bustag(softc->mmio_res);
340493d26c5SEd Maste 	softc->mmio_handle = rman_get_bushandle(softc->mmio_res);
341493d26c5SEd Maste 	softc->mmio_size = rman_get_size(softc->mmio_res);
342493d26c5SEd Maste 	softc->hw.hw_addr = (u8*) softc->mmio_handle;
343493d26c5SEd Maste 	hw = &softc->hw;
344493d26c5SEd Maste 	hw->link_rate = aq_fw_speed_auto;
345493d26c5SEd Maste 	hw->itr = -1;
346493d26c5SEd Maste 	hw->fc.fc_rx = 1;
347493d26c5SEd Maste 	hw->fc.fc_tx = 1;
348493d26c5SEd Maste 	softc->linkup = 0U;
349493d26c5SEd Maste 
350493d26c5SEd Maste 	/* Look up ops and caps. */
351493d26c5SEd Maste 	rc = aq_hw_mpi_create(hw);
352493d26c5SEd Maste 	if (rc < 0) {
353493d26c5SEd Maste 		AQ_DBG_ERROR(" %s: aq_hw_mpi_create fail err=%d", __func__, rc);
354493d26c5SEd Maste 		goto fail;
355493d26c5SEd Maste 	}
356493d26c5SEd Maste 
357493d26c5SEd Maste 	if (hw->fast_start_enabled) {
358493d26c5SEd Maste 		if (hw->fw_ops && hw->fw_ops->reset)
359493d26c5SEd Maste 			hw->fw_ops->reset(hw);
360493d26c5SEd Maste 	} else
361493d26c5SEd Maste 		aq_hw_reset(&softc->hw);
362493d26c5SEd Maste 	aq_hw_capabilities(softc);
363493d26c5SEd Maste 
364493d26c5SEd Maste 	if (aq_hw_get_mac_permanent(hw, hw->mac_addr) < 0) {
365493d26c5SEd Maste 		AQ_DBG_ERROR("Unable to get mac addr from hw");
366493d26c5SEd Maste 		goto fail;
367493d26c5SEd Maste 	};
368493d26c5SEd Maste 
369493d26c5SEd Maste 	softc->admin_ticks = 0;
370493d26c5SEd Maste 
371493d26c5SEd Maste 	iflib_set_mac(ctx, hw->mac_addr);
372493d26c5SEd Maste #if __FreeBSD__ < 13
373493d26c5SEd Maste 	/* since FreeBSD13 deadlock due to calling iflib_led_func() under CTX_LOCK() */
374493d26c5SEd Maste 	iflib_led_create(ctx);
375493d26c5SEd Maste #endif
376493d26c5SEd Maste 	scctx->isc_tx_csum_flags = CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_TSO;
377493d26c5SEd Maste #if __FreeBSD__ >= 12
378493d26c5SEd Maste 	scctx->isc_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_HWCSUM | IFCAP_TSO |
379493d26c5SEd Maste 							  IFCAP_JUMBO_MTU | IFCAP_VLAN_HWFILTER |
380493d26c5SEd Maste 							  IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
381493d26c5SEd Maste 							  IFCAP_VLAN_HWCSUM;
382493d26c5SEd Maste 	scctx->isc_capenable = scctx->isc_capabilities;
383493d26c5SEd Maste #else
384493d26c5SEd Maste 	if_t ifp;
385493d26c5SEd Maste 	ifp = iflib_get_ifp(ctx);
3864756f5ffSOlivier Cochard 	if_setcapenable(ifp,  IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_HWCSUM | IFCAP_TSO |
387493d26c5SEd Maste 							  IFCAP_JUMBO_MTU | IFCAP_VLAN_HWFILTER |
388493d26c5SEd Maste 							  IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
389493d26c5SEd Maste 							  IFCAP_VLAN_HWCSUM;
390493d26c5SEd Maste #endif
391493d26c5SEd Maste 	scctx->isc_tx_nsegments = 31,
392493d26c5SEd Maste 	scctx->isc_tx_tso_segments_max = 31;
393493d26c5SEd Maste 	scctx->isc_tx_tso_size_max = HW_ATL_B0_TSO_SIZE - sizeof(struct ether_vlan_header);
394493d26c5SEd Maste 	scctx->isc_tx_tso_segsize_max = HW_ATL_B0_MTU_JUMBO;
395493d26c5SEd Maste 	scctx->isc_min_frame_size = 52;
396493d26c5SEd Maste 	scctx->isc_txrx = &aq_txrx;
397493d26c5SEd Maste 
398493d26c5SEd Maste 	scctx->isc_txqsizes[0] = sizeof(aq_tx_desc_t) * scctx->isc_ntxd[0];
399493d26c5SEd Maste 	scctx->isc_rxqsizes[0] = sizeof(aq_rx_desc_t) * scctx->isc_nrxd[0];
400493d26c5SEd Maste 
401493d26c5SEd Maste 	scctx->isc_ntxqsets_max = HW_ATL_B0_RINGS_MAX;
402493d26c5SEd Maste 	scctx->isc_nrxqsets_max = HW_ATL_B0_RINGS_MAX;
403493d26c5SEd Maste 
404493d26c5SEd Maste 	/* iflib will map and release this bar */
405493d26c5SEd Maste 	scctx->isc_msix_bar = pci_msix_table_bar(softc->dev);
406493d26c5SEd Maste 
407493d26c5SEd Maste 	softc->vlan_tags  = bit_alloc(4096, M_AQ, M_NOWAIT);
408493d26c5SEd Maste 
409493d26c5SEd Maste 	AQ_DBG_EXIT(rc);
410493d26c5SEd Maste 	return (rc);
411493d26c5SEd Maste 
412493d26c5SEd Maste fail:
413493d26c5SEd Maste 	if (softc->mmio_res != NULL)
414493d26c5SEd Maste 		bus_release_resource(softc->dev, SYS_RES_MEMORY,
415493d26c5SEd Maste 		    softc->mmio_rid, softc->mmio_res);
416493d26c5SEd Maste 
417493d26c5SEd Maste 	AQ_DBG_EXIT(rc);
418493d26c5SEd Maste 	return (ENXIO);
419493d26c5SEd Maste }
420493d26c5SEd Maste 
421493d26c5SEd Maste 
422493d26c5SEd Maste static int aq_if_attach_post(if_ctx_t ctx)
423493d26c5SEd Maste {
424493d26c5SEd Maste 	struct aq_dev *softc;
425493d26c5SEd Maste 	int rc;
426493d26c5SEd Maste 
427493d26c5SEd Maste 	AQ_DBG_ENTER();
428493d26c5SEd Maste 
429493d26c5SEd Maste 	softc = iflib_get_softc(ctx);
430493d26c5SEd Maste 	rc = 0;
431493d26c5SEd Maste 
432493d26c5SEd Maste 	aq_update_hw_stats(softc);
433493d26c5SEd Maste 
434493d26c5SEd Maste 	aq_initmedia(softc);
435493d26c5SEd Maste 
436493d26c5SEd Maste 
437493d26c5SEd Maste 	switch (softc->scctx->isc_intr) {
438493d26c5SEd Maste 	case IFLIB_INTR_LEGACY:
439493d26c5SEd Maste 		rc = EOPNOTSUPP;
440493d26c5SEd Maste 		goto exit;
441493d26c5SEd Maste         goto exit;
442493d26c5SEd Maste 		break;
443493d26c5SEd Maste 	case IFLIB_INTR_MSI:
444493d26c5SEd Maste 		break;
445493d26c5SEd Maste 	case IFLIB_INTR_MSIX:
446493d26c5SEd Maste 		break;
447493d26c5SEd Maste 	default:
448493d26c5SEd Maste 		device_printf(softc->dev, "unknown interrupt mode\n");
449493d26c5SEd Maste 		rc = EOPNOTSUPP;
450493d26c5SEd Maste 		goto exit;
451493d26c5SEd Maste 	}
452493d26c5SEd Maste 
453493d26c5SEd Maste 	aq_add_stats_sysctls(softc);
454493d26c5SEd Maste 	/* RSS */
455493d26c5SEd Maste 	arc4rand(softc->rss_key, HW_ATL_RSS_HASHKEY_SIZE, 0);
456493d26c5SEd Maste 	for (int i = ARRAY_SIZE(softc->rss_table); i--;){
457493d26c5SEd Maste 		softc->rss_table[i] = i & (softc->rx_rings_count - 1);
458493d26c5SEd Maste 	}
459493d26c5SEd Maste exit:
460493d26c5SEd Maste 	AQ_DBG_EXIT(rc);
461493d26c5SEd Maste 	return (rc);
462493d26c5SEd Maste }
463493d26c5SEd Maste 
464493d26c5SEd Maste 
465493d26c5SEd Maste static int aq_if_detach(if_ctx_t ctx)
466493d26c5SEd Maste {
467493d26c5SEd Maste 	struct aq_dev *softc;
468493d26c5SEd Maste 	int i;
469493d26c5SEd Maste 
470493d26c5SEd Maste 	AQ_DBG_ENTER();
471493d26c5SEd Maste 	softc = iflib_get_softc(ctx);
472493d26c5SEd Maste 
473493d26c5SEd Maste 	aq_hw_deinit(&softc->hw);
474493d26c5SEd Maste 
475493d26c5SEd Maste 	for (i = 0; i < softc->scctx->isc_nrxqsets; i++)
476493d26c5SEd Maste 		iflib_irq_free(ctx, &softc->rx_rings[i]->irq);
477493d26c5SEd Maste 	iflib_irq_free(ctx, &softc->irq);
478493d26c5SEd Maste 
479493d26c5SEd Maste 
480493d26c5SEd Maste 	if (softc->mmio_res != NULL)
481493d26c5SEd Maste 		bus_release_resource(softc->dev, SYS_RES_MEMORY,
482493d26c5SEd Maste 		    softc->mmio_rid, softc->mmio_res);
483493d26c5SEd Maste 
484493d26c5SEd Maste 	free(softc->vlan_tags, M_AQ);
485493d26c5SEd Maste 
486493d26c5SEd Maste 	AQ_DBG_EXIT(0);
487493d26c5SEd Maste 	return (0);
488493d26c5SEd Maste }
489493d26c5SEd Maste 
490493d26c5SEd Maste static int aq_if_shutdown(if_ctx_t ctx)
491493d26c5SEd Maste {
492493d26c5SEd Maste 
493493d26c5SEd Maste 	AQ_DBG_ENTER();
494493d26c5SEd Maste 
495493d26c5SEd Maste 	AQ_XXX_UNIMPLEMENTED_FUNCTION;
496493d26c5SEd Maste 
497493d26c5SEd Maste 	AQ_DBG_EXIT(0);
498493d26c5SEd Maste 	return (0);
499493d26c5SEd Maste }
500493d26c5SEd Maste 
501493d26c5SEd Maste static int aq_if_suspend(if_ctx_t ctx)
502493d26c5SEd Maste {
503493d26c5SEd Maste 	AQ_DBG_ENTER();
504493d26c5SEd Maste 
505493d26c5SEd Maste 	AQ_XXX_UNIMPLEMENTED_FUNCTION;
506493d26c5SEd Maste 
507493d26c5SEd Maste 	AQ_DBG_EXIT(0);
508493d26c5SEd Maste 	return (0);
509493d26c5SEd Maste }
510493d26c5SEd Maste 
511493d26c5SEd Maste static int aq_if_resume(if_ctx_t ctx)
512493d26c5SEd Maste {
513493d26c5SEd Maste 	AQ_DBG_ENTER();
514493d26c5SEd Maste 
515493d26c5SEd Maste 	AQ_XXX_UNIMPLEMENTED_FUNCTION;
516493d26c5SEd Maste 
517493d26c5SEd Maste 	AQ_DBG_EXIT(0);
518493d26c5SEd Maste 	return (0);
519493d26c5SEd Maste }
520493d26c5SEd Maste 
521493d26c5SEd Maste /* Soft queue setup and teardown */
522493d26c5SEd Maste static int aq_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs,
523493d26c5SEd Maste     uint64_t *paddrs, int ntxqs, int ntxqsets)
524493d26c5SEd Maste {
525493d26c5SEd Maste 	struct aq_dev *softc;
526493d26c5SEd Maste 	struct aq_ring *ring;
527493d26c5SEd Maste 	int rc = 0, i;
528493d26c5SEd Maste 
529493d26c5SEd Maste 	AQ_DBG_ENTERA("ntxqs=%d, ntxqsets=%d", ntxqs, ntxqsets);
530493d26c5SEd Maste 	softc = iflib_get_softc(ctx);
531493d26c5SEd Maste 	AQ_DBG_PRINT("tx descriptors  number %d", softc->scctx->isc_ntxd[0]);
532493d26c5SEd Maste 
533493d26c5SEd Maste 	for (i = 0; i < ntxqsets; i++) {
534493d26c5SEd Maste 		ring = softc->tx_rings[i] = malloc(sizeof(struct aq_ring),
535493d26c5SEd Maste 						   M_AQ, M_NOWAIT | M_ZERO);
536493d26c5SEd Maste 		if (!ring){
537493d26c5SEd Maste 			rc = ENOMEM;
538493d26c5SEd Maste 			device_printf(softc->dev, "atlantic: tx_ring malloc fail\n");
539493d26c5SEd Maste 			goto fail;
540493d26c5SEd Maste 		}
541493d26c5SEd Maste 		ring->tx_descs = (aq_tx_desc_t*)vaddrs[i];
542493d26c5SEd Maste 		ring->tx_size = softc->scctx->isc_ntxd[0];
543493d26c5SEd Maste 		ring->tx_descs_phys = paddrs[i];
544493d26c5SEd Maste 		ring->tx_head = ring->tx_tail = 0;
545493d26c5SEd Maste 		ring->index = i;
546493d26c5SEd Maste 		ring->dev = softc;
547493d26c5SEd Maste 
548493d26c5SEd Maste 		softc->tx_rings_count++;
549493d26c5SEd Maste 	}
550493d26c5SEd Maste 
551493d26c5SEd Maste 	AQ_DBG_EXIT(rc);
552493d26c5SEd Maste 	return (rc);
553493d26c5SEd Maste 
554493d26c5SEd Maste fail:
555493d26c5SEd Maste 	aq_if_queues_free(ctx);
556493d26c5SEd Maste 	AQ_DBG_EXIT(rc);
557493d26c5SEd Maste 	return (rc);
558493d26c5SEd Maste }
559493d26c5SEd Maste 
560493d26c5SEd Maste static int aq_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs,
561493d26c5SEd Maste     uint64_t *paddrs, int nrxqs, int nrxqsets)
562493d26c5SEd Maste {
563493d26c5SEd Maste 	struct aq_dev *softc;
564493d26c5SEd Maste 	struct aq_ring *ring;
565493d26c5SEd Maste 	int rc = 0, i;
566493d26c5SEd Maste 
567493d26c5SEd Maste 	AQ_DBG_ENTERA("nrxqs=%d, nrxqsets=%d", nrxqs, nrxqsets);
568493d26c5SEd Maste 	softc = iflib_get_softc(ctx);
569493d26c5SEd Maste 
570493d26c5SEd Maste 	for (i = 0; i < nrxqsets; i++) {
571493d26c5SEd Maste 		ring = softc->rx_rings[i] = malloc(sizeof(struct aq_ring),
572493d26c5SEd Maste 						   M_AQ, M_NOWAIT | M_ZERO);
573493d26c5SEd Maste 		if (!ring){
574493d26c5SEd Maste 			rc = ENOMEM;
575493d26c5SEd Maste 			device_printf(softc->dev, "atlantic: rx_ring malloc fail\n");
576493d26c5SEd Maste 			goto fail;
577493d26c5SEd Maste 		}
578493d26c5SEd Maste 
579493d26c5SEd Maste 		ring->rx_descs = (aq_rx_desc_t*)vaddrs[i];
580493d26c5SEd Maste 		ring->rx_descs_phys = paddrs[i];
581493d26c5SEd Maste 		ring->rx_size = softc->scctx->isc_nrxd[0];
582493d26c5SEd Maste 		ring->index = i;
583493d26c5SEd Maste 		ring->dev = softc;
584493d26c5SEd Maste 
585493d26c5SEd Maste 		switch (MCLBYTES) {
586493d26c5SEd Maste 			case    (4 * 1024):
587493d26c5SEd Maste 			case    (8 * 1024):
588493d26c5SEd Maste 			case    (16 * 1024):
589493d26c5SEd Maste 				ring->rx_max_frame_size = MCLBYTES;
590493d26c5SEd Maste 				break;
591493d26c5SEd Maste 			default:
592493d26c5SEd Maste 				ring->rx_max_frame_size = 2048;
593493d26c5SEd Maste 				break;
594493d26c5SEd Maste 		}
595493d26c5SEd Maste 
596493d26c5SEd Maste 		softc->rx_rings_count++;
597493d26c5SEd Maste 	}
598493d26c5SEd Maste 
599493d26c5SEd Maste 	AQ_DBG_EXIT(rc);
600493d26c5SEd Maste 	return (rc);
601493d26c5SEd Maste 
602493d26c5SEd Maste fail:
603493d26c5SEd Maste 	aq_if_queues_free(ctx);
604493d26c5SEd Maste 	AQ_DBG_EXIT(rc);
605493d26c5SEd Maste 	return (rc);
606493d26c5SEd Maste }
607493d26c5SEd Maste 
608493d26c5SEd Maste static void aq_if_queues_free(if_ctx_t ctx)
609493d26c5SEd Maste {
610493d26c5SEd Maste 	struct aq_dev *softc;
611493d26c5SEd Maste 	int i;
612493d26c5SEd Maste 
613493d26c5SEd Maste 	AQ_DBG_ENTER();
614493d26c5SEd Maste 	softc = iflib_get_softc(ctx);
615493d26c5SEd Maste 
616493d26c5SEd Maste 	for (i = 0; i < softc->tx_rings_count; i++) {
617493d26c5SEd Maste 		if (softc->tx_rings[i]) {
618493d26c5SEd Maste 			free(softc->tx_rings[i], M_AQ);
619493d26c5SEd Maste 			softc->tx_rings[i] = NULL;
620493d26c5SEd Maste 		}
621493d26c5SEd Maste 	}
622493d26c5SEd Maste 	softc->tx_rings_count = 0;
623493d26c5SEd Maste 	for (i = 0; i < softc->rx_rings_count; i++) {
624493d26c5SEd Maste 		if (softc->rx_rings[i]){
625493d26c5SEd Maste 			free(softc->rx_rings[i], M_AQ);
626493d26c5SEd Maste 			softc->rx_rings[i] = NULL;
627493d26c5SEd Maste 		}
628493d26c5SEd Maste 	}
629493d26c5SEd Maste 	softc->rx_rings_count = 0;
630493d26c5SEd Maste 
631493d26c5SEd Maste 	AQ_DBG_EXIT(0);
632493d26c5SEd Maste 	return;
633493d26c5SEd Maste }
634493d26c5SEd Maste 
635493d26c5SEd Maste /* Device configuration */
636493d26c5SEd Maste static void aq_if_init(if_ctx_t ctx)
637493d26c5SEd Maste {
638493d26c5SEd Maste 	struct aq_dev *softc;
639493d26c5SEd Maste 	struct aq_hw *hw;
640493d26c5SEd Maste 	struct ifmediareq ifmr;
641493d26c5SEd Maste 	int i, err;
642493d26c5SEd Maste 
643493d26c5SEd Maste 	AQ_DBG_ENTER();
644493d26c5SEd Maste 	softc = iflib_get_softc(ctx);
645493d26c5SEd Maste 	hw = &softc->hw;
646493d26c5SEd Maste 
647493d26c5SEd Maste 	err = aq_hw_init(&softc->hw, softc->hw.mac_addr, softc->msix,
648493d26c5SEd Maste 					softc->scctx->isc_intr == IFLIB_INTR_MSIX);
649493d26c5SEd Maste 	if (err != EOK) {
650493d26c5SEd Maste 		device_printf(softc->dev, "atlantic: aq_hw_init: %d", err);
651493d26c5SEd Maste 	}
652493d26c5SEd Maste 
653493d26c5SEd Maste 	aq_if_media_status(ctx, &ifmr);
654493d26c5SEd Maste 
655493d26c5SEd Maste 	aq_update_vlan_filters(softc);
656493d26c5SEd Maste 
657493d26c5SEd Maste 	for (i = 0; i < softc->tx_rings_count; i++) {
658493d26c5SEd Maste 		struct aq_ring *ring = softc->tx_rings[i];
659493d26c5SEd Maste 		err = aq_ring_tx_init(&softc->hw, ring);
660493d26c5SEd Maste 		if (err) {
661493d26c5SEd Maste 			device_printf(softc->dev, "atlantic: aq_ring_tx_init: %d", err);
662493d26c5SEd Maste 		}
663493d26c5SEd Maste 		err = aq_ring_tx_start(hw, ring);
664493d26c5SEd Maste 		if (err != EOK) {
665493d26c5SEd Maste 			device_printf(softc->dev, "atlantic: aq_ring_tx_start: %d", err);
666493d26c5SEd Maste 		}
667493d26c5SEd Maste 	}
668493d26c5SEd Maste 	for (i = 0; i < softc->rx_rings_count; i++) {
669493d26c5SEd Maste 		struct aq_ring *ring = softc->rx_rings[i];
670493d26c5SEd Maste 		err = aq_ring_rx_init(&softc->hw, ring);
671493d26c5SEd Maste 		if (err) {
672493d26c5SEd Maste 			device_printf(softc->dev, "atlantic: aq_ring_rx_init: %d", err);
673493d26c5SEd Maste 		}
674493d26c5SEd Maste 		err = aq_ring_rx_start(hw, ring);
675493d26c5SEd Maste 		if (err != EOK) {
676493d26c5SEd Maste 			device_printf(softc->dev, "atlantic: aq_ring_rx_start: %d", err);
677493d26c5SEd Maste 		}
678493d26c5SEd Maste 		aq_if_rx_queue_intr_enable(ctx, i);
679493d26c5SEd Maste 	}
680493d26c5SEd Maste 
681493d26c5SEd Maste 	aq_hw_start(hw);
682493d26c5SEd Maste 	aq_if_enable_intr(ctx);
683493d26c5SEd Maste 	aq_hw_rss_hash_set(&softc->hw, softc->rss_key);
684493d26c5SEd Maste 	aq_hw_rss_set(&softc->hw, softc->rss_table);
685493d26c5SEd Maste 	aq_hw_udp_rss_enable(hw, aq_enable_rss_udp);
686493d26c5SEd Maste 	aq_hw_set_link_speed(hw, hw->link_rate);
687493d26c5SEd Maste 
688493d26c5SEd Maste 	AQ_DBG_EXIT(0);
689493d26c5SEd Maste }
690493d26c5SEd Maste 
691493d26c5SEd Maste 
692493d26c5SEd Maste static void aq_if_stop(if_ctx_t ctx)
693493d26c5SEd Maste {
694493d26c5SEd Maste 	struct aq_dev *softc;
695493d26c5SEd Maste 	struct aq_hw *hw;
696493d26c5SEd Maste 	int i;
697493d26c5SEd Maste 
698493d26c5SEd Maste 	AQ_DBG_ENTER();
699493d26c5SEd Maste 
700493d26c5SEd Maste 	softc = iflib_get_softc(ctx);
701493d26c5SEd Maste 	hw = &softc->hw;
702493d26c5SEd Maste 
703493d26c5SEd Maste 	/* disable interrupt */
704493d26c5SEd Maste 	aq_if_disable_intr(ctx);
705493d26c5SEd Maste 
706493d26c5SEd Maste 	for (i = 0; i < softc->tx_rings_count; i++) {
707493d26c5SEd Maste 		aq_ring_tx_stop(hw, softc->tx_rings[i]);
708493d26c5SEd Maste 		softc->tx_rings[i]->tx_head = 0;
709493d26c5SEd Maste 		softc->tx_rings[i]->tx_tail = 0;
710493d26c5SEd Maste 	}
711493d26c5SEd Maste 	for (i = 0; i < softc->rx_rings_count; i++) {
712493d26c5SEd Maste 		aq_ring_rx_stop(hw, softc->rx_rings[i]);
713493d26c5SEd Maste 	}
714493d26c5SEd Maste 
715493d26c5SEd Maste 	aq_hw_reset(&softc->hw);
716493d26c5SEd Maste 	memset(&softc->last_stats, 0, sizeof(softc->last_stats));
717493d26c5SEd Maste 	softc->linkup = false;
718493d26c5SEd Maste 	aq_if_update_admin_status(ctx);
719493d26c5SEd Maste 	AQ_DBG_EXIT(0);
720493d26c5SEd Maste }
721493d26c5SEd Maste 
722493d26c5SEd Maste static uint64_t aq_if_get_counter(if_ctx_t ctx, ift_counter cnt)
723493d26c5SEd Maste {
724493d26c5SEd Maste 	struct aq_dev *softc = iflib_get_softc(ctx);
7254756f5ffSOlivier Cochard 	if_t ifp = iflib_get_ifp(ctx);
726493d26c5SEd Maste 
727493d26c5SEd Maste 	switch (cnt) {
728493d26c5SEd Maste 	case IFCOUNTER_IERRORS:
729493d26c5SEd Maste 		return (softc->curr_stats.erpr);
730493d26c5SEd Maste 	case IFCOUNTER_IQDROPS:
731493d26c5SEd Maste 		return (softc->curr_stats.dpc);
732493d26c5SEd Maste 	case IFCOUNTER_OERRORS:
733493d26c5SEd Maste 		return (softc->curr_stats.erpt);
734493d26c5SEd Maste 	default:
735493d26c5SEd Maste 		return (if_get_counter_default(ifp, cnt));
736493d26c5SEd Maste 	}
737493d26c5SEd Maste }
738493d26c5SEd Maste 
739493d26c5SEd Maste #if __FreeBSD_version >= 1300054
740493d26c5SEd Maste static u_int aq_mc_filter_apply(void *arg, struct sockaddr_dl *dl, u_int count)
741493d26c5SEd Maste {
742493d26c5SEd Maste 	struct aq_dev *softc = arg;
743493d26c5SEd Maste 	struct aq_hw *hw = &softc->hw;
744493d26c5SEd Maste 	u8 *mac_addr = NULL;
745493d26c5SEd Maste 
746493d26c5SEd Maste 	if (count == AQ_HW_MAC_MAX)
747493d26c5SEd Maste 		return (0);
748493d26c5SEd Maste 
749493d26c5SEd Maste 	mac_addr = LLADDR(dl);
750493d26c5SEd Maste 	aq_hw_mac_addr_set(hw, mac_addr, count + 1);
751493d26c5SEd Maste 
752493d26c5SEd Maste 	aq_log_detail("set %d mc address %6D", count + 1, mac_addr, ":");
753493d26c5SEd Maste 	return (1);
754493d26c5SEd Maste }
755493d26c5SEd Maste #else
756493d26c5SEd Maste static int aq_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int count)
757493d26c5SEd Maste {
758493d26c5SEd Maste 	struct aq_dev *softc = arg;
759493d26c5SEd Maste 	struct aq_hw *hw = &softc->hw;
760493d26c5SEd Maste 	u8 *mac_addr = NULL;
761493d26c5SEd Maste 
762493d26c5SEd Maste 	if (ifma->ifma_addr->sa_family != AF_LINK)
763493d26c5SEd Maste 		return (0);
764493d26c5SEd Maste 	if (count == AQ_HW_MAC_MAX)
765493d26c5SEd Maste 		return (0);
766493d26c5SEd Maste 
767493d26c5SEd Maste 	mac_addr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
768493d26c5SEd Maste 	aq_hw_mac_addr_set(hw, mac_addr, count + 1);
769493d26c5SEd Maste 
770493d26c5SEd Maste 	aq_log_detail("set %d mc address %6D", count + 1, mac_addr, ":");
771493d26c5SEd Maste 	return (1);
772493d26c5SEd Maste }
773493d26c5SEd Maste #endif
774493d26c5SEd Maste 
775493d26c5SEd Maste static bool aq_is_mc_promisc_required(struct aq_dev *softc)
776493d26c5SEd Maste {
777493d26c5SEd Maste 	return (softc->mcnt >= AQ_HW_MAC_MAX);
778493d26c5SEd Maste }
779493d26c5SEd Maste 
780493d26c5SEd Maste static void aq_if_multi_set(if_ctx_t ctx)
781493d26c5SEd Maste {
782493d26c5SEd Maste 	struct aq_dev *softc = iflib_get_softc(ctx);
7834756f5ffSOlivier Cochard 	if_t ifp = iflib_get_ifp(ctx);
784493d26c5SEd Maste 	struct aq_hw  *hw = &softc->hw;
785493d26c5SEd Maste 	AQ_DBG_ENTER();
786493d26c5SEd Maste #if __FreeBSD_version >= 1300054
787493d26c5SEd Maste 	softc->mcnt = if_llmaddr_count(iflib_get_ifp(ctx));
788493d26c5SEd Maste #else
789493d26c5SEd Maste 	softc->mcnt = if_multiaddr_count(iflib_get_ifp(ctx), AQ_HW_MAC_MAX);
790493d26c5SEd Maste #endif
791493d26c5SEd Maste 	if (softc->mcnt >= AQ_HW_MAC_MAX)
792493d26c5SEd Maste 	{
7934756f5ffSOlivier Cochard 		aq_hw_set_promisc(hw, !!(if_getflags(ifp) & IFF_PROMISC),
794493d26c5SEd Maste 				  aq_is_vlan_promisc_required(softc),
7954756f5ffSOlivier Cochard 				  !!(if_getflags(ifp) & IFF_ALLMULTI) || aq_is_mc_promisc_required(softc));
796493d26c5SEd Maste 	}else{
797493d26c5SEd Maste #if __FreeBSD_version >= 1300054
798493d26c5SEd Maste 		if_foreach_llmaddr(iflib_get_ifp(ctx), &aq_mc_filter_apply, softc);
799493d26c5SEd Maste #else
800493d26c5SEd Maste 		if_multi_apply(iflib_get_ifp(ctx), aq_mc_filter_apply, softc);
801493d26c5SEd Maste #endif
802493d26c5SEd Maste 	}
803493d26c5SEd Maste 	AQ_DBG_EXIT(0);
804493d26c5SEd Maste }
805493d26c5SEd Maste 
806493d26c5SEd Maste static int aq_if_mtu_set(if_ctx_t ctx, uint32_t mtu)
807493d26c5SEd Maste {
808493d26c5SEd Maste 	int err = 0;
809493d26c5SEd Maste 	AQ_DBG_ENTER();
810493d26c5SEd Maste 
811493d26c5SEd Maste 	AQ_DBG_EXIT(err);
812493d26c5SEd Maste 	return (err);
813493d26c5SEd Maste }
814493d26c5SEd Maste 
815493d26c5SEd Maste static void aq_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr)
816493d26c5SEd Maste {
8174756f5ffSOlivier Cochard 	if_t ifp;
818493d26c5SEd Maste 
819493d26c5SEd Maste 	AQ_DBG_ENTER();
820493d26c5SEd Maste 
821493d26c5SEd Maste 	ifp = iflib_get_ifp(ctx);
822493d26c5SEd Maste 
823493d26c5SEd Maste 	aq_mediastatus(ifp, ifmr);
824493d26c5SEd Maste 
825493d26c5SEd Maste 	AQ_DBG_EXIT(0);
826493d26c5SEd Maste }
827493d26c5SEd Maste 
828493d26c5SEd Maste static int aq_if_media_change(if_ctx_t ctx)
829493d26c5SEd Maste {
830493d26c5SEd Maste 	struct aq_dev *softc = iflib_get_softc(ctx);
8314756f5ffSOlivier Cochard 	if_t ifp = iflib_get_ifp(ctx);
832493d26c5SEd Maste 	int rc = 0;
833493d26c5SEd Maste 
834493d26c5SEd Maste 	AQ_DBG_ENTER();
835493d26c5SEd Maste 
836493d26c5SEd Maste 	/* Not allowd in UP state, since causes unsync of rings */
8374756f5ffSOlivier Cochard 	if ((if_getflags(ifp) & IFF_UP)){
838493d26c5SEd Maste 		rc = EPERM;
839493d26c5SEd Maste 		goto exit;
840493d26c5SEd Maste 	}
841493d26c5SEd Maste 
842493d26c5SEd Maste 	ifp = iflib_get_ifp(softc->ctx);
843493d26c5SEd Maste 
844493d26c5SEd Maste 	rc = aq_mediachange(ifp);
845493d26c5SEd Maste 
846493d26c5SEd Maste exit:
847493d26c5SEd Maste 	AQ_DBG_EXIT(rc);
848493d26c5SEd Maste 	return (rc);
849493d26c5SEd Maste }
850493d26c5SEd Maste 
851493d26c5SEd Maste static int aq_if_promisc_set(if_ctx_t ctx, int flags)
852493d26c5SEd Maste {
853493d26c5SEd Maste 	struct aq_dev *softc;
854493d26c5SEd Maste 
855493d26c5SEd Maste 	AQ_DBG_ENTER();
856493d26c5SEd Maste 
857493d26c5SEd Maste 	softc = iflib_get_softc(ctx);
858493d26c5SEd Maste 
859493d26c5SEd Maste 	aq_hw_set_promisc(&softc->hw, !!(flags & IFF_PROMISC),
860493d26c5SEd Maste 			  aq_is_vlan_promisc_required(softc),
861493d26c5SEd Maste 			  !!(flags & IFF_ALLMULTI) || aq_is_mc_promisc_required(softc));
862493d26c5SEd Maste 
863493d26c5SEd Maste 	AQ_DBG_EXIT(0);
864493d26c5SEd Maste 	return (0);
865493d26c5SEd Maste }
866493d26c5SEd Maste 
867493d26c5SEd Maste static void aq_if_timer(if_ctx_t ctx, uint16_t qid)
868493d26c5SEd Maste {
869493d26c5SEd Maste 	struct aq_dev *softc;
870493d26c5SEd Maste 	uint64_t ticks_now;
871493d26c5SEd Maste 
872493d26c5SEd Maste //	AQ_DBG_ENTER();
873493d26c5SEd Maste 
874493d26c5SEd Maste 	softc = iflib_get_softc(ctx);
875493d26c5SEd Maste 	ticks_now = ticks;
876493d26c5SEd Maste 
877493d26c5SEd Maste 	/* Schedule aqc_if_update_admin_status() once per sec */
878493d26c5SEd Maste 	if (ticks_now - softc->admin_ticks >= hz) {
879493d26c5SEd Maste 		softc->admin_ticks = ticks_now;
880493d26c5SEd Maste 		iflib_admin_intr_deferred(ctx);
881493d26c5SEd Maste 	}
882493d26c5SEd Maste 
883493d26c5SEd Maste //	AQ_DBG_EXIT(0);
884493d26c5SEd Maste 	return;
885493d26c5SEd Maste 
886493d26c5SEd Maste }
887493d26c5SEd Maste 
888493d26c5SEd Maste /* Interrupt enable / disable */
889493d26c5SEd Maste static void aq_if_enable_intr(if_ctx_t ctx)
890493d26c5SEd Maste {
891493d26c5SEd Maste 	struct aq_dev *softc = iflib_get_softc(ctx);
892493d26c5SEd Maste 	struct aq_hw  *hw = &softc->hw;
893493d26c5SEd Maste 
894493d26c5SEd Maste 	AQ_DBG_ENTER();
895493d26c5SEd Maste 
896493d26c5SEd Maste 	/* Enable interrupts */
897493d26c5SEd Maste 	itr_irq_msk_setlsw_set(hw, BIT(softc->msix + 1) - 1);
898493d26c5SEd Maste 
899493d26c5SEd Maste 	AQ_DBG_EXIT(0);
900493d26c5SEd Maste }
901493d26c5SEd Maste 
902493d26c5SEd Maste static void aq_if_disable_intr(if_ctx_t ctx)
903493d26c5SEd Maste {
904493d26c5SEd Maste 	struct aq_dev *softc = iflib_get_softc(ctx);
905493d26c5SEd Maste 	struct aq_hw  *hw = &softc->hw;
906493d26c5SEd Maste 
907493d26c5SEd Maste 	AQ_DBG_ENTER();
908493d26c5SEd Maste 
909493d26c5SEd Maste 	/* Disable interrupts */
910493d26c5SEd Maste 	itr_irq_msk_clearlsw_set(hw, BIT(softc->msix + 1) - 1);
911493d26c5SEd Maste 
912493d26c5SEd Maste 	AQ_DBG_EXIT(0);
913493d26c5SEd Maste }
914493d26c5SEd Maste 
915493d26c5SEd Maste static int aq_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid)
916493d26c5SEd Maste {
917493d26c5SEd Maste 	struct aq_dev *softc = iflib_get_softc(ctx);
918493d26c5SEd Maste 	struct aq_hw  *hw = &softc->hw;
919493d26c5SEd Maste 
920493d26c5SEd Maste 	AQ_DBG_ENTER();
921493d26c5SEd Maste 
922493d26c5SEd Maste 	itr_irq_msk_setlsw_set(hw, BIT(softc->rx_rings[rxqid]->msix));
923493d26c5SEd Maste 
924493d26c5SEd Maste 	AQ_DBG_EXIT(0);
925493d26c5SEd Maste 	return (0);
926493d26c5SEd Maste }
927493d26c5SEd Maste 
928493d26c5SEd Maste static int aq_if_msix_intr_assign(if_ctx_t ctx, int msix)
929493d26c5SEd Maste {
930493d26c5SEd Maste 	struct aq_dev *softc;
931493d26c5SEd Maste 	int i, vector = 0, rc;
932493d26c5SEd Maste 	char irq_name[16];
933493d26c5SEd Maste 	int rx_vectors;
934493d26c5SEd Maste 
935493d26c5SEd Maste 	AQ_DBG_ENTER();
936493d26c5SEd Maste 	softc = iflib_get_softc(ctx);
937493d26c5SEd Maste 
938493d26c5SEd Maste 	for (i = 0; i < softc->rx_rings_count; i++, vector++) {
939493d26c5SEd Maste 		snprintf(irq_name, sizeof(irq_name), "rxq%d", i);
940493d26c5SEd Maste 		rc = iflib_irq_alloc_generic(ctx, &softc->rx_rings[i]->irq,
941493d26c5SEd Maste 		    vector + 1, IFLIB_INTR_RX, aq_isr_rx, softc->rx_rings[i],
942493d26c5SEd Maste 			softc->rx_rings[i]->index, irq_name);
943493d26c5SEd Maste 		device_printf(softc->dev, "Assign IRQ %u to rx ring %u\n",
944493d26c5SEd Maste 					  vector, softc->rx_rings[i]->index);
945493d26c5SEd Maste 
946493d26c5SEd Maste 		if (rc) {
947493d26c5SEd Maste 			device_printf(softc->dev, "failed to set up RX handler\n");
948493d26c5SEd Maste 			i--;
949493d26c5SEd Maste 			goto fail;
950493d26c5SEd Maste 		}
951493d26c5SEd Maste 
952493d26c5SEd Maste 		softc->rx_rings[i]->msix = vector;
953493d26c5SEd Maste 	}
954493d26c5SEd Maste 
955493d26c5SEd Maste 	rx_vectors = vector;
956493d26c5SEd Maste 
957493d26c5SEd Maste 	for (i = 0; i < softc->tx_rings_count; i++, vector++) {
958493d26c5SEd Maste 		snprintf(irq_name, sizeof(irq_name), "txq%d", i);
959493d26c5SEd Maste 		iflib_softirq_alloc_generic(ctx, &softc->rx_rings[i]->irq, IFLIB_INTR_TX,
960493d26c5SEd Maste 									softc->tx_rings[i], i, irq_name);
961493d26c5SEd Maste 
962493d26c5SEd Maste 		softc->tx_rings[i]->msix = (vector % softc->rx_rings_count);
963493d26c5SEd Maste 		device_printf(softc->dev, "Assign IRQ %u to tx ring %u\n",
964493d26c5SEd Maste 					  softc->tx_rings[i]->msix, softc->tx_rings[i]->index);
965493d26c5SEd Maste 	}
966493d26c5SEd Maste 
967493d26c5SEd Maste 	rc = iflib_irq_alloc_generic(ctx, &softc->irq, rx_vectors + 1,
968493d26c5SEd Maste 								 IFLIB_INTR_ADMIN, aq_linkstat_isr,
969493d26c5SEd Maste 								 softc, 0, "aq");
970493d26c5SEd Maste 	softc->msix = rx_vectors;
971493d26c5SEd Maste 	device_printf(softc->dev, "Assign IRQ %u to admin proc \n",
972493d26c5SEd Maste 				  rx_vectors);
973493d26c5SEd Maste 	if (rc) {
974493d26c5SEd Maste 		device_printf(iflib_get_dev(ctx), "Failed to register admin handler");
975493d26c5SEd Maste 		i = softc->rx_rings_count;
976493d26c5SEd Maste 		goto fail;
977493d26c5SEd Maste 	}
978493d26c5SEd Maste 	AQ_DBG_EXIT(0);
979493d26c5SEd Maste 	return (0);
980493d26c5SEd Maste 
981493d26c5SEd Maste fail:
982493d26c5SEd Maste 	for (; i >= 0; i--)
983493d26c5SEd Maste 		iflib_irq_free(ctx, &softc->rx_rings[i]->irq);
984493d26c5SEd Maste 	AQ_DBG_EXIT(rc);
985493d26c5SEd Maste 	return (rc);
986493d26c5SEd Maste }
987493d26c5SEd Maste 
988493d26c5SEd Maste static bool aq_is_vlan_promisc_required(struct aq_dev *softc)
989493d26c5SEd Maste {
990493d26c5SEd Maste 	int vlan_tag_count;
991493d26c5SEd Maste 
992493d26c5SEd Maste 	bit_count(softc->vlan_tags, 0, 4096, &vlan_tag_count);
993493d26c5SEd Maste 
994493d26c5SEd Maste 	if (vlan_tag_count <= AQ_HW_VLAN_MAX_FILTERS)
995493d26c5SEd Maste 		return (false);
996493d26c5SEd Maste 	else
997493d26c5SEd Maste 		return (true);
998493d26c5SEd Maste 
999493d26c5SEd Maste }
1000493d26c5SEd Maste 
1001493d26c5SEd Maste static void aq_update_vlan_filters(struct aq_dev *softc)
1002493d26c5SEd Maste {
1003493d26c5SEd Maste 	struct aq_rx_filter_vlan aq_vlans[AQ_HW_VLAN_MAX_FILTERS];
1004493d26c5SEd Maste 	struct aq_hw  *hw = &softc->hw;
1005493d26c5SEd Maste 	int bit_pos = 0;
1006493d26c5SEd Maste 	int vlan_tag = -1;
1007493d26c5SEd Maste 	int i;
1008493d26c5SEd Maste 
1009493d26c5SEd Maste 	hw_atl_b0_hw_vlan_promisc_set(hw, true);
1010493d26c5SEd Maste 	for (i = 0; i < AQ_HW_VLAN_MAX_FILTERS; i++) {
1011493d26c5SEd Maste 		bit_ffs_at(softc->vlan_tags, bit_pos, 4096, &vlan_tag);
1012493d26c5SEd Maste 		if (vlan_tag != -1) {
1013493d26c5SEd Maste 			aq_vlans[i].enable = true;
1014493d26c5SEd Maste 			aq_vlans[i].location = i;
1015493d26c5SEd Maste 			aq_vlans[i].queue = 0xFF;
1016493d26c5SEd Maste 			aq_vlans[i].vlan_id = vlan_tag;
1017493d26c5SEd Maste 			bit_pos = vlan_tag;
1018493d26c5SEd Maste 		} else {
1019493d26c5SEd Maste 			aq_vlans[i].enable = false;
1020493d26c5SEd Maste 		}
1021493d26c5SEd Maste 	}
1022493d26c5SEd Maste 
1023493d26c5SEd Maste 	hw_atl_b0_hw_vlan_set(hw, aq_vlans);
1024493d26c5SEd Maste 	hw_atl_b0_hw_vlan_promisc_set(hw, aq_is_vlan_promisc_required(softc));
1025493d26c5SEd Maste }
1026493d26c5SEd Maste 
1027493d26c5SEd Maste /* VLAN support */
1028493d26c5SEd Maste static void aq_if_vlan_register(if_ctx_t ctx, uint16_t vtag)
1029493d26c5SEd Maste {
1030493d26c5SEd Maste 	struct aq_dev *softc = iflib_get_softc(ctx);
1031493d26c5SEd Maste 
1032493d26c5SEd Maste 	AQ_DBG_ENTERA("%d", vtag);
1033493d26c5SEd Maste 
1034493d26c5SEd Maste 	bit_set(softc->vlan_tags, vtag);
1035493d26c5SEd Maste 
1036493d26c5SEd Maste 	aq_update_vlan_filters(softc);
1037493d26c5SEd Maste 
1038493d26c5SEd Maste 	AQ_DBG_EXIT(0);
1039493d26c5SEd Maste }
1040493d26c5SEd Maste 
1041493d26c5SEd Maste static void aq_if_vlan_unregister(if_ctx_t ctx, uint16_t vtag)
1042493d26c5SEd Maste {
1043493d26c5SEd Maste 	struct aq_dev *softc = iflib_get_softc(ctx);
1044493d26c5SEd Maste 
1045493d26c5SEd Maste 	AQ_DBG_ENTERA("%d", vtag);
1046493d26c5SEd Maste 
1047493d26c5SEd Maste 	bit_clear(softc->vlan_tags, vtag);
1048493d26c5SEd Maste 
1049493d26c5SEd Maste 	aq_update_vlan_filters(softc);
1050493d26c5SEd Maste 
1051493d26c5SEd Maste 	AQ_DBG_EXIT(0);
1052493d26c5SEd Maste }
1053493d26c5SEd Maste 
1054493d26c5SEd Maste static void aq_if_led_func(if_ctx_t ctx, int onoff)
1055493d26c5SEd Maste {
1056493d26c5SEd Maste 	struct aq_dev *softc = iflib_get_softc(ctx);
1057493d26c5SEd Maste 	struct aq_hw  *hw = &softc->hw;
1058493d26c5SEd Maste 
1059493d26c5SEd Maste 	AQ_DBG_ENTERA("%d", onoff);
1060493d26c5SEd Maste 	if (hw->fw_ops && hw->fw_ops->led_control)
1061493d26c5SEd Maste 		hw->fw_ops->led_control(hw, onoff);
1062493d26c5SEd Maste 
1063493d26c5SEd Maste 	AQ_DBG_EXIT(0);
1064493d26c5SEd Maste }
1065493d26c5SEd Maste 
1066493d26c5SEd Maste static int aq_hw_capabilities(struct aq_dev *softc)
1067493d26c5SEd Maste {
1068493d26c5SEd Maste 
1069493d26c5SEd Maste 	if (pci_get_vendor(softc->dev) != AQUANTIA_VENDOR_ID)
1070493d26c5SEd Maste 		return (ENXIO);
1071493d26c5SEd Maste 
1072493d26c5SEd Maste 	switch (pci_get_device(softc->dev)) {
1073493d26c5SEd Maste 	case AQ_DEVICE_ID_D100:
1074493d26c5SEd Maste 	case AQ_DEVICE_ID_AQC100:
1075493d26c5SEd Maste 	case AQ_DEVICE_ID_AQC100S:
1076493d26c5SEd Maste 		softc->media_type = AQ_MEDIA_TYPE_FIBRE;
1077493d26c5SEd Maste 		softc->link_speeds = AQ_LINK_ALL & ~AQ_LINK_10G;
1078493d26c5SEd Maste 		break;
1079493d26c5SEd Maste 
1080493d26c5SEd Maste 	case AQ_DEVICE_ID_0001:
1081493d26c5SEd Maste 	case AQ_DEVICE_ID_D107:
1082493d26c5SEd Maste 	case AQ_DEVICE_ID_AQC107:
1083493d26c5SEd Maste 	case AQ_DEVICE_ID_AQC107S:
1084493d26c5SEd Maste 		softc->media_type = AQ_MEDIA_TYPE_TP;
1085493d26c5SEd Maste 		softc->link_speeds = AQ_LINK_ALL;
1086493d26c5SEd Maste 		break;
1087493d26c5SEd Maste 
1088493d26c5SEd Maste 	case AQ_DEVICE_ID_D108:
1089493d26c5SEd Maste 	case AQ_DEVICE_ID_AQC108:
1090493d26c5SEd Maste 	case AQ_DEVICE_ID_AQC108S:
1091493d26c5SEd Maste 	case AQ_DEVICE_ID_AQC111:
1092493d26c5SEd Maste 	case AQ_DEVICE_ID_AQC111S:
1093493d26c5SEd Maste 		softc->media_type = AQ_MEDIA_TYPE_TP;
1094493d26c5SEd Maste 		softc->link_speeds = AQ_LINK_ALL & ~AQ_LINK_10G;
1095493d26c5SEd Maste 		break;
1096493d26c5SEd Maste 
1097493d26c5SEd Maste 	case AQ_DEVICE_ID_D109:
1098493d26c5SEd Maste 	case AQ_DEVICE_ID_AQC109:
1099493d26c5SEd Maste 	case AQ_DEVICE_ID_AQC109S:
1100493d26c5SEd Maste 	case AQ_DEVICE_ID_AQC112:
1101493d26c5SEd Maste 	case AQ_DEVICE_ID_AQC112S:
1102493d26c5SEd Maste 		softc->media_type = AQ_MEDIA_TYPE_TP;
1103493d26c5SEd Maste 		softc->link_speeds = AQ_LINK_ALL & ~(AQ_LINK_10G | AQ_LINK_5G);
1104493d26c5SEd Maste 		break;
1105493d26c5SEd Maste 
1106493d26c5SEd Maste 	default:
1107493d26c5SEd Maste 		return (ENXIO);
1108493d26c5SEd Maste 	}
1109493d26c5SEd Maste 
1110493d26c5SEd Maste 	return (0);
1111493d26c5SEd Maste }
1112493d26c5SEd Maste 
1113493d26c5SEd Maste static int aq_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS)
1114493d26c5SEd Maste {
1115493d26c5SEd Maste 	struct aq_dev  *softc = (struct aq_dev *)arg1;
1116493d26c5SEd Maste 	device_t        dev = softc->dev;
1117493d26c5SEd Maste 	struct sbuf     *buf;
1118493d26c5SEd Maste 	int             error = 0;
1119493d26c5SEd Maste 
1120493d26c5SEd Maste 	buf = sbuf_new_for_sysctl(NULL, NULL, 256, req);
1121493d26c5SEd Maste 	if (!buf) {
1122493d26c5SEd Maste 		device_printf(dev, "Could not allocate sbuf for output.\n");
1123493d26c5SEd Maste 		return (ENOMEM);
1124493d26c5SEd Maste 	}
1125493d26c5SEd Maste 
1126493d26c5SEd Maste 	/* Print out the redirection table */
1127493d26c5SEd Maste 	sbuf_cat(buf, "\nRSS Indirection table:\n");
1128493d26c5SEd Maste 	for (int i = 0; i < HW_ATL_RSS_INDIRECTION_TABLE_MAX; i++) {
1129493d26c5SEd Maste 		sbuf_printf(buf, "%d ", softc->rss_table[i]);
1130493d26c5SEd Maste 		if ((i+1) % 10 == 0)
1131493d26c5SEd Maste 			sbuf_printf(buf, "\n");
1132493d26c5SEd Maste 	}
1133493d26c5SEd Maste 
1134493d26c5SEd Maste 	sbuf_cat(buf, "\nRSS Key:\n");
1135493d26c5SEd Maste 	for (int i = 0; i < HW_ATL_RSS_HASHKEY_SIZE; i++) {
1136493d26c5SEd Maste 		sbuf_printf(buf, "0x%02x ", softc->rss_key[i]);
1137493d26c5SEd Maste 	}
1138493d26c5SEd Maste 	sbuf_printf(buf, "\n");
1139493d26c5SEd Maste 
1140493d26c5SEd Maste 	error = sbuf_finish(buf);
1141493d26c5SEd Maste 	if (error)
1142493d26c5SEd Maste 		device_printf(dev, "Error finishing sbuf: %d\n", error);
1143493d26c5SEd Maste 
1144493d26c5SEd Maste 	sbuf_delete(buf);
1145493d26c5SEd Maste 
1146493d26c5SEd Maste 	return (0);
1147493d26c5SEd Maste }
1148493d26c5SEd Maste 
1149493d26c5SEd Maste static int aq_sysctl_print_tx_head(SYSCTL_HANDLER_ARGS)
1150493d26c5SEd Maste {
1151493d26c5SEd Maste 	struct aq_ring  *ring = arg1;
1152493d26c5SEd Maste 	int             error = 0;
1153493d26c5SEd Maste 	unsigned int   val;
1154493d26c5SEd Maste 
1155493d26c5SEd Maste 	if (!ring)
1156493d26c5SEd Maste 		return (0);
1157493d26c5SEd Maste 
1158493d26c5SEd Maste 	val = tdm_tx_desc_head_ptr_get(&ring->dev->hw, ring->index);
1159493d26c5SEd Maste 
1160493d26c5SEd Maste 	error = sysctl_handle_int(oidp, &val, 0, req);
1161493d26c5SEd Maste 	if (error || !req->newptr)
1162493d26c5SEd Maste 		return (error);
1163493d26c5SEd Maste 
1164493d26c5SEd Maste 	return (0);
1165493d26c5SEd Maste }
1166493d26c5SEd Maste 
1167493d26c5SEd Maste static int aq_sysctl_print_tx_tail(SYSCTL_HANDLER_ARGS)
1168493d26c5SEd Maste {
1169493d26c5SEd Maste 	struct aq_ring  *ring = arg1;
1170493d26c5SEd Maste 	int             error = 0;
1171493d26c5SEd Maste 	unsigned int   val;
1172493d26c5SEd Maste 
1173493d26c5SEd Maste 	if (!ring)
1174493d26c5SEd Maste 		return (0);
1175493d26c5SEd Maste 
1176493d26c5SEd Maste 	val = reg_tx_dma_desc_tail_ptr_get(&ring->dev->hw, ring->index);
1177493d26c5SEd Maste 
1178493d26c5SEd Maste 	error = sysctl_handle_int(oidp, &val, 0, req);
1179493d26c5SEd Maste 	if (error || !req->newptr)
1180493d26c5SEd Maste 		return (error);
1181493d26c5SEd Maste 
1182493d26c5SEd Maste 	return (0);
1183493d26c5SEd Maste }
1184493d26c5SEd Maste 
1185493d26c5SEd Maste static int aq_sysctl_print_rx_head(SYSCTL_HANDLER_ARGS)
1186493d26c5SEd Maste {
1187493d26c5SEd Maste 	struct aq_ring  *ring = arg1;
1188493d26c5SEd Maste 	int             error = 0;
1189493d26c5SEd Maste 	unsigned int   val;
1190493d26c5SEd Maste 
1191493d26c5SEd Maste 	if (!ring)
1192493d26c5SEd Maste 		return (0);
1193493d26c5SEd Maste 
1194493d26c5SEd Maste 	val = rdm_rx_desc_head_ptr_get(&ring->dev->hw, ring->index);
1195493d26c5SEd Maste 
1196493d26c5SEd Maste 	error = sysctl_handle_int(oidp, &val, 0, req);
1197493d26c5SEd Maste 	if (error || !req->newptr)
1198493d26c5SEd Maste 		return (error);
1199493d26c5SEd Maste 
1200493d26c5SEd Maste 	return (0);
1201493d26c5SEd Maste }
1202493d26c5SEd Maste 
1203493d26c5SEd Maste static int aq_sysctl_print_rx_tail(SYSCTL_HANDLER_ARGS)
1204493d26c5SEd Maste {
1205493d26c5SEd Maste 	struct aq_ring  *ring = arg1;
1206493d26c5SEd Maste 	int             error = 0;
1207493d26c5SEd Maste 	unsigned int   val;
1208493d26c5SEd Maste 
1209493d26c5SEd Maste 	if (!ring)
1210493d26c5SEd Maste 		return (0);
1211493d26c5SEd Maste 
1212493d26c5SEd Maste 	val = reg_rx_dma_desc_tail_ptr_get(&ring->dev->hw, ring->index);
1213493d26c5SEd Maste 
1214493d26c5SEd Maste 	error = sysctl_handle_int(oidp, &val, 0, req);
1215493d26c5SEd Maste 	if (error || !req->newptr)
1216493d26c5SEd Maste 		return (error);
1217493d26c5SEd Maste 
1218493d26c5SEd Maste 	return (0);
1219493d26c5SEd Maste }
1220493d26c5SEd Maste 
1221493d26c5SEd Maste static void aq_add_stats_sysctls(struct aq_dev *softc)
1222493d26c5SEd Maste {
1223493d26c5SEd Maste     device_t                dev = softc->dev;
1224493d26c5SEd Maste     struct sysctl_ctx_list  *ctx = device_get_sysctl_ctx(dev);
1225493d26c5SEd Maste     struct sysctl_oid       *tree = device_get_sysctl_tree(dev);
1226493d26c5SEd Maste     struct sysctl_oid_list  *child = SYSCTL_CHILDREN(tree);
1227493d26c5SEd Maste     struct aq_stats_s *stats = &softc->curr_stats;
1228493d26c5SEd Maste     struct sysctl_oid       *stat_node, *queue_node;
1229493d26c5SEd Maste     struct sysctl_oid_list  *stat_list, *queue_list;
1230493d26c5SEd Maste 
1231493d26c5SEd Maste #define QUEUE_NAME_LEN 32
1232493d26c5SEd Maste     char                    namebuf[QUEUE_NAME_LEN];
1233493d26c5SEd Maste 	/* RSS configuration */
1234493d26c5SEd Maste 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "print_rss_config",
1235493d26c5SEd Maste 		CTLTYPE_STRING | CTLFLAG_RD, softc, 0,
1236493d26c5SEd Maste 		aq_sysctl_print_rss_config, "A", "Prints RSS Configuration");
1237493d26c5SEd Maste 
1238493d26c5SEd Maste     /* Driver Statistics */
1239493d26c5SEd Maste      for (int i = 0; i < softc->tx_rings_count; i++) {
1240493d26c5SEd Maste         struct aq_ring *ring = softc->tx_rings[i];
1241493d26c5SEd Maste         snprintf(namebuf, QUEUE_NAME_LEN, "tx_queue%d", i);
1242493d26c5SEd Maste         queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
1243493d26c5SEd Maste             CTLFLAG_RD, NULL, "Queue Name");
1244493d26c5SEd Maste         queue_list = SYSCTL_CHILDREN(queue_node);
1245493d26c5SEd Maste 
1246493d26c5SEd Maste         SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_pkts",
1247493d26c5SEd Maste             CTLFLAG_RD, &(ring->stats.tx_pkts), "TX Packets");
1248493d26c5SEd Maste         SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
1249493d26c5SEd Maste             CTLFLAG_RD, &(ring->stats.tx_bytes), "TX Octets");
1250493d26c5SEd Maste         SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_drops",
1251493d26c5SEd Maste             CTLFLAG_RD, &(ring->stats.tx_drops), "TX Drops");
1252493d26c5SEd Maste         SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_queue_full",
1253493d26c5SEd Maste             CTLFLAG_RD, &(ring->stats.tx_queue_full), "TX Queue Full");
1254493d26c5SEd Maste 	SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "tx_head",
1255493d26c5SEd Maste 		CTLTYPE_UINT | CTLFLAG_RD, ring, 0,
1256493d26c5SEd Maste 		aq_sysctl_print_tx_head, "IU", "ring head pointer");
1257493d26c5SEd Maste 	SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "tx_tail",
1258493d26c5SEd Maste 		CTLTYPE_UINT | CTLFLAG_RD, ring, 0,
1259493d26c5SEd Maste 		aq_sysctl_print_tx_tail, "IU", "ring tail pointer");
1260493d26c5SEd Maste     }
1261493d26c5SEd Maste 
1262493d26c5SEd Maste      for (int i = 0; i < softc->rx_rings_count; i++) {
1263493d26c5SEd Maste         struct aq_ring *ring = softc->rx_rings[i];
1264493d26c5SEd Maste         snprintf(namebuf, QUEUE_NAME_LEN, "rx_queue%d", i);
1265493d26c5SEd Maste         queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
1266493d26c5SEd Maste             CTLFLAG_RD, NULL, "Queue Name");
1267493d26c5SEd Maste         queue_list = SYSCTL_CHILDREN(queue_node);
1268493d26c5SEd Maste 
1269493d26c5SEd Maste         SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_pkts",
1270493d26c5SEd Maste             CTLFLAG_RD, &(ring->stats.rx_pkts), "RX Packets");
1271493d26c5SEd Maste         SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
1272493d26c5SEd Maste             CTLFLAG_RD, &(ring->stats.rx_bytes), "TX Octets");
1273493d26c5SEd Maste         SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "jumbo_pkts",
1274493d26c5SEd Maste             CTLFLAG_RD, &(ring->stats.jumbo_pkts), "Jumbo Packets");
1275493d26c5SEd Maste         SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_err",
1276493d26c5SEd Maste             CTLFLAG_RD, &(ring->stats.rx_err), "RX Errors");
1277493d26c5SEd Maste         SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irq",
1278493d26c5SEd Maste             CTLFLAG_RD, &(ring->stats.irq), "RX interrupts");
1279493d26c5SEd Maste 	SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rx_head",
1280493d26c5SEd Maste 		CTLTYPE_UINT | CTLFLAG_RD, ring, 0,
1281493d26c5SEd Maste 		aq_sysctl_print_rx_head, "IU", "ring head pointer");
1282493d26c5SEd Maste 	SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rx_tail",
1283493d26c5SEd Maste 		CTLTYPE_UINT | CTLFLAG_RD, ring, 0,
1284493d26c5SEd Maste 		aq_sysctl_print_rx_tail, "IU", " ring tail pointer");
1285493d26c5SEd Maste     }
1286493d26c5SEd Maste 
1287493d26c5SEd Maste     stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac",
1288493d26c5SEd Maste         CTLFLAG_RD, NULL, "Statistics (read from HW registers)");
1289493d26c5SEd Maste     stat_list = SYSCTL_CHILDREN(stat_node);
1290493d26c5SEd Maste 
1291493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd",
1292493d26c5SEd Maste         CTLFLAG_RD, &stats->prc, "Good Packets Received");
1293493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_pkts_rcvd",
1294493d26c5SEd Maste         CTLFLAG_RD, &stats->uprc, "Unicast Packets Received");
1295493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd",
1296493d26c5SEd Maste         CTLFLAG_RD, &stats->mprc, "Multicast Packets Received");
1297493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd",
1298493d26c5SEd Maste         CTLFLAG_RD, &stats->bprc, "Broadcast Packets Received");
1299493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rsc_pkts_rcvd",
1300493d26c5SEd Maste         CTLFLAG_RD, &stats->cprc, "Coalesced Packets Received");
1301493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "err_pkts_rcvd",
1302493d26c5SEd Maste         CTLFLAG_RD, &stats->erpr, "Errors of Packet Receive");
1303493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "drop_pkts_dma",
1304493d26c5SEd Maste         CTLFLAG_RD, &stats->dpc, "Dropped Packets in DMA");
1305493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd",
1306493d26c5SEd Maste         CTLFLAG_RD, &stats->brc, "Good Octets Received");
1307493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_octets_rcvd",
1308493d26c5SEd Maste         CTLFLAG_RD, &stats->ubrc, "Unicast Octets Received");
1309493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_octets_rcvd",
1310493d26c5SEd Maste         CTLFLAG_RD, &stats->mbrc, "Multicast Octets Received");
1311493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_octets_rcvd",
1312493d26c5SEd Maste         CTLFLAG_RD, &stats->bbrc, "Broadcast Octets Received");
1313493d26c5SEd Maste 
1314493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd",
1315493d26c5SEd Maste         CTLFLAG_RD, &stats->ptc, "Good Packets Transmitted");
1316493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_pkts_txd",
1317493d26c5SEd Maste         CTLFLAG_RD, &stats->uptc, "Unicast Packets Transmitted");
1318493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd",
1319493d26c5SEd Maste         CTLFLAG_RD, &stats->mptc, "Multicast Packets Transmitted");
1320493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd",
1321493d26c5SEd Maste         CTLFLAG_RD, &stats->bptc, "Broadcast Packets Transmitted");
1322493d26c5SEd Maste 
1323493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "err_pkts_txd",
1324493d26c5SEd Maste         CTLFLAG_RD, &stats->erpt, "Errors of Packet Transmit");
1325493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd",
1326493d26c5SEd Maste         CTLFLAG_RD, &stats->btc, "Good Octets Transmitted");
1327493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_octets_txd",
1328493d26c5SEd Maste         CTLFLAG_RD, &stats->ubtc, "Unicast Octets Transmitted");
1329493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_octets_txd",
1330493d26c5SEd Maste         CTLFLAG_RD, &stats->mbtc, "Multicast Octets Transmitted");
1331493d26c5SEd Maste     SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_octets_txd",
1332493d26c5SEd Maste         CTLFLAG_RD, &stats->bbtc, "Broadcast Octets Transmitted");
1333493d26c5SEd Maste }
1334