xref: /freebsd/sys/dev/enetc/if_enetc.c (revision 19aa95e4b30d0560b849fb59dbe76360a3de2254)
1*19aa95e4SMarcin Wojtas /*-
2*19aa95e4SMarcin Wojtas  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*19aa95e4SMarcin Wojtas  *
4*19aa95e4SMarcin Wojtas  * Copyright (c) 2021 Alstom Group.
5*19aa95e4SMarcin Wojtas  * Copyright (c) 2021 Semihalf.
6*19aa95e4SMarcin Wojtas  *
7*19aa95e4SMarcin Wojtas  * Redistribution and use in source and binary forms, with or without
8*19aa95e4SMarcin Wojtas  * modification, are permitted provided that the following conditions
9*19aa95e4SMarcin Wojtas  * are met:
10*19aa95e4SMarcin Wojtas  * 1. Redistributions of source code must retain the above copyright
11*19aa95e4SMarcin Wojtas  *    notice, this list of conditions and the following disclaimer.
12*19aa95e4SMarcin Wojtas  * 2. Redistributions in binary form must reproduce the above copyright
13*19aa95e4SMarcin Wojtas  *    notice, this list of conditions and the following disclaimer in the
14*19aa95e4SMarcin Wojtas  *    documentation and/or other materials provided with the distribution.
15*19aa95e4SMarcin Wojtas  *
16*19aa95e4SMarcin Wojtas  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*19aa95e4SMarcin Wojtas  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*19aa95e4SMarcin Wojtas  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*19aa95e4SMarcin Wojtas  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*19aa95e4SMarcin Wojtas  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*19aa95e4SMarcin Wojtas  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*19aa95e4SMarcin Wojtas  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*19aa95e4SMarcin Wojtas  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*19aa95e4SMarcin Wojtas  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*19aa95e4SMarcin Wojtas  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*19aa95e4SMarcin Wojtas  */
27*19aa95e4SMarcin Wojtas 
28*19aa95e4SMarcin Wojtas #include <sys/cdefs.h>
29*19aa95e4SMarcin Wojtas __FBSDID("$FreeBSD$");
30*19aa95e4SMarcin Wojtas 
31*19aa95e4SMarcin Wojtas #include <sys/param.h>
32*19aa95e4SMarcin Wojtas #include <sys/bus.h>
33*19aa95e4SMarcin Wojtas #include <sys/endian.h>
34*19aa95e4SMarcin Wojtas #include <sys/kernel.h>
35*19aa95e4SMarcin Wojtas #include <sys/module.h>
36*19aa95e4SMarcin Wojtas #include <sys/rman.h>
37*19aa95e4SMarcin Wojtas #include <sys/socket.h>
38*19aa95e4SMarcin Wojtas #include <sys/sockio.h>
39*19aa95e4SMarcin Wojtas 
40*19aa95e4SMarcin Wojtas #include <machine/bus.h>
41*19aa95e4SMarcin Wojtas #include <machine/resource.h>
42*19aa95e4SMarcin Wojtas 
43*19aa95e4SMarcin Wojtas #include <net/ethernet.h>
44*19aa95e4SMarcin Wojtas #include <net/if.h>
45*19aa95e4SMarcin Wojtas #include <net/if_dl.h>
46*19aa95e4SMarcin Wojtas #include <net/if_var.h>
47*19aa95e4SMarcin Wojtas #include <net/if_types.h>
48*19aa95e4SMarcin Wojtas #include <net/if_media.h>
49*19aa95e4SMarcin Wojtas #include <net/iflib.h>
50*19aa95e4SMarcin Wojtas 
51*19aa95e4SMarcin Wojtas #include <dev/enetc/enetc_hw.h>
52*19aa95e4SMarcin Wojtas #include <dev/enetc/enetc.h>
53*19aa95e4SMarcin Wojtas #include <dev/enetc/enetc_mdio.h>
54*19aa95e4SMarcin Wojtas #include <dev/mii/mii.h>
55*19aa95e4SMarcin Wojtas #include <dev/mii/miivar.h>
56*19aa95e4SMarcin Wojtas #include <dev/pci/pcireg.h>
57*19aa95e4SMarcin Wojtas #include <dev/pci/pcivar.h>
58*19aa95e4SMarcin Wojtas 
59*19aa95e4SMarcin Wojtas #include <dev/ofw/ofw_bus.h>
60*19aa95e4SMarcin Wojtas #include <dev/ofw/ofw_bus_subr.h>
61*19aa95e4SMarcin Wojtas 
62*19aa95e4SMarcin Wojtas #include "ifdi_if.h"
63*19aa95e4SMarcin Wojtas #include "miibus_if.h"
64*19aa95e4SMarcin Wojtas 
65*19aa95e4SMarcin Wojtas static device_register_t		enetc_register;
66*19aa95e4SMarcin Wojtas 
67*19aa95e4SMarcin Wojtas static ifdi_attach_pre_t		enetc_attach_pre;
68*19aa95e4SMarcin Wojtas static ifdi_attach_post_t		enetc_attach_post;
69*19aa95e4SMarcin Wojtas static ifdi_detach_t			enetc_detach;
70*19aa95e4SMarcin Wojtas 
71*19aa95e4SMarcin Wojtas static ifdi_tx_queues_alloc_t		enetc_tx_queues_alloc;
72*19aa95e4SMarcin Wojtas static ifdi_rx_queues_alloc_t		enetc_rx_queues_alloc;
73*19aa95e4SMarcin Wojtas static ifdi_queues_free_t		enetc_queues_free;
74*19aa95e4SMarcin Wojtas 
75*19aa95e4SMarcin Wojtas static ifdi_init_t			enetc_init;
76*19aa95e4SMarcin Wojtas static ifdi_stop_t			enetc_stop;
77*19aa95e4SMarcin Wojtas 
78*19aa95e4SMarcin Wojtas static ifdi_msix_intr_assign_t		enetc_msix_intr_assign;
79*19aa95e4SMarcin Wojtas static ifdi_tx_queue_intr_enable_t	enetc_tx_queue_intr_enable;
80*19aa95e4SMarcin Wojtas static ifdi_rx_queue_intr_enable_t	enetc_rx_queue_intr_enable;
81*19aa95e4SMarcin Wojtas static ifdi_intr_enable_t		enetc_intr_enable;
82*19aa95e4SMarcin Wojtas static ifdi_intr_disable_t		enetc_intr_disable;
83*19aa95e4SMarcin Wojtas 
84*19aa95e4SMarcin Wojtas static int	enetc_isc_txd_encap(void*, if_pkt_info_t);
85*19aa95e4SMarcin Wojtas static void	enetc_isc_txd_flush(void*, uint16_t, qidx_t);
86*19aa95e4SMarcin Wojtas static int	enetc_isc_txd_credits_update(void*, uint16_t, bool);
87*19aa95e4SMarcin Wojtas static int	enetc_isc_rxd_available(void*, uint16_t, qidx_t, qidx_t);
88*19aa95e4SMarcin Wojtas static int	enetc_isc_rxd_pkt_get(void*, if_rxd_info_t);
89*19aa95e4SMarcin Wojtas static void	enetc_isc_rxd_refill(void*, if_rxd_update_t);
90*19aa95e4SMarcin Wojtas static void	enetc_isc_rxd_flush(void*, uint16_t, uint8_t, qidx_t);
91*19aa95e4SMarcin Wojtas 
92*19aa95e4SMarcin Wojtas static void	enetc_vlan_register(if_ctx_t, uint16_t);
93*19aa95e4SMarcin Wojtas static void	enetc_vlan_unregister(if_ctx_t, uint16_t);
94*19aa95e4SMarcin Wojtas 
95*19aa95e4SMarcin Wojtas static uint64_t	enetc_get_counter(if_ctx_t, ift_counter);
96*19aa95e4SMarcin Wojtas static int	enetc_promisc_set(if_ctx_t, int);
97*19aa95e4SMarcin Wojtas static int	enetc_mtu_set(if_ctx_t, uint32_t);
98*19aa95e4SMarcin Wojtas static void	enetc_setup_multicast(if_ctx_t);
99*19aa95e4SMarcin Wojtas static void	enetc_timer(if_ctx_t, uint16_t);
100*19aa95e4SMarcin Wojtas static void	enetc_update_admin_status(if_ctx_t);
101*19aa95e4SMarcin Wojtas 
102*19aa95e4SMarcin Wojtas static miibus_readreg_t		enetc_miibus_readreg;
103*19aa95e4SMarcin Wojtas static miibus_writereg_t	enetc_miibus_writereg;
104*19aa95e4SMarcin Wojtas static miibus_linkchg_t		enetc_miibus_linkchg;
105*19aa95e4SMarcin Wojtas static miibus_statchg_t		enetc_miibus_statchg;
106*19aa95e4SMarcin Wojtas 
107*19aa95e4SMarcin Wojtas static int			enetc_media_change(if_t);
108*19aa95e4SMarcin Wojtas static void			enetc_media_status(if_t, struct ifmediareq*);
109*19aa95e4SMarcin Wojtas 
110*19aa95e4SMarcin Wojtas static int			enetc_fixed_media_change(if_t);
111*19aa95e4SMarcin Wojtas static void			enetc_fixed_media_status(if_t, struct ifmediareq*);
112*19aa95e4SMarcin Wojtas 
113*19aa95e4SMarcin Wojtas static void			enetc_max_nqueues(struct enetc_softc*, int*, int*);
114*19aa95e4SMarcin Wojtas static int			enetc_setup_phy(struct enetc_softc*);
115*19aa95e4SMarcin Wojtas 
116*19aa95e4SMarcin Wojtas static void			enetc_get_hwaddr(struct enetc_softc*);
117*19aa95e4SMarcin Wojtas static void			enetc_set_hwaddr(struct enetc_softc*);
118*19aa95e4SMarcin Wojtas static int			enetc_setup_rss(struct enetc_softc*);
119*19aa95e4SMarcin Wojtas 
120*19aa95e4SMarcin Wojtas static void			enetc_init_hw(struct enetc_softc*);
121*19aa95e4SMarcin Wojtas static void			enetc_init_ctrl(struct enetc_softc*);
122*19aa95e4SMarcin Wojtas static void			enetc_init_tx(struct enetc_softc*);
123*19aa95e4SMarcin Wojtas static void			enetc_init_rx(struct enetc_softc*);
124*19aa95e4SMarcin Wojtas 
125*19aa95e4SMarcin Wojtas static int			enetc_ctrl_send(struct enetc_softc*,
126*19aa95e4SMarcin Wojtas 				    uint16_t, uint16_t, iflib_dma_info_t);
127*19aa95e4SMarcin Wojtas 
128*19aa95e4SMarcin Wojtas static const char enetc_driver_version[] = "1.0.0";
129*19aa95e4SMarcin Wojtas 
130*19aa95e4SMarcin Wojtas static pci_vendor_info_t enetc_vendor_info_array[] = {
131*19aa95e4SMarcin Wojtas 	PVID(PCI_VENDOR_FREESCALE, ENETC_DEV_ID_PF,
132*19aa95e4SMarcin Wojtas 	    "Freescale ENETC PCIe Gigabit Ethernet Controller"),
133*19aa95e4SMarcin Wojtas 	PVID_END
134*19aa95e4SMarcin Wojtas };
135*19aa95e4SMarcin Wojtas 
136*19aa95e4SMarcin Wojtas #define ENETC_IFCAPS (IFCAP_VLAN_MTU | IFCAP_RXCSUM | IFCAP_JUMBO_MTU | \
137*19aa95e4SMarcin Wojtas 	IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWFILTER)
138*19aa95e4SMarcin Wojtas 
139*19aa95e4SMarcin Wojtas static device_method_t enetc_methods[] = {
140*19aa95e4SMarcin Wojtas 	DEVMETHOD(device_register,	enetc_register),
141*19aa95e4SMarcin Wojtas 	DEVMETHOD(device_probe,		iflib_device_probe),
142*19aa95e4SMarcin Wojtas 	DEVMETHOD(device_attach,	iflib_device_attach),
143*19aa95e4SMarcin Wojtas 	DEVMETHOD(device_detach,	iflib_device_detach),
144*19aa95e4SMarcin Wojtas 	DEVMETHOD(device_shutdown,	iflib_device_shutdown),
145*19aa95e4SMarcin Wojtas 	DEVMETHOD(device_suspend,	iflib_device_suspend),
146*19aa95e4SMarcin Wojtas 	DEVMETHOD(device_resume,	iflib_device_resume),
147*19aa95e4SMarcin Wojtas 
148*19aa95e4SMarcin Wojtas 	DEVMETHOD(miibus_readreg,	enetc_miibus_readreg),
149*19aa95e4SMarcin Wojtas 	DEVMETHOD(miibus_writereg,	enetc_miibus_writereg),
150*19aa95e4SMarcin Wojtas 	DEVMETHOD(miibus_linkchg,	enetc_miibus_linkchg),
151*19aa95e4SMarcin Wojtas 	DEVMETHOD(miibus_statchg,	enetc_miibus_statchg),
152*19aa95e4SMarcin Wojtas 
153*19aa95e4SMarcin Wojtas 	DEVMETHOD_END
154*19aa95e4SMarcin Wojtas };
155*19aa95e4SMarcin Wojtas 
156*19aa95e4SMarcin Wojtas static driver_t enetc_driver = {
157*19aa95e4SMarcin Wojtas 	"enetc", enetc_methods, sizeof(struct enetc_softc)
158*19aa95e4SMarcin Wojtas };
159*19aa95e4SMarcin Wojtas 
160*19aa95e4SMarcin Wojtas static devclass_t enetc_devclass;
161*19aa95e4SMarcin Wojtas DRIVER_MODULE(enetc, pci, enetc_driver, enetc_devclass, NULL, NULL);
162*19aa95e4SMarcin Wojtas DRIVER_MODULE(miibus, enetc, miibus_driver, miibus_devclass, NULL, NULL);
163*19aa95e4SMarcin Wojtas MODULE_VERSION(enetc, 1);
164*19aa95e4SMarcin Wojtas 
165*19aa95e4SMarcin Wojtas IFLIB_PNP_INFO(pci, enetc, enetc_vendor_info_array);
166*19aa95e4SMarcin Wojtas 
167*19aa95e4SMarcin Wojtas MODULE_DEPEND(enetc, ether, 1, 1, 1);
168*19aa95e4SMarcin Wojtas MODULE_DEPEND(enetc, iflib, 1, 1, 1);
169*19aa95e4SMarcin Wojtas MODULE_DEPEND(enetc, miibus, 1, 1, 1);
170*19aa95e4SMarcin Wojtas 
171*19aa95e4SMarcin Wojtas static device_method_t enetc_iflib_methods[] = {
172*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_attach_pre,		enetc_attach_pre),
173*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_attach_post,		enetc_attach_post),
174*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_detach,			enetc_detach),
175*19aa95e4SMarcin Wojtas 
176*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_init,			enetc_init),
177*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_stop,			enetc_stop),
178*19aa95e4SMarcin Wojtas 
179*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_tx_queues_alloc,		enetc_tx_queues_alloc),
180*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_rx_queues_alloc,		enetc_rx_queues_alloc),
181*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_queues_free,		enetc_queues_free),
182*19aa95e4SMarcin Wojtas 
183*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_msix_intr_assign,	enetc_msix_intr_assign),
184*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_tx_queue_intr_enable,	enetc_tx_queue_intr_enable),
185*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_rx_queue_intr_enable,	enetc_rx_queue_intr_enable),
186*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_intr_enable,		enetc_intr_enable),
187*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_intr_disable,		enetc_intr_disable),
188*19aa95e4SMarcin Wojtas 
189*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_vlan_register,		enetc_vlan_register),
190*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_vlan_unregister,		enetc_vlan_unregister),
191*19aa95e4SMarcin Wojtas 
192*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_get_counter,		enetc_get_counter),
193*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_mtu_set,			enetc_mtu_set),
194*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_multi_set,		enetc_setup_multicast),
195*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_promisc_set,		enetc_promisc_set),
196*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_timer,			enetc_timer),
197*19aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_update_admin_status,	enetc_update_admin_status),
198*19aa95e4SMarcin Wojtas 
199*19aa95e4SMarcin Wojtas 	DEVMETHOD_END
200*19aa95e4SMarcin Wojtas };
201*19aa95e4SMarcin Wojtas 
202*19aa95e4SMarcin Wojtas static driver_t enetc_iflib_driver = {
203*19aa95e4SMarcin Wojtas 	"enetc", enetc_iflib_methods, sizeof(struct enetc_softc)
204*19aa95e4SMarcin Wojtas };
205*19aa95e4SMarcin Wojtas 
206*19aa95e4SMarcin Wojtas static struct if_txrx enetc_txrx = {
207*19aa95e4SMarcin Wojtas 	.ift_txd_encap = enetc_isc_txd_encap,
208*19aa95e4SMarcin Wojtas 	.ift_txd_flush = enetc_isc_txd_flush,
209*19aa95e4SMarcin Wojtas 	.ift_txd_credits_update = enetc_isc_txd_credits_update,
210*19aa95e4SMarcin Wojtas 	.ift_rxd_available = enetc_isc_rxd_available,
211*19aa95e4SMarcin Wojtas 	.ift_rxd_pkt_get = enetc_isc_rxd_pkt_get,
212*19aa95e4SMarcin Wojtas 	.ift_rxd_refill = enetc_isc_rxd_refill,
213*19aa95e4SMarcin Wojtas 	.ift_rxd_flush = enetc_isc_rxd_flush
214*19aa95e4SMarcin Wojtas };
215*19aa95e4SMarcin Wojtas 
216*19aa95e4SMarcin Wojtas static struct if_shared_ctx enetc_sctx_init = {
217*19aa95e4SMarcin Wojtas 	.isc_magic = IFLIB_MAGIC,
218*19aa95e4SMarcin Wojtas 
219*19aa95e4SMarcin Wojtas 	.isc_q_align = ENETC_RING_ALIGN,
220*19aa95e4SMarcin Wojtas 
221*19aa95e4SMarcin Wojtas 	.isc_tx_maxsize = ENETC_MAX_FRAME_LEN,
222*19aa95e4SMarcin Wojtas 	.isc_tx_maxsegsize = PAGE_SIZE,
223*19aa95e4SMarcin Wojtas 
224*19aa95e4SMarcin Wojtas 	.isc_rx_maxsize = ENETC_MAX_FRAME_LEN,
225*19aa95e4SMarcin Wojtas 	.isc_rx_maxsegsize = ENETC_MAX_FRAME_LEN,
226*19aa95e4SMarcin Wojtas 	.isc_rx_nsegments = ENETC_MAX_SCATTER,
227*19aa95e4SMarcin Wojtas 
228*19aa95e4SMarcin Wojtas 	.isc_admin_intrcnt = 0,
229*19aa95e4SMarcin Wojtas 
230*19aa95e4SMarcin Wojtas 	.isc_nfl = 1,
231*19aa95e4SMarcin Wojtas 	.isc_nrxqs = 1,
232*19aa95e4SMarcin Wojtas 	.isc_ntxqs = 1,
233*19aa95e4SMarcin Wojtas 
234*19aa95e4SMarcin Wojtas 	.isc_vendor_info = enetc_vendor_info_array,
235*19aa95e4SMarcin Wojtas 	.isc_driver_version = enetc_driver_version,
236*19aa95e4SMarcin Wojtas 	.isc_driver = &enetc_iflib_driver,
237*19aa95e4SMarcin Wojtas 
238*19aa95e4SMarcin Wojtas 	.isc_flags = IFLIB_DRIVER_MEDIA | IFLIB_PRESERVE_TX_INDICES,
239*19aa95e4SMarcin Wojtas 	.isc_ntxd_min = {ENETC_MIN_DESC},
240*19aa95e4SMarcin Wojtas 	.isc_ntxd_max = {ENETC_MAX_DESC},
241*19aa95e4SMarcin Wojtas 	.isc_ntxd_default = {ENETC_DEFAULT_DESC},
242*19aa95e4SMarcin Wojtas 	.isc_nrxd_min = {ENETC_MIN_DESC},
243*19aa95e4SMarcin Wojtas 	.isc_nrxd_max = {ENETC_MAX_DESC},
244*19aa95e4SMarcin Wojtas 	.isc_nrxd_default = {ENETC_DEFAULT_DESC}
245*19aa95e4SMarcin Wojtas };
246*19aa95e4SMarcin Wojtas 
247*19aa95e4SMarcin Wojtas static void*
248*19aa95e4SMarcin Wojtas enetc_register(device_t dev)
249*19aa95e4SMarcin Wojtas {
250*19aa95e4SMarcin Wojtas 
251*19aa95e4SMarcin Wojtas 	if (!ofw_bus_status_okay(dev))
252*19aa95e4SMarcin Wojtas 		return (NULL);
253*19aa95e4SMarcin Wojtas 
254*19aa95e4SMarcin Wojtas 	return (&enetc_sctx_init);
255*19aa95e4SMarcin Wojtas }
256*19aa95e4SMarcin Wojtas 
257*19aa95e4SMarcin Wojtas static void
258*19aa95e4SMarcin Wojtas enetc_max_nqueues(struct enetc_softc *sc, int *max_tx_nqueues,
259*19aa95e4SMarcin Wojtas     int *max_rx_nqueues)
260*19aa95e4SMarcin Wojtas {
261*19aa95e4SMarcin Wojtas 	uint32_t val;
262*19aa95e4SMarcin Wojtas 
263*19aa95e4SMarcin Wojtas 	val = ENETC_PORT_RD4(sc, ENETC_PCAPR0);
264*19aa95e4SMarcin Wojtas 	*max_tx_nqueues = MIN(ENETC_PCAPR0_TXBDR(val), ENETC_MAX_QUEUES);
265*19aa95e4SMarcin Wojtas 	*max_rx_nqueues = MIN(ENETC_PCAPR0_RXBDR(val), ENETC_MAX_QUEUES);
266*19aa95e4SMarcin Wojtas }
267*19aa95e4SMarcin Wojtas 
268*19aa95e4SMarcin Wojtas static int
269*19aa95e4SMarcin Wojtas enetc_setup_fixed(struct enetc_softc *sc, phandle_t node)
270*19aa95e4SMarcin Wojtas {
271*19aa95e4SMarcin Wojtas 	ssize_t size;
272*19aa95e4SMarcin Wojtas 	int speed;
273*19aa95e4SMarcin Wojtas 
274*19aa95e4SMarcin Wojtas 	size = OF_getencprop(node, "speed", &speed, sizeof(speed));
275*19aa95e4SMarcin Wojtas 	if (size <= 0) {
276*19aa95e4SMarcin Wojtas 		device_printf(sc->dev,
277*19aa95e4SMarcin Wojtas 		    "Device has fixed-link node without link speed specified\n");
278*19aa95e4SMarcin Wojtas 		return (ENXIO);
279*19aa95e4SMarcin Wojtas 	}
280*19aa95e4SMarcin Wojtas 	switch (speed) {
281*19aa95e4SMarcin Wojtas 	case 10:
282*19aa95e4SMarcin Wojtas 		speed = IFM_10_T;
283*19aa95e4SMarcin Wojtas 		break;
284*19aa95e4SMarcin Wojtas 	case 100:
285*19aa95e4SMarcin Wojtas 		speed = IFM_100_TX;
286*19aa95e4SMarcin Wojtas 		break;
287*19aa95e4SMarcin Wojtas 	case 1000:
288*19aa95e4SMarcin Wojtas 		speed = IFM_1000_T;
289*19aa95e4SMarcin Wojtas 		break;
290*19aa95e4SMarcin Wojtas 	default:
291*19aa95e4SMarcin Wojtas 		device_printf(sc->dev, "Unsupported link speed value of %d\n",
292*19aa95e4SMarcin Wojtas 		    speed);
293*19aa95e4SMarcin Wojtas 		return (ENXIO);
294*19aa95e4SMarcin Wojtas 	}
295*19aa95e4SMarcin Wojtas 	speed |= IFM_ETHER;
296*19aa95e4SMarcin Wojtas 
297*19aa95e4SMarcin Wojtas 	if (OF_hasprop(node, "full-duplex"))
298*19aa95e4SMarcin Wojtas 		speed |= IFM_FDX;
299*19aa95e4SMarcin Wojtas 	else
300*19aa95e4SMarcin Wojtas 		speed |= IFM_HDX;
301*19aa95e4SMarcin Wojtas 
302*19aa95e4SMarcin Wojtas 	sc->fixed_link = true;
303*19aa95e4SMarcin Wojtas 
304*19aa95e4SMarcin Wojtas 	ifmedia_init(&sc->fixed_ifmedia, 0, enetc_fixed_media_change,
305*19aa95e4SMarcin Wojtas 	    enetc_fixed_media_status);
306*19aa95e4SMarcin Wojtas 	ifmedia_add(&sc->fixed_ifmedia, speed, 0, NULL);
307*19aa95e4SMarcin Wojtas 	ifmedia_set(&sc->fixed_ifmedia, speed);
308*19aa95e4SMarcin Wojtas 	sc->shared->isc_media = &sc->fixed_ifmedia;
309*19aa95e4SMarcin Wojtas 
310*19aa95e4SMarcin Wojtas 	return (0);
311*19aa95e4SMarcin Wojtas }
312*19aa95e4SMarcin Wojtas 
313*19aa95e4SMarcin Wojtas static int
314*19aa95e4SMarcin Wojtas enetc_setup_phy(struct enetc_softc *sc)
315*19aa95e4SMarcin Wojtas {
316*19aa95e4SMarcin Wojtas 	phandle_t node, fixed_link, phy_handle;
317*19aa95e4SMarcin Wojtas 	struct mii_data *miid;
318*19aa95e4SMarcin Wojtas 	int phy_addr, error;
319*19aa95e4SMarcin Wojtas 	ssize_t size;
320*19aa95e4SMarcin Wojtas 
321*19aa95e4SMarcin Wojtas 	node = ofw_bus_get_node(sc->dev);
322*19aa95e4SMarcin Wojtas 	fixed_link = ofw_bus_find_child(node, "fixed-link");
323*19aa95e4SMarcin Wojtas 	if (fixed_link != 0)
324*19aa95e4SMarcin Wojtas 		return (enetc_setup_fixed(sc, fixed_link));
325*19aa95e4SMarcin Wojtas 
326*19aa95e4SMarcin Wojtas 	size = OF_getencprop(node, "phy-handle", &phy_handle, sizeof(phy_handle));
327*19aa95e4SMarcin Wojtas 	if (size <= 0) {
328*19aa95e4SMarcin Wojtas 		device_printf(sc->dev,
329*19aa95e4SMarcin Wojtas 		    "Failed to acquire PHY handle from FDT.\n");
330*19aa95e4SMarcin Wojtas 		return (ENXIO);
331*19aa95e4SMarcin Wojtas 	}
332*19aa95e4SMarcin Wojtas 	phy_handle = OF_node_from_xref(phy_handle);
333*19aa95e4SMarcin Wojtas 	size = OF_getencprop(phy_handle, "reg", &phy_addr, sizeof(phy_addr));
334*19aa95e4SMarcin Wojtas 	if (size <= 0) {
335*19aa95e4SMarcin Wojtas 		device_printf(sc->dev, "Failed to obtain PHY address\n");
336*19aa95e4SMarcin Wojtas 		return (ENXIO);
337*19aa95e4SMarcin Wojtas 	}
338*19aa95e4SMarcin Wojtas 	error = mii_attach(sc->dev, &sc->miibus, iflib_get_ifp(sc->ctx),
339*19aa95e4SMarcin Wojtas 	    enetc_media_change, enetc_media_status,
340*19aa95e4SMarcin Wojtas 	    BMSR_DEFCAPMASK, phy_addr, MII_OFFSET_ANY, MIIF_DOPAUSE);
341*19aa95e4SMarcin Wojtas 	if (error != 0) {
342*19aa95e4SMarcin Wojtas 		device_printf(sc->dev, "mii_attach failed\n");
343*19aa95e4SMarcin Wojtas 		return (error);
344*19aa95e4SMarcin Wojtas 	}
345*19aa95e4SMarcin Wojtas 	miid = device_get_softc(sc->miibus);
346*19aa95e4SMarcin Wojtas 	sc->shared->isc_media = &miid->mii_media;
347*19aa95e4SMarcin Wojtas 
348*19aa95e4SMarcin Wojtas 	return (0);
349*19aa95e4SMarcin Wojtas }
350*19aa95e4SMarcin Wojtas 
351*19aa95e4SMarcin Wojtas static int
352*19aa95e4SMarcin Wojtas enetc_attach_pre(if_ctx_t ctx)
353*19aa95e4SMarcin Wojtas {
354*19aa95e4SMarcin Wojtas 	struct ifnet *ifp;
355*19aa95e4SMarcin Wojtas 	if_softc_ctx_t scctx;
356*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
357*19aa95e4SMarcin Wojtas 	int error, rid;
358*19aa95e4SMarcin Wojtas 
359*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
360*19aa95e4SMarcin Wojtas 	scctx = iflib_get_softc_ctx(ctx);
361*19aa95e4SMarcin Wojtas 	sc->ctx = ctx;
362*19aa95e4SMarcin Wojtas 	sc->dev = iflib_get_dev(ctx);
363*19aa95e4SMarcin Wojtas 	sc->shared = scctx;
364*19aa95e4SMarcin Wojtas 	ifp = iflib_get_ifp(ctx);
365*19aa95e4SMarcin Wojtas 
366*19aa95e4SMarcin Wojtas 	rid = PCIR_BAR(ENETC_BAR_REGS);
367*19aa95e4SMarcin Wojtas 	sc->regs = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
368*19aa95e4SMarcin Wojtas 	if (sc->regs == NULL) {
369*19aa95e4SMarcin Wojtas 		device_printf(sc->dev,
370*19aa95e4SMarcin Wojtas 		    "Failed to allocate BAR %d\n", ENETC_BAR_REGS);
371*19aa95e4SMarcin Wojtas 		return (ENXIO);
372*19aa95e4SMarcin Wojtas 	}
373*19aa95e4SMarcin Wojtas 
374*19aa95e4SMarcin Wojtas 	error = iflib_dma_alloc_align(ctx,
375*19aa95e4SMarcin Wojtas 	    ENETC_MIN_DESC * sizeof(struct enetc_cbd),
376*19aa95e4SMarcin Wojtas 	    ENETC_RING_ALIGN,
377*19aa95e4SMarcin Wojtas 	    &sc->ctrl_queue.dma,
378*19aa95e4SMarcin Wojtas 	    0);
379*19aa95e4SMarcin Wojtas 	if (error != 0) {
380*19aa95e4SMarcin Wojtas 		device_printf(sc->dev, "Failed to allocate control ring\n");
381*19aa95e4SMarcin Wojtas 		goto fail;
382*19aa95e4SMarcin Wojtas 	}
383*19aa95e4SMarcin Wojtas 	sc->ctrl_queue.ring = (struct enetc_cbd*)sc->ctrl_queue.dma.idi_vaddr;
384*19aa95e4SMarcin Wojtas 
385*19aa95e4SMarcin Wojtas 	scctx->isc_txrx = &enetc_txrx;
386*19aa95e4SMarcin Wojtas 	scctx->isc_tx_nsegments = ENETC_MAX_SCATTER;
387*19aa95e4SMarcin Wojtas 	enetc_max_nqueues(sc, &scctx->isc_nrxqsets_max, &scctx->isc_ntxqsets_max);
388*19aa95e4SMarcin Wojtas 
389*19aa95e4SMarcin Wojtas 	if (scctx->isc_ntxd[0] % ENETC_DESC_ALIGN != 0) {
390*19aa95e4SMarcin Wojtas 		device_printf(sc->dev,
391*19aa95e4SMarcin Wojtas 		    "The number of TX descriptors has to be a multiple of %d\n",
392*19aa95e4SMarcin Wojtas 		    ENETC_DESC_ALIGN);
393*19aa95e4SMarcin Wojtas 		error = EINVAL;
394*19aa95e4SMarcin Wojtas 		goto fail;
395*19aa95e4SMarcin Wojtas 	}
396*19aa95e4SMarcin Wojtas 	if (scctx->isc_nrxd[0] % ENETC_DESC_ALIGN != 0) {
397*19aa95e4SMarcin Wojtas 		device_printf(sc->dev,
398*19aa95e4SMarcin Wojtas 		    "The number of RX descriptors has to be a multiple of %d\n",
399*19aa95e4SMarcin Wojtas 		    ENETC_DESC_ALIGN);
400*19aa95e4SMarcin Wojtas 		error = EINVAL;
401*19aa95e4SMarcin Wojtas 		goto fail;
402*19aa95e4SMarcin Wojtas 	}
403*19aa95e4SMarcin Wojtas 	scctx->isc_txqsizes[0] = scctx->isc_ntxd[0] * sizeof(union enetc_tx_bd);
404*19aa95e4SMarcin Wojtas 	scctx->isc_rxqsizes[0] = scctx->isc_nrxd[0] * sizeof(union enetc_rx_bd);
405*19aa95e4SMarcin Wojtas 	scctx->isc_txd_size[0] = sizeof(union enetc_tx_bd);
406*19aa95e4SMarcin Wojtas 	scctx->isc_rxd_size[0] = sizeof(union enetc_rx_bd);
407*19aa95e4SMarcin Wojtas 	scctx->isc_tx_csum_flags = 0;
408*19aa95e4SMarcin Wojtas 	scctx->isc_capabilities = scctx->isc_capenable = ENETC_IFCAPS;
409*19aa95e4SMarcin Wojtas 
410*19aa95e4SMarcin Wojtas 	error = enetc_mtu_set(ctx, ETHERMTU);
411*19aa95e4SMarcin Wojtas 	if (error != 0)
412*19aa95e4SMarcin Wojtas 		goto fail;
413*19aa95e4SMarcin Wojtas 
414*19aa95e4SMarcin Wojtas 	scctx->isc_msix_bar = pci_msix_table_bar(sc->dev);
415*19aa95e4SMarcin Wojtas 
416*19aa95e4SMarcin Wojtas 	error = enetc_setup_phy(sc);
417*19aa95e4SMarcin Wojtas 	if (error != 0)
418*19aa95e4SMarcin Wojtas 		goto fail;
419*19aa95e4SMarcin Wojtas 
420*19aa95e4SMarcin Wojtas 	enetc_get_hwaddr(sc);
421*19aa95e4SMarcin Wojtas 
422*19aa95e4SMarcin Wojtas 	return (0);
423*19aa95e4SMarcin Wojtas fail:
424*19aa95e4SMarcin Wojtas 	enetc_detach(ctx);
425*19aa95e4SMarcin Wojtas 	return (error);
426*19aa95e4SMarcin Wojtas }
427*19aa95e4SMarcin Wojtas 
428*19aa95e4SMarcin Wojtas static int
429*19aa95e4SMarcin Wojtas enetc_attach_post(if_ctx_t ctx)
430*19aa95e4SMarcin Wojtas {
431*19aa95e4SMarcin Wojtas 
432*19aa95e4SMarcin Wojtas 	enetc_init_hw(iflib_get_softc(ctx));
433*19aa95e4SMarcin Wojtas 	return (0);
434*19aa95e4SMarcin Wojtas }
435*19aa95e4SMarcin Wojtas 
436*19aa95e4SMarcin Wojtas static int
437*19aa95e4SMarcin Wojtas enetc_detach(if_ctx_t ctx)
438*19aa95e4SMarcin Wojtas {
439*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
440*19aa95e4SMarcin Wojtas 	int error = 0, i;
441*19aa95e4SMarcin Wojtas 
442*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
443*19aa95e4SMarcin Wojtas 
444*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++)
445*19aa95e4SMarcin Wojtas 		iflib_irq_free(ctx, &sc->rx_queues[i].irq);
446*19aa95e4SMarcin Wojtas 
447*19aa95e4SMarcin Wojtas 	if (sc->miibus != NULL)
448*19aa95e4SMarcin Wojtas 		device_delete_child(sc->dev, sc->miibus);
449*19aa95e4SMarcin Wojtas 
450*19aa95e4SMarcin Wojtas 	if (sc->regs != NULL)
451*19aa95e4SMarcin Wojtas 		error = bus_release_resource(sc->dev, SYS_RES_MEMORY,
452*19aa95e4SMarcin Wojtas 		    rman_get_rid(sc->regs), sc->regs);
453*19aa95e4SMarcin Wojtas 
454*19aa95e4SMarcin Wojtas 	if (sc->ctrl_queue.dma.idi_size != 0)
455*19aa95e4SMarcin Wojtas 		iflib_dma_free(&sc->ctrl_queue.dma);
456*19aa95e4SMarcin Wojtas 
457*19aa95e4SMarcin Wojtas 	return (error);
458*19aa95e4SMarcin Wojtas }
459*19aa95e4SMarcin Wojtas 
460*19aa95e4SMarcin Wojtas static int
461*19aa95e4SMarcin Wojtas enetc_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
462*19aa95e4SMarcin Wojtas     int ntxqs, int ntxqsets)
463*19aa95e4SMarcin Wojtas {
464*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
465*19aa95e4SMarcin Wojtas 	struct enetc_tx_queue *queue;
466*19aa95e4SMarcin Wojtas 	int i;
467*19aa95e4SMarcin Wojtas 
468*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
469*19aa95e4SMarcin Wojtas 
470*19aa95e4SMarcin Wojtas 	MPASS(ntxqs == 1);
471*19aa95e4SMarcin Wojtas 
472*19aa95e4SMarcin Wojtas 	sc->tx_queues = mallocarray(sc->tx_num_queues,
473*19aa95e4SMarcin Wojtas 	    sizeof(struct enetc_tx_queue), M_DEVBUF, M_NOWAIT | M_ZERO);
474*19aa95e4SMarcin Wojtas 	if (sc->tx_queues == NULL) {
475*19aa95e4SMarcin Wojtas 		device_printf(sc->dev,
476*19aa95e4SMarcin Wojtas 		    "Failed to allocate memory for TX queues.\n");
477*19aa95e4SMarcin Wojtas 		return (ENOMEM);
478*19aa95e4SMarcin Wojtas 	}
479*19aa95e4SMarcin Wojtas 
480*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->tx_num_queues; i++) {
481*19aa95e4SMarcin Wojtas 		queue = &sc->tx_queues[i];
482*19aa95e4SMarcin Wojtas 		queue->sc = sc;
483*19aa95e4SMarcin Wojtas 		queue->ring = (union enetc_tx_bd*)(vaddrs[i]);
484*19aa95e4SMarcin Wojtas 		queue->ring_paddr = paddrs[i];
485*19aa95e4SMarcin Wojtas 		queue->next_to_clean = 0;
486*19aa95e4SMarcin Wojtas 		queue->ring_full = false;
487*19aa95e4SMarcin Wojtas 	}
488*19aa95e4SMarcin Wojtas 
489*19aa95e4SMarcin Wojtas 	return (0);
490*19aa95e4SMarcin Wojtas }
491*19aa95e4SMarcin Wojtas 
492*19aa95e4SMarcin Wojtas static int
493*19aa95e4SMarcin Wojtas enetc_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
494*19aa95e4SMarcin Wojtas     int nrxqs, int nrxqsets)
495*19aa95e4SMarcin Wojtas {
496*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
497*19aa95e4SMarcin Wojtas 	struct enetc_rx_queue *queue;
498*19aa95e4SMarcin Wojtas 	int i;
499*19aa95e4SMarcin Wojtas 
500*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
501*19aa95e4SMarcin Wojtas 	MPASS(nrxqs == 1);
502*19aa95e4SMarcin Wojtas 
503*19aa95e4SMarcin Wojtas 	sc->rx_queues = mallocarray(sc->rx_num_queues,
504*19aa95e4SMarcin Wojtas 	    sizeof(struct enetc_rx_queue), M_DEVBUF, M_NOWAIT | M_ZERO);
505*19aa95e4SMarcin Wojtas 	if (sc->rx_queues == NULL) {
506*19aa95e4SMarcin Wojtas 		device_printf(sc->dev,
507*19aa95e4SMarcin Wojtas 		    "Failed to allocate memory for RX queues.\n");
508*19aa95e4SMarcin Wojtas 		return (ENOMEM);
509*19aa95e4SMarcin Wojtas 	}
510*19aa95e4SMarcin Wojtas 
511*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++) {
512*19aa95e4SMarcin Wojtas 		queue = &sc->rx_queues[i];
513*19aa95e4SMarcin Wojtas 		queue->sc = sc;
514*19aa95e4SMarcin Wojtas 		queue->qid = i;
515*19aa95e4SMarcin Wojtas 		queue->ring = (union enetc_rx_bd*)(vaddrs[i]);
516*19aa95e4SMarcin Wojtas 		queue->ring_paddr = paddrs[i];
517*19aa95e4SMarcin Wojtas 	}
518*19aa95e4SMarcin Wojtas 
519*19aa95e4SMarcin Wojtas 	return (0);
520*19aa95e4SMarcin Wojtas }
521*19aa95e4SMarcin Wojtas 
522*19aa95e4SMarcin Wojtas static void
523*19aa95e4SMarcin Wojtas enetc_queues_free(if_ctx_t ctx)
524*19aa95e4SMarcin Wojtas {
525*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
526*19aa95e4SMarcin Wojtas 
527*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
528*19aa95e4SMarcin Wojtas 
529*19aa95e4SMarcin Wojtas 	if (sc->tx_queues != NULL) {
530*19aa95e4SMarcin Wojtas 		free(sc->tx_queues, M_DEVBUF);
531*19aa95e4SMarcin Wojtas 		sc->tx_queues = NULL;
532*19aa95e4SMarcin Wojtas 	}
533*19aa95e4SMarcin Wojtas 	if (sc->rx_queues != NULL) {
534*19aa95e4SMarcin Wojtas 		free(sc->rx_queues, M_DEVBUF);
535*19aa95e4SMarcin Wojtas 		sc->rx_queues = NULL;
536*19aa95e4SMarcin Wojtas 	}
537*19aa95e4SMarcin Wojtas }
538*19aa95e4SMarcin Wojtas 
539*19aa95e4SMarcin Wojtas static void
540*19aa95e4SMarcin Wojtas enetc_get_hwaddr(struct enetc_softc *sc)
541*19aa95e4SMarcin Wojtas {
542*19aa95e4SMarcin Wojtas 	struct ether_addr hwaddr;
543*19aa95e4SMarcin Wojtas 	uint16_t high;
544*19aa95e4SMarcin Wojtas 	uint32_t low;
545*19aa95e4SMarcin Wojtas 
546*19aa95e4SMarcin Wojtas 	low = ENETC_PORT_RD4(sc, ENETC_PSIPMAR0(0));
547*19aa95e4SMarcin Wojtas 	high = ENETC_PORT_RD2(sc, ENETC_PSIPMAR1(0));
548*19aa95e4SMarcin Wojtas 
549*19aa95e4SMarcin Wojtas 	memcpy(&hwaddr.octet[0], &low, 4);
550*19aa95e4SMarcin Wojtas 	memcpy(&hwaddr.octet[4], &high, 2);
551*19aa95e4SMarcin Wojtas 
552*19aa95e4SMarcin Wojtas 	if (ETHER_IS_BROADCAST(hwaddr.octet) ||
553*19aa95e4SMarcin Wojtas 	    ETHER_IS_MULTICAST(hwaddr.octet) ||
554*19aa95e4SMarcin Wojtas 	    ETHER_IS_ZERO(hwaddr.octet)) {
555*19aa95e4SMarcin Wojtas 		ether_gen_addr(iflib_get_ifp(sc->ctx), &hwaddr);
556*19aa95e4SMarcin Wojtas 		device_printf(sc->dev,
557*19aa95e4SMarcin Wojtas 		    "Failed to obtain MAC address, using a random one\n");
558*19aa95e4SMarcin Wojtas 		memcpy(&low, &hwaddr.octet[0], 4);
559*19aa95e4SMarcin Wojtas 		memcpy(&high, &hwaddr.octet[4], 2);
560*19aa95e4SMarcin Wojtas 	}
561*19aa95e4SMarcin Wojtas 
562*19aa95e4SMarcin Wojtas 	iflib_set_mac(sc->ctx, hwaddr.octet);
563*19aa95e4SMarcin Wojtas }
564*19aa95e4SMarcin Wojtas 
565*19aa95e4SMarcin Wojtas static void
566*19aa95e4SMarcin Wojtas enetc_set_hwaddr(struct enetc_softc *sc)
567*19aa95e4SMarcin Wojtas {
568*19aa95e4SMarcin Wojtas 	struct ifnet *ifp;
569*19aa95e4SMarcin Wojtas 	uint16_t high;
570*19aa95e4SMarcin Wojtas 	uint32_t low;
571*19aa95e4SMarcin Wojtas 	uint8_t *hwaddr;
572*19aa95e4SMarcin Wojtas 
573*19aa95e4SMarcin Wojtas 	ifp = iflib_get_ifp(sc->ctx);
574*19aa95e4SMarcin Wojtas 	hwaddr = (uint8_t*)if_getlladdr(ifp);
575*19aa95e4SMarcin Wojtas 	low = *((uint32_t*)hwaddr);
576*19aa95e4SMarcin Wojtas 	high = *((uint16_t*)(hwaddr+4));
577*19aa95e4SMarcin Wojtas 
578*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIPMAR0(0), low);
579*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR2(sc, ENETC_PSIPMAR1(0), high);
580*19aa95e4SMarcin Wojtas }
581*19aa95e4SMarcin Wojtas 
582*19aa95e4SMarcin Wojtas static int
583*19aa95e4SMarcin Wojtas enetc_setup_rss(struct enetc_softc *sc)
584*19aa95e4SMarcin Wojtas {
585*19aa95e4SMarcin Wojtas 	struct iflib_dma_info dma;
586*19aa95e4SMarcin Wojtas 	int error, i, buckets_num = 0;
587*19aa95e4SMarcin Wojtas 	uint8_t *rss_table;
588*19aa95e4SMarcin Wojtas 	uint32_t reg;
589*19aa95e4SMarcin Wojtas 
590*19aa95e4SMarcin Wojtas 	reg = ENETC_RD4(sc, ENETC_SIPCAPR0);
591*19aa95e4SMarcin Wojtas 	if (reg & ENETC_SIPCAPR0_RSS) {
592*19aa95e4SMarcin Wojtas 		reg = ENETC_RD4(sc, ENETC_SIRSSCAPR);
593*19aa95e4SMarcin Wojtas 		buckets_num = ENETC_SIRSSCAPR_GET_NUM_RSS(reg);
594*19aa95e4SMarcin Wojtas         }
595*19aa95e4SMarcin Wojtas 	if (buckets_num == 0)
596*19aa95e4SMarcin Wojtas 		return (ENOTSUP);
597*19aa95e4SMarcin Wojtas 
598*19aa95e4SMarcin Wojtas 	for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / sizeof(uint32_t); i++) {
599*19aa95e4SMarcin Wojtas 		arc4rand((uint8_t *)&reg, sizeof(reg), 0);
600*19aa95e4SMarcin Wojtas 		ENETC_PORT_WR4(sc, ENETC_PRSSK(i), reg);
601*19aa95e4SMarcin Wojtas 	}
602*19aa95e4SMarcin Wojtas 
603*19aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SIRBGCR, sc->rx_num_queues);
604*19aa95e4SMarcin Wojtas 
605*19aa95e4SMarcin Wojtas 	error = iflib_dma_alloc_align(sc->ctx,
606*19aa95e4SMarcin Wojtas 	    buckets_num * sizeof(*rss_table),
607*19aa95e4SMarcin Wojtas 	    ENETC_RING_ALIGN,
608*19aa95e4SMarcin Wojtas 	    &dma,
609*19aa95e4SMarcin Wojtas 	    0);
610*19aa95e4SMarcin Wojtas 	if (error != 0) {
611*19aa95e4SMarcin Wojtas 		device_printf(sc->dev, "Failed to allocate DMA buffer for RSS\n");
612*19aa95e4SMarcin Wojtas 		return (error);
613*19aa95e4SMarcin Wojtas 	}
614*19aa95e4SMarcin Wojtas 	rss_table = (uint8_t *)dma.idi_vaddr;
615*19aa95e4SMarcin Wojtas 
616*19aa95e4SMarcin Wojtas 	for (i = 0; i < buckets_num; i++)
617*19aa95e4SMarcin Wojtas 		rss_table[i] = i % sc->rx_num_queues;
618*19aa95e4SMarcin Wojtas 
619*19aa95e4SMarcin Wojtas 	error = enetc_ctrl_send(sc, (BDCR_CMD_RSS << 8) | BDCR_CMD_RSS_WRITE,
620*19aa95e4SMarcin Wojtas 	    buckets_num * sizeof(*rss_table), &dma);
621*19aa95e4SMarcin Wojtas 	if (error != 0)
622*19aa95e4SMarcin Wojtas 		device_printf(sc->dev, "Failed to setup RSS table\n");
623*19aa95e4SMarcin Wojtas 
624*19aa95e4SMarcin Wojtas 	iflib_dma_free(&dma);
625*19aa95e4SMarcin Wojtas 
626*19aa95e4SMarcin Wojtas 	return (error);
627*19aa95e4SMarcin Wojtas }
628*19aa95e4SMarcin Wojtas 
629*19aa95e4SMarcin Wojtas static int
630*19aa95e4SMarcin Wojtas enetc_ctrl_send(struct enetc_softc *sc, uint16_t cmd, uint16_t size,
631*19aa95e4SMarcin Wojtas     iflib_dma_info_t dma)
632*19aa95e4SMarcin Wojtas {
633*19aa95e4SMarcin Wojtas 	struct enetc_ctrl_queue *queue;
634*19aa95e4SMarcin Wojtas 	struct enetc_cbd *desc;
635*19aa95e4SMarcin Wojtas 	int timeout = 1000;
636*19aa95e4SMarcin Wojtas 
637*19aa95e4SMarcin Wojtas 	queue = &sc->ctrl_queue;
638*19aa95e4SMarcin Wojtas 	desc = &queue->ring[queue->pidx];
639*19aa95e4SMarcin Wojtas 
640*19aa95e4SMarcin Wojtas 	if (++queue->pidx == ENETC_MIN_DESC)
641*19aa95e4SMarcin Wojtas 		queue->pidx = 0;
642*19aa95e4SMarcin Wojtas 
643*19aa95e4SMarcin Wojtas 	desc->addr[0] = (uint32_t)dma->idi_paddr;
644*19aa95e4SMarcin Wojtas 	desc->addr[1] = (uint32_t)(dma->idi_paddr >> 32);
645*19aa95e4SMarcin Wojtas 	desc->index = 0;
646*19aa95e4SMarcin Wojtas 	desc->length = (uint16_t)size;
647*19aa95e4SMarcin Wojtas 	desc->cmd = (uint8_t)cmd;
648*19aa95e4SMarcin Wojtas 	desc->cls = (uint8_t)(cmd >> 8);
649*19aa95e4SMarcin Wojtas 	desc->status_flags = 0;
650*19aa95e4SMarcin Wojtas 
651*19aa95e4SMarcin Wojtas 	/* Sync command packet, */
652*19aa95e4SMarcin Wojtas 	bus_dmamap_sync(dma->idi_tag, dma->idi_map, BUS_DMASYNC_PREWRITE);
653*19aa95e4SMarcin Wojtas 	/* and the control ring. */
654*19aa95e4SMarcin Wojtas 	bus_dmamap_sync(queue->dma.idi_tag, queue->dma.idi_map, BUS_DMASYNC_PREWRITE);
655*19aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRPIR, queue->pidx);
656*19aa95e4SMarcin Wojtas 
657*19aa95e4SMarcin Wojtas 	while (--timeout != 0) {
658*19aa95e4SMarcin Wojtas 		DELAY(20);
659*19aa95e4SMarcin Wojtas 		if (ENETC_RD4(sc, ENETC_SICBDRCIR) == queue->pidx)
660*19aa95e4SMarcin Wojtas 			break;
661*19aa95e4SMarcin Wojtas 	}
662*19aa95e4SMarcin Wojtas 
663*19aa95e4SMarcin Wojtas 	if (timeout == 0)
664*19aa95e4SMarcin Wojtas 		return (ETIMEDOUT);
665*19aa95e4SMarcin Wojtas 
666*19aa95e4SMarcin Wojtas 	bus_dmamap_sync(dma->idi_tag, dma->idi_map, BUS_DMASYNC_POSTREAD);
667*19aa95e4SMarcin Wojtas 	return (0);
668*19aa95e4SMarcin Wojtas }
669*19aa95e4SMarcin Wojtas 
670*19aa95e4SMarcin Wojtas static void
671*19aa95e4SMarcin Wojtas enetc_init_hw(struct enetc_softc *sc)
672*19aa95e4SMarcin Wojtas {
673*19aa95e4SMarcin Wojtas 	uint32_t val;
674*19aa95e4SMarcin Wojtas 	int error;
675*19aa95e4SMarcin Wojtas 
676*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PM0_CMD_CFG,
677*19aa95e4SMarcin Wojtas 	    ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC |
678*19aa95e4SMarcin Wojtas 	    ENETC_PM0_TX_EN | ENETC_PM0_RX_EN);
679*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PM0_RX_FIFO, ENETC_PM0_RX_FIFO_VAL);
680*19aa95e4SMarcin Wojtas 	val = ENETC_PSICFGR0_SET_TXBDR(sc->tx_num_queues);
681*19aa95e4SMarcin Wojtas 	val |= ENETC_PSICFGR0_SET_RXBDR(sc->rx_num_queues);
682*19aa95e4SMarcin Wojtas 	val |= ENETC_PSICFGR0_SIVC(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S);
683*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSICFGR0(0), val);
684*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIPVMR, ENETC_PSIPVMR_SET_VUTA(1));
685*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PVCLCTR,  ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S);
686*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIVLANFMR, ENETC_PSIVLANFMR_VS);
687*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PAR_PORT_CFG, ENETC_PAR_PORT_L4CD);
688*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PMR, ENETC_PMR_SI0EN | ENETC_PMR_PSPEED_1000M);
689*19aa95e4SMarcin Wojtas 
690*19aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICAR0,
691*19aa95e4SMarcin Wojtas 	    ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);
692*19aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICAR1, ENETC_SICAR_MSI);
693*19aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICAR2,
694*19aa95e4SMarcin Wojtas 	    ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);
695*19aa95e4SMarcin Wojtas 
696*19aa95e4SMarcin Wojtas 	enetc_init_ctrl(sc);
697*19aa95e4SMarcin Wojtas 	error = enetc_setup_rss(sc);
698*19aa95e4SMarcin Wojtas 	if (error != 0)
699*19aa95e4SMarcin Wojtas 		ENETC_WR4(sc, ENETC_SIMR, ENETC_SIMR_EN);
700*19aa95e4SMarcin Wojtas 	else
701*19aa95e4SMarcin Wojtas 		ENETC_WR4(sc, ENETC_SIMR, ENETC_SIMR_EN | ENETC_SIMR_RSSE);
702*19aa95e4SMarcin Wojtas 
703*19aa95e4SMarcin Wojtas }
704*19aa95e4SMarcin Wojtas 
705*19aa95e4SMarcin Wojtas static void
706*19aa95e4SMarcin Wojtas enetc_init_ctrl(struct enetc_softc *sc)
707*19aa95e4SMarcin Wojtas {
708*19aa95e4SMarcin Wojtas 	struct enetc_ctrl_queue *queue = &sc->ctrl_queue;
709*19aa95e4SMarcin Wojtas 
710*19aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRBAR0,
711*19aa95e4SMarcin Wojtas 	    (uint32_t)queue->dma.idi_paddr);
712*19aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRBAR1,
713*19aa95e4SMarcin Wojtas 	    (uint32_t)(queue->dma.idi_paddr >> 32));
714*19aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRLENR,
715*19aa95e4SMarcin Wojtas 	    queue->dma.idi_size / sizeof(struct enetc_cbd));
716*19aa95e4SMarcin Wojtas 
717*19aa95e4SMarcin Wojtas 	queue->pidx = 0;
718*19aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRPIR, queue->pidx);
719*19aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRCIR, queue->pidx);
720*19aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRMR, ENETC_SICBDRMR_EN);
721*19aa95e4SMarcin Wojtas }
722*19aa95e4SMarcin Wojtas 
723*19aa95e4SMarcin Wojtas static void
724*19aa95e4SMarcin Wojtas enetc_init_tx(struct enetc_softc *sc)
725*19aa95e4SMarcin Wojtas {
726*19aa95e4SMarcin Wojtas 	struct enetc_tx_queue *queue;
727*19aa95e4SMarcin Wojtas 	int i;
728*19aa95e4SMarcin Wojtas 
729*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->tx_num_queues; i++) {
730*19aa95e4SMarcin Wojtas 		queue = &sc->tx_queues[i];
731*19aa95e4SMarcin Wojtas 
732*19aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBBAR0,
733*19aa95e4SMarcin Wojtas 		    (uint32_t)queue->ring_paddr);
734*19aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBBAR1,
735*19aa95e4SMarcin Wojtas 		    (uint32_t)(queue->ring_paddr >> 32));
736*19aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBLENR, sc->tx_queue_size);
737*19aa95e4SMarcin Wojtas 
738*19aa95e4SMarcin Wojtas 		/*
739*19aa95e4SMarcin Wojtas 		 * Even though it is undoccumented resetting the TX ring
740*19aa95e4SMarcin Wojtas 		 * indices results in TX hang.
741*19aa95e4SMarcin Wojtas 		 * Do the same as Linux and simply keep those unchanged
742*19aa95e4SMarcin Wojtas 		 * for the drivers lifetime.
743*19aa95e4SMarcin Wojtas 		 */
744*19aa95e4SMarcin Wojtas #if 0
745*19aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBPIR, 0);
746*19aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBCIR, 0);
747*19aa95e4SMarcin Wojtas #endif
748*19aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBMR, ENETC_TBMR_EN);
749*19aa95e4SMarcin Wojtas 	}
750*19aa95e4SMarcin Wojtas 
751*19aa95e4SMarcin Wojtas }
752*19aa95e4SMarcin Wojtas 
753*19aa95e4SMarcin Wojtas static void
754*19aa95e4SMarcin Wojtas enetc_init_rx(struct enetc_softc *sc)
755*19aa95e4SMarcin Wojtas {
756*19aa95e4SMarcin Wojtas 	struct enetc_rx_queue *queue;
757*19aa95e4SMarcin Wojtas 	uint32_t rx_buf_size;
758*19aa95e4SMarcin Wojtas 	int i;
759*19aa95e4SMarcin Wojtas 
760*19aa95e4SMarcin Wojtas 	rx_buf_size = iflib_get_rx_mbuf_sz(sc->ctx);
761*19aa95e4SMarcin Wojtas 
762*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++) {
763*19aa95e4SMarcin Wojtas 		queue = &sc->rx_queues[i];
764*19aa95e4SMarcin Wojtas 
765*19aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBBAR0,
766*19aa95e4SMarcin Wojtas 		    (uint32_t)queue->ring_paddr);
767*19aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBBAR1,
768*19aa95e4SMarcin Wojtas 		    (uint32_t)(queue->ring_paddr >> 32));
769*19aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBLENR, sc->rx_queue_size);
770*19aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBBSR, rx_buf_size);
771*19aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBPIR, 0);
772*19aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBCIR, 0);
773*19aa95e4SMarcin Wojtas 		queue->enabled = false;
774*19aa95e4SMarcin Wojtas 	}
775*19aa95e4SMarcin Wojtas }
776*19aa95e4SMarcin Wojtas 
777*19aa95e4SMarcin Wojtas static u_int
778*19aa95e4SMarcin Wojtas enetc_hash_mac(void *arg, struct sockaddr_dl *sdl, u_int cnt)
779*19aa95e4SMarcin Wojtas {
780*19aa95e4SMarcin Wojtas 	uint64_t *bitmap = arg;
781*19aa95e4SMarcin Wojtas 	uint64_t address = 0;
782*19aa95e4SMarcin Wojtas 	uint8_t hash = 0;
783*19aa95e4SMarcin Wojtas 	bool bit;
784*19aa95e4SMarcin Wojtas 	int i, j;
785*19aa95e4SMarcin Wojtas 
786*19aa95e4SMarcin Wojtas 	bcopy(LLADDR(sdl), &address, ETHER_ADDR_LEN);
787*19aa95e4SMarcin Wojtas 
788*19aa95e4SMarcin Wojtas 	/*
789*19aa95e4SMarcin Wojtas 	 * The six bit hash is calculated by xoring every
790*19aa95e4SMarcin Wojtas 	 * 6th bit of the address.
791*19aa95e4SMarcin Wojtas 	 * It is then used as an index in a bitmap that is
792*19aa95e4SMarcin Wojtas 	 * written to the device.
793*19aa95e4SMarcin Wojtas 	 */
794*19aa95e4SMarcin Wojtas 	for (i = 0; i < 6; i++) {
795*19aa95e4SMarcin Wojtas 		bit = 0;
796*19aa95e4SMarcin Wojtas 		for (j = 0; j < 8; j++)
797*19aa95e4SMarcin Wojtas 			bit ^= address & BIT(i + j*6);
798*19aa95e4SMarcin Wojtas 
799*19aa95e4SMarcin Wojtas 		hash |= bit << i;
800*19aa95e4SMarcin Wojtas 	}
801*19aa95e4SMarcin Wojtas 
802*19aa95e4SMarcin Wojtas 	*bitmap |= (1 << hash);
803*19aa95e4SMarcin Wojtas 	return (1);
804*19aa95e4SMarcin Wojtas }
805*19aa95e4SMarcin Wojtas 
806*19aa95e4SMarcin Wojtas static void
807*19aa95e4SMarcin Wojtas enetc_setup_multicast(if_ctx_t ctx)
808*19aa95e4SMarcin Wojtas {
809*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
810*19aa95e4SMarcin Wojtas 	struct ifnet *ifp;
811*19aa95e4SMarcin Wojtas 	uint64_t bitmap = 0;
812*19aa95e4SMarcin Wojtas 	uint8_t revid;
813*19aa95e4SMarcin Wojtas 
814*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
815*19aa95e4SMarcin Wojtas 	ifp = iflib_get_ifp(ctx);
816*19aa95e4SMarcin Wojtas 	revid = pci_get_revid(sc->dev);
817*19aa95e4SMarcin Wojtas 
818*19aa95e4SMarcin Wojtas 	if_foreach_llmaddr(ifp, enetc_hash_mac, &bitmap);
819*19aa95e4SMarcin Wojtas 
820*19aa95e4SMarcin Wojtas 	/*
821*19aa95e4SMarcin Wojtas 	 * In revid 1 of this chip the positions multicast and unicast
822*19aa95e4SMarcin Wojtas 	 * hash filter registers are flipped.
823*19aa95e4SMarcin Wojtas 	 */
824*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIMMHFR0(0, revid == 1), bitmap & UINT32_MAX);
825*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIMMHFR1(0), bitmap >> 32);
826*19aa95e4SMarcin Wojtas 
827*19aa95e4SMarcin Wojtas }
828*19aa95e4SMarcin Wojtas 
829*19aa95e4SMarcin Wojtas static uint8_t
830*19aa95e4SMarcin Wojtas enetc_hash_vid(uint16_t vid)
831*19aa95e4SMarcin Wojtas {
832*19aa95e4SMarcin Wojtas 	uint8_t hash = 0;
833*19aa95e4SMarcin Wojtas 	bool bit;
834*19aa95e4SMarcin Wojtas 	int i;
835*19aa95e4SMarcin Wojtas 
836*19aa95e4SMarcin Wojtas 	for (i = 0;i < 6;i++) {
837*19aa95e4SMarcin Wojtas 		bit = vid & BIT(i);
838*19aa95e4SMarcin Wojtas 		bit ^= vid & BIT(i + 6);
839*19aa95e4SMarcin Wojtas 		hash |= bit << i;
840*19aa95e4SMarcin Wojtas 	}
841*19aa95e4SMarcin Wojtas 
842*19aa95e4SMarcin Wojtas 	return (hash);
843*19aa95e4SMarcin Wojtas }
844*19aa95e4SMarcin Wojtas 
845*19aa95e4SMarcin Wojtas static void
846*19aa95e4SMarcin Wojtas enetc_vlan_register(if_ctx_t ctx, uint16_t vid)
847*19aa95e4SMarcin Wojtas {
848*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
849*19aa95e4SMarcin Wojtas 	uint8_t hash;
850*19aa95e4SMarcin Wojtas 	uint64_t bitmap;
851*19aa95e4SMarcin Wojtas 
852*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
853*19aa95e4SMarcin Wojtas 	hash = enetc_hash_vid(vid);
854*19aa95e4SMarcin Wojtas 
855*19aa95e4SMarcin Wojtas 	/* Check if hash is alredy present in the bitmap. */
856*19aa95e4SMarcin Wojtas 	if (++sc->vlan_bitmap[hash] != 1)
857*19aa95e4SMarcin Wojtas 		return;
858*19aa95e4SMarcin Wojtas 
859*19aa95e4SMarcin Wojtas 	bitmap = ENETC_PORT_RD4(sc, ENETC_PSIVHFR0(0));
860*19aa95e4SMarcin Wojtas 	bitmap |= (uint64_t)ENETC_PORT_RD4(sc, ENETC_PSIVHFR1(0)) << 32;
861*19aa95e4SMarcin Wojtas 	bitmap |= BIT(hash);
862*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIVHFR0(0), bitmap & UINT32_MAX);
863*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIVHFR1(0), bitmap >> 32);
864*19aa95e4SMarcin Wojtas }
865*19aa95e4SMarcin Wojtas 
866*19aa95e4SMarcin Wojtas static void
867*19aa95e4SMarcin Wojtas enetc_vlan_unregister(if_ctx_t ctx, uint16_t vid)
868*19aa95e4SMarcin Wojtas {
869*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
870*19aa95e4SMarcin Wojtas 	uint8_t hash;
871*19aa95e4SMarcin Wojtas 	uint64_t bitmap;
872*19aa95e4SMarcin Wojtas 
873*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
874*19aa95e4SMarcin Wojtas 	hash = enetc_hash_vid(vid);
875*19aa95e4SMarcin Wojtas 
876*19aa95e4SMarcin Wojtas 	MPASS(sc->vlan_bitmap[hash] > 0);
877*19aa95e4SMarcin Wojtas 	if (--sc->vlan_bitmap[hash] != 0)
878*19aa95e4SMarcin Wojtas 		return;
879*19aa95e4SMarcin Wojtas 
880*19aa95e4SMarcin Wojtas 	bitmap = ENETC_PORT_RD4(sc, ENETC_PSIVHFR0(0));
881*19aa95e4SMarcin Wojtas 	bitmap |= (uint64_t)ENETC_PORT_RD4(sc, ENETC_PSIVHFR1(0)) << 32;
882*19aa95e4SMarcin Wojtas 	bitmap &= ~BIT(hash);
883*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIVHFR0(0), bitmap & UINT32_MAX);
884*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIVHFR1(0), bitmap >> 32);
885*19aa95e4SMarcin Wojtas }
886*19aa95e4SMarcin Wojtas 
887*19aa95e4SMarcin Wojtas static void
888*19aa95e4SMarcin Wojtas enetc_init(if_ctx_t ctx)
889*19aa95e4SMarcin Wojtas {
890*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
891*19aa95e4SMarcin Wojtas 	struct mii_data *miid;
892*19aa95e4SMarcin Wojtas 	struct ifnet *ifp;
893*19aa95e4SMarcin Wojtas 	uint16_t max_frame_length;
894*19aa95e4SMarcin Wojtas 	int baudrate;
895*19aa95e4SMarcin Wojtas 
896*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
897*19aa95e4SMarcin Wojtas 	ifp = iflib_get_ifp(ctx);
898*19aa95e4SMarcin Wojtas 
899*19aa95e4SMarcin Wojtas 	max_frame_length = sc->shared->isc_max_frame_size;
900*19aa95e4SMarcin Wojtas 	MPASS(max_frame_length < ENETC_MAX_FRAME_LEN);
901*19aa95e4SMarcin Wojtas 
902*19aa95e4SMarcin Wojtas 	/* Set max RX and TX frame lengths. */
903*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PM0_MAXFRM, max_frame_length);
904*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PTCMSDUR(0), max_frame_length);
905*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PTXMBAR, 2 * max_frame_length);
906*19aa95e4SMarcin Wojtas 
907*19aa95e4SMarcin Wojtas 	/* Set "VLAN promiscious" mode if filtering is disabled. */
908*19aa95e4SMarcin Wojtas 	if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0)
909*19aa95e4SMarcin Wojtas 		ENETC_PORT_WR4(sc, ENETC_PSIPVMR,
910*19aa95e4SMarcin Wojtas 		    ENETC_PSIPVMR_SET_VUTA(1) | ENETC_PSIPVMR_SET_VP(1));
911*19aa95e4SMarcin Wojtas 	else
912*19aa95e4SMarcin Wojtas 		ENETC_PORT_WR4(sc, ENETC_PSIPVMR,
913*19aa95e4SMarcin Wojtas 		    ENETC_PSIPVMR_SET_VUTA(1));
914*19aa95e4SMarcin Wojtas 
915*19aa95e4SMarcin Wojtas 	sc->rbmr = ENETC_RBMR_EN | ENETC_RBMR_AL;
916*19aa95e4SMarcin Wojtas 
917*19aa95e4SMarcin Wojtas 	if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING)
918*19aa95e4SMarcin Wojtas 		sc->rbmr |= ENETC_RBMR_VTE;
919*19aa95e4SMarcin Wojtas 
920*19aa95e4SMarcin Wojtas 	/* Write MAC address to hardware. */
921*19aa95e4SMarcin Wojtas 	enetc_set_hwaddr(sc);
922*19aa95e4SMarcin Wojtas 
923*19aa95e4SMarcin Wojtas 	enetc_init_tx(sc);
924*19aa95e4SMarcin Wojtas 	enetc_init_rx(sc);
925*19aa95e4SMarcin Wojtas 
926*19aa95e4SMarcin Wojtas 	if (sc->fixed_link) {
927*19aa95e4SMarcin Wojtas 		baudrate = ifmedia_baudrate(sc->fixed_ifmedia.ifm_cur->ifm_media);
928*19aa95e4SMarcin Wojtas 		iflib_link_state_change(sc->ctx, LINK_STATE_UP, baudrate);
929*19aa95e4SMarcin Wojtas 	} else {
930*19aa95e4SMarcin Wojtas 		/*
931*19aa95e4SMarcin Wojtas 		 * Can't return an error from this function, there is not much
932*19aa95e4SMarcin Wojtas 		 * we can do if this fails.
933*19aa95e4SMarcin Wojtas 		 */
934*19aa95e4SMarcin Wojtas 		miid = device_get_softc(sc->miibus);
935*19aa95e4SMarcin Wojtas 		(void)mii_mediachg(miid);
936*19aa95e4SMarcin Wojtas 	}
937*19aa95e4SMarcin Wojtas 
938*19aa95e4SMarcin Wojtas 	enetc_promisc_set(ctx, if_getflags(ifp));
939*19aa95e4SMarcin Wojtas }
940*19aa95e4SMarcin Wojtas 
941*19aa95e4SMarcin Wojtas static void
942*19aa95e4SMarcin Wojtas enetc_stop(if_ctx_t ctx)
943*19aa95e4SMarcin Wojtas {
944*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
945*19aa95e4SMarcin Wojtas 	int i;
946*19aa95e4SMarcin Wojtas 
947*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
948*19aa95e4SMarcin Wojtas 
949*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->tx_num_queues; i++)
950*19aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBMR, 0);
951*19aa95e4SMarcin Wojtas 
952*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++)
953*19aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBMR, 0);
954*19aa95e4SMarcin Wojtas }
955*19aa95e4SMarcin Wojtas 
956*19aa95e4SMarcin Wojtas static int
957*19aa95e4SMarcin Wojtas enetc_msix_intr_assign(if_ctx_t ctx, int msix)
958*19aa95e4SMarcin Wojtas {
959*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
960*19aa95e4SMarcin Wojtas 	struct enetc_rx_queue *rx_queue;
961*19aa95e4SMarcin Wojtas 	struct enetc_tx_queue *tx_queue;
962*19aa95e4SMarcin Wojtas 	int vector = 0, i, error;
963*19aa95e4SMarcin Wojtas 	char irq_name[16];
964*19aa95e4SMarcin Wojtas 
965*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
966*19aa95e4SMarcin Wojtas 
967*19aa95e4SMarcin Wojtas 	MPASS(sc->rx_num_queues + 1 <= ENETC_MSIX_COUNT);
968*19aa95e4SMarcin Wojtas 	MPASS(sc->rx_num_queues == sc->tx_num_queues);
969*19aa95e4SMarcin Wojtas 
970*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++, vector++) {
971*19aa95e4SMarcin Wojtas 		rx_queue = &sc->rx_queues[i];
972*19aa95e4SMarcin Wojtas 		snprintf(irq_name, sizeof(irq_name), "rxtxq%d", i);
973*19aa95e4SMarcin Wojtas 		error = iflib_irq_alloc_generic(ctx,
974*19aa95e4SMarcin Wojtas 		    &rx_queue->irq, vector + 1, IFLIB_INTR_RXTX,
975*19aa95e4SMarcin Wojtas 		    NULL, rx_queue, i, irq_name);
976*19aa95e4SMarcin Wojtas 		if (error != 0)
977*19aa95e4SMarcin Wojtas 			goto fail;
978*19aa95e4SMarcin Wojtas 
979*19aa95e4SMarcin Wojtas 		ENETC_WR4(sc, ENETC_SIMSIRRV(i), vector);
980*19aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBICR1, ENETC_RX_INTR_TIME_THR);
981*19aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBICR0,
982*19aa95e4SMarcin Wojtas 		    ENETC_RBICR0_ICEN | ENETC_RBICR0_SET_ICPT(ENETC_RX_INTR_PKT_THR));
983*19aa95e4SMarcin Wojtas 	}
984*19aa95e4SMarcin Wojtas 	vector = 0;
985*19aa95e4SMarcin Wojtas 	for (i = 0;i < sc->tx_num_queues; i++, vector++) {
986*19aa95e4SMarcin Wojtas 		tx_queue = &sc->tx_queues[i];
987*19aa95e4SMarcin Wojtas 		snprintf(irq_name, sizeof(irq_name), "txq%d", i);
988*19aa95e4SMarcin Wojtas 		iflib_softirq_alloc_generic(ctx, &tx_queue->irq,
989*19aa95e4SMarcin Wojtas 		    IFLIB_INTR_TX, tx_queue, i, irq_name);
990*19aa95e4SMarcin Wojtas 
991*19aa95e4SMarcin Wojtas 		ENETC_WR4(sc, ENETC_SIMSITRV(i), vector);
992*19aa95e4SMarcin Wojtas 	}
993*19aa95e4SMarcin Wojtas 
994*19aa95e4SMarcin Wojtas 	return (0);
995*19aa95e4SMarcin Wojtas fail:
996*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++) {
997*19aa95e4SMarcin Wojtas 		rx_queue = &sc->rx_queues[i];
998*19aa95e4SMarcin Wojtas 		iflib_irq_free(ctx, &rx_queue->irq);
999*19aa95e4SMarcin Wojtas 	}
1000*19aa95e4SMarcin Wojtas 	return (error);
1001*19aa95e4SMarcin Wojtas }
1002*19aa95e4SMarcin Wojtas 
1003*19aa95e4SMarcin Wojtas static int
1004*19aa95e4SMarcin Wojtas enetc_tx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
1005*19aa95e4SMarcin Wojtas {
1006*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1007*19aa95e4SMarcin Wojtas 
1008*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
1009*19aa95e4SMarcin Wojtas 	ENETC_TXQ_RD4(sc, qid, ENETC_TBIDR);
1010*19aa95e4SMarcin Wojtas 	return (0);
1011*19aa95e4SMarcin Wojtas }
1012*19aa95e4SMarcin Wojtas 
1013*19aa95e4SMarcin Wojtas static int
1014*19aa95e4SMarcin Wojtas enetc_rx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
1015*19aa95e4SMarcin Wojtas {
1016*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1017*19aa95e4SMarcin Wojtas 
1018*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
1019*19aa95e4SMarcin Wojtas 	ENETC_RXQ_RD4(sc, qid, ENETC_RBIDR);
1020*19aa95e4SMarcin Wojtas 	return (0);
1021*19aa95e4SMarcin Wojtas }
1022*19aa95e4SMarcin Wojtas static void
1023*19aa95e4SMarcin Wojtas enetc_intr_enable(if_ctx_t ctx)
1024*19aa95e4SMarcin Wojtas {
1025*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1026*19aa95e4SMarcin Wojtas 	int i;
1027*19aa95e4SMarcin Wojtas 
1028*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
1029*19aa95e4SMarcin Wojtas 
1030*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++)
1031*19aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBIER, ENETC_RBIER_RXTIE);
1032*19aa95e4SMarcin Wojtas 
1033*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->tx_num_queues; i++)
1034*19aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBIER, ENETC_TBIER_TXF);
1035*19aa95e4SMarcin Wojtas }
1036*19aa95e4SMarcin Wojtas 
1037*19aa95e4SMarcin Wojtas static void
1038*19aa95e4SMarcin Wojtas enetc_intr_disable(if_ctx_t ctx)
1039*19aa95e4SMarcin Wojtas {
1040*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1041*19aa95e4SMarcin Wojtas 	int i;
1042*19aa95e4SMarcin Wojtas 
1043*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
1044*19aa95e4SMarcin Wojtas 
1045*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++)
1046*19aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBIER, 0);
1047*19aa95e4SMarcin Wojtas 
1048*19aa95e4SMarcin Wojtas 	for (i = 0; i < sc->tx_num_queues; i++)
1049*19aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBIER, 0);
1050*19aa95e4SMarcin Wojtas }
1051*19aa95e4SMarcin Wojtas 
1052*19aa95e4SMarcin Wojtas static int
1053*19aa95e4SMarcin Wojtas enetc_isc_txd_encap(void *data, if_pkt_info_t ipi)
1054*19aa95e4SMarcin Wojtas {
1055*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
1056*19aa95e4SMarcin Wojtas 	struct enetc_tx_queue *queue;
1057*19aa95e4SMarcin Wojtas 	union enetc_tx_bd *desc;
1058*19aa95e4SMarcin Wojtas 	bus_dma_segment_t *segs;
1059*19aa95e4SMarcin Wojtas 	qidx_t pidx, queue_len;
1060*19aa95e4SMarcin Wojtas 	qidx_t i = 0;
1061*19aa95e4SMarcin Wojtas 
1062*19aa95e4SMarcin Wojtas 	queue = &sc->tx_queues[ipi->ipi_qsidx];
1063*19aa95e4SMarcin Wojtas 	segs = ipi->ipi_segs;
1064*19aa95e4SMarcin Wojtas 	pidx = ipi->ipi_pidx;
1065*19aa95e4SMarcin Wojtas 	queue_len = sc->tx_queue_size;
1066*19aa95e4SMarcin Wojtas 
1067*19aa95e4SMarcin Wojtas 	/*
1068*19aa95e4SMarcin Wojtas 	 * First descriptor is special. We use it to set frame
1069*19aa95e4SMarcin Wojtas 	 * related information and offloads, e.g. VLAN tag.
1070*19aa95e4SMarcin Wojtas 	 */
1071*19aa95e4SMarcin Wojtas 	desc = &queue->ring[pidx];
1072*19aa95e4SMarcin Wojtas 	bzero(desc, sizeof(*desc));
1073*19aa95e4SMarcin Wojtas 	desc->frm_len = ipi->ipi_len;
1074*19aa95e4SMarcin Wojtas 	desc->addr = segs[i].ds_addr;
1075*19aa95e4SMarcin Wojtas 	desc->buf_len = segs[i].ds_len;
1076*19aa95e4SMarcin Wojtas 	if (ipi->ipi_flags & IPI_TX_INTR)
1077*19aa95e4SMarcin Wojtas 		desc->flags = ENETC_TXBD_FLAGS_FI;
1078*19aa95e4SMarcin Wojtas 
1079*19aa95e4SMarcin Wojtas 	i++;
1080*19aa95e4SMarcin Wojtas 	if (++pidx == queue_len)
1081*19aa95e4SMarcin Wojtas 		pidx = 0;
1082*19aa95e4SMarcin Wojtas 
1083*19aa95e4SMarcin Wojtas 	if (ipi->ipi_mflags & M_VLANTAG) {
1084*19aa95e4SMarcin Wojtas 		/* VLAN tag is inserted in a separate descriptor. */
1085*19aa95e4SMarcin Wojtas 		desc->flags |= ENETC_TXBD_FLAGS_EX;
1086*19aa95e4SMarcin Wojtas 		desc = &queue->ring[pidx];
1087*19aa95e4SMarcin Wojtas 		bzero(desc, sizeof(*desc));
1088*19aa95e4SMarcin Wojtas 		desc->ext.vid = ipi->ipi_vtag;
1089*19aa95e4SMarcin Wojtas 		desc->ext.e_flags = ENETC_TXBD_E_FLAGS_VLAN_INS;
1090*19aa95e4SMarcin Wojtas 		if (++pidx == queue_len)
1091*19aa95e4SMarcin Wojtas 			pidx = 0;
1092*19aa95e4SMarcin Wojtas 	}
1093*19aa95e4SMarcin Wojtas 
1094*19aa95e4SMarcin Wojtas 	/* Now add remaining descriptors. */
1095*19aa95e4SMarcin Wojtas 	for (;i < ipi->ipi_nsegs; i++) {
1096*19aa95e4SMarcin Wojtas 		desc = &queue->ring[pidx];
1097*19aa95e4SMarcin Wojtas 		bzero(desc, sizeof(*desc));
1098*19aa95e4SMarcin Wojtas 		desc->addr = segs[i].ds_addr;
1099*19aa95e4SMarcin Wojtas 		desc->buf_len = segs[i].ds_len;
1100*19aa95e4SMarcin Wojtas 
1101*19aa95e4SMarcin Wojtas 		if (++pidx == queue_len)
1102*19aa95e4SMarcin Wojtas 			pidx = 0;
1103*19aa95e4SMarcin Wojtas 	}
1104*19aa95e4SMarcin Wojtas 
1105*19aa95e4SMarcin Wojtas 	desc->flags |= ENETC_TXBD_FLAGS_F;
1106*19aa95e4SMarcin Wojtas 	ipi->ipi_new_pidx = pidx;
1107*19aa95e4SMarcin Wojtas 	if (pidx == queue->next_to_clean)
1108*19aa95e4SMarcin Wojtas 		queue->ring_full = true;
1109*19aa95e4SMarcin Wojtas 
1110*19aa95e4SMarcin Wojtas 	return (0);
1111*19aa95e4SMarcin Wojtas }
1112*19aa95e4SMarcin Wojtas 
1113*19aa95e4SMarcin Wojtas static void
1114*19aa95e4SMarcin Wojtas enetc_isc_txd_flush(void *data, uint16_t qid, qidx_t pidx)
1115*19aa95e4SMarcin Wojtas {
1116*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
1117*19aa95e4SMarcin Wojtas 
1118*19aa95e4SMarcin Wojtas 	ENETC_TXQ_WR4(sc, qid, ENETC_TBPIR, pidx);
1119*19aa95e4SMarcin Wojtas }
1120*19aa95e4SMarcin Wojtas 
1121*19aa95e4SMarcin Wojtas static int
1122*19aa95e4SMarcin Wojtas enetc_isc_txd_credits_update(void *data, uint16_t qid, bool clear)
1123*19aa95e4SMarcin Wojtas {
1124*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
1125*19aa95e4SMarcin Wojtas 	struct enetc_tx_queue *queue;
1126*19aa95e4SMarcin Wojtas 	qidx_t next_to_clean, next_to_process;
1127*19aa95e4SMarcin Wojtas 	int clean_count;
1128*19aa95e4SMarcin Wojtas 
1129*19aa95e4SMarcin Wojtas 	queue = &sc->tx_queues[qid];
1130*19aa95e4SMarcin Wojtas 	next_to_process =
1131*19aa95e4SMarcin Wojtas 	    ENETC_TXQ_RD4(sc, qid, ENETC_TBCIR) & ENETC_TBCIR_IDX_MASK;
1132*19aa95e4SMarcin Wojtas 	next_to_clean = queue->next_to_clean;
1133*19aa95e4SMarcin Wojtas 
1134*19aa95e4SMarcin Wojtas 	if (next_to_clean == next_to_process && !queue->ring_full)
1135*19aa95e4SMarcin Wojtas 		return (0);
1136*19aa95e4SMarcin Wojtas 
1137*19aa95e4SMarcin Wojtas 	if (!clear)
1138*19aa95e4SMarcin Wojtas 		return (1);
1139*19aa95e4SMarcin Wojtas 
1140*19aa95e4SMarcin Wojtas 	clean_count = next_to_process - next_to_clean;
1141*19aa95e4SMarcin Wojtas 	if (clean_count <= 0)
1142*19aa95e4SMarcin Wojtas 		clean_count += sc->tx_queue_size;
1143*19aa95e4SMarcin Wojtas 
1144*19aa95e4SMarcin Wojtas 	queue->next_to_clean = next_to_process;
1145*19aa95e4SMarcin Wojtas 	queue->ring_full = false;
1146*19aa95e4SMarcin Wojtas 
1147*19aa95e4SMarcin Wojtas 	return (clean_count);
1148*19aa95e4SMarcin Wojtas }
1149*19aa95e4SMarcin Wojtas 
1150*19aa95e4SMarcin Wojtas static int
1151*19aa95e4SMarcin Wojtas enetc_isc_rxd_available(void *data, uint16_t qid, qidx_t pidx, qidx_t budget)
1152*19aa95e4SMarcin Wojtas {
1153*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
1154*19aa95e4SMarcin Wojtas 	struct enetc_rx_queue *queue;
1155*19aa95e4SMarcin Wojtas 	qidx_t hw_pidx, queue_len;
1156*19aa95e4SMarcin Wojtas 	union enetc_rx_bd *desc;
1157*19aa95e4SMarcin Wojtas 	int count = 0;
1158*19aa95e4SMarcin Wojtas 
1159*19aa95e4SMarcin Wojtas 	queue = &sc->rx_queues[qid];
1160*19aa95e4SMarcin Wojtas 	desc = &queue->ring[pidx];
1161*19aa95e4SMarcin Wojtas 	queue_len = sc->rx_queue_size;
1162*19aa95e4SMarcin Wojtas 
1163*19aa95e4SMarcin Wojtas 	if (desc->r.lstatus == 0)
1164*19aa95e4SMarcin Wojtas 		return (0);
1165*19aa95e4SMarcin Wojtas 
1166*19aa95e4SMarcin Wojtas 	if (budget == 1)
1167*19aa95e4SMarcin Wojtas 		return (1);
1168*19aa95e4SMarcin Wojtas 
1169*19aa95e4SMarcin Wojtas 	hw_pidx = ENETC_RXQ_RD4(sc, qid, ENETC_RBPIR);
1170*19aa95e4SMarcin Wojtas 	while (pidx != hw_pidx && count < budget) {
1171*19aa95e4SMarcin Wojtas 		desc = &queue->ring[pidx];
1172*19aa95e4SMarcin Wojtas 		if (desc->r.lstatus & ENETC_RXBD_LSTATUS_F)
1173*19aa95e4SMarcin Wojtas 			count++;
1174*19aa95e4SMarcin Wojtas 
1175*19aa95e4SMarcin Wojtas 		if (++pidx == queue_len)
1176*19aa95e4SMarcin Wojtas 			pidx = 0;
1177*19aa95e4SMarcin Wojtas 	}
1178*19aa95e4SMarcin Wojtas 
1179*19aa95e4SMarcin Wojtas 	return (count);
1180*19aa95e4SMarcin Wojtas }
1181*19aa95e4SMarcin Wojtas 
1182*19aa95e4SMarcin Wojtas static int
1183*19aa95e4SMarcin Wojtas enetc_isc_rxd_pkt_get(void *data, if_rxd_info_t ri)
1184*19aa95e4SMarcin Wojtas {
1185*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
1186*19aa95e4SMarcin Wojtas 	struct enetc_rx_queue *queue;
1187*19aa95e4SMarcin Wojtas 	union enetc_rx_bd *desc;
1188*19aa95e4SMarcin Wojtas 	uint16_t buf_len, pkt_size = 0;
1189*19aa95e4SMarcin Wojtas 	qidx_t cidx, queue_len;
1190*19aa95e4SMarcin Wojtas 	uint32_t status;
1191*19aa95e4SMarcin Wojtas 	int i;
1192*19aa95e4SMarcin Wojtas 
1193*19aa95e4SMarcin Wojtas 	cidx = ri->iri_cidx;
1194*19aa95e4SMarcin Wojtas 	queue = &sc->rx_queues[ri->iri_qsidx];
1195*19aa95e4SMarcin Wojtas 	desc = &queue->ring[cidx];
1196*19aa95e4SMarcin Wojtas 	status = desc->r.lstatus;
1197*19aa95e4SMarcin Wojtas 	queue_len = sc->rx_queue_size;
1198*19aa95e4SMarcin Wojtas 
1199*19aa95e4SMarcin Wojtas 	/*
1200*19aa95e4SMarcin Wojtas 	 * Ready bit will be set only when all descriptors
1201*19aa95e4SMarcin Wojtas 	 * in the chain have been processed.
1202*19aa95e4SMarcin Wojtas 	 */
1203*19aa95e4SMarcin Wojtas 	if ((status & ENETC_RXBD_LSTATUS_R) == 0)
1204*19aa95e4SMarcin Wojtas 		return (EAGAIN);
1205*19aa95e4SMarcin Wojtas 
1206*19aa95e4SMarcin Wojtas 	/* Pass RSS hash. */
1207*19aa95e4SMarcin Wojtas 	if (status & ENETC_RXBD_FLAG_RSSV) {
1208*19aa95e4SMarcin Wojtas 		ri->iri_flowid = desc->r.rss_hash;
1209*19aa95e4SMarcin Wojtas 		ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
1210*19aa95e4SMarcin Wojtas 	}
1211*19aa95e4SMarcin Wojtas 
1212*19aa95e4SMarcin Wojtas 	/* Pass IP checksum status. */
1213*19aa95e4SMarcin Wojtas 	ri->iri_csum_flags = CSUM_IP_CHECKED;
1214*19aa95e4SMarcin Wojtas 	if ((desc->r.parse_summary & ENETC_RXBD_PARSER_ERROR) == 0)
1215*19aa95e4SMarcin Wojtas 		ri->iri_csum_flags |= CSUM_IP_VALID;
1216*19aa95e4SMarcin Wojtas 
1217*19aa95e4SMarcin Wojtas 	/* Pass extracted VLAN tag. */
1218*19aa95e4SMarcin Wojtas 	if (status & ENETC_RXBD_FLAG_VLAN) {
1219*19aa95e4SMarcin Wojtas 		ri->iri_vtag = desc->r.vlan_opt;
1220*19aa95e4SMarcin Wojtas 		ri->iri_flags = M_VLANTAG;
1221*19aa95e4SMarcin Wojtas 	}
1222*19aa95e4SMarcin Wojtas 
1223*19aa95e4SMarcin Wojtas 	for (i = 0; i < ENETC_MAX_SCATTER; i++) {
1224*19aa95e4SMarcin Wojtas 		buf_len = desc->r.buf_len;
1225*19aa95e4SMarcin Wojtas 		ri->iri_frags[i].irf_idx = cidx;
1226*19aa95e4SMarcin Wojtas 		ri->iri_frags[i].irf_len = buf_len;
1227*19aa95e4SMarcin Wojtas 		pkt_size += buf_len;
1228*19aa95e4SMarcin Wojtas 		if (desc->r.lstatus & ENETC_RXBD_LSTATUS_F)
1229*19aa95e4SMarcin Wojtas 			break;
1230*19aa95e4SMarcin Wojtas 
1231*19aa95e4SMarcin Wojtas 		if (++cidx == queue_len)
1232*19aa95e4SMarcin Wojtas 			cidx = 0;
1233*19aa95e4SMarcin Wojtas 
1234*19aa95e4SMarcin Wojtas 		desc = &queue->ring[cidx];
1235*19aa95e4SMarcin Wojtas 	}
1236*19aa95e4SMarcin Wojtas 	ri->iri_nfrags = i + 1;
1237*19aa95e4SMarcin Wojtas 	ri->iri_len = pkt_size + ENETC_RX_IP_ALIGN;
1238*19aa95e4SMarcin Wojtas 	ri->iri_pad = ENETC_RX_IP_ALIGN;
1239*19aa95e4SMarcin Wojtas 
1240*19aa95e4SMarcin Wojtas 	MPASS(desc->r.lstatus & ENETC_RXBD_LSTATUS_F);
1241*19aa95e4SMarcin Wojtas 	if (status & ENETC_RXBD_LSTATUS(ENETC_RXBD_ERR_MASK))
1242*19aa95e4SMarcin Wojtas 		return (EBADMSG);
1243*19aa95e4SMarcin Wojtas 
1244*19aa95e4SMarcin Wojtas 	return (0);
1245*19aa95e4SMarcin Wojtas }
1246*19aa95e4SMarcin Wojtas 
1247*19aa95e4SMarcin Wojtas static void
1248*19aa95e4SMarcin Wojtas enetc_isc_rxd_refill(void *data, if_rxd_update_t iru)
1249*19aa95e4SMarcin Wojtas {
1250*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
1251*19aa95e4SMarcin Wojtas 	struct enetc_rx_queue *queue;
1252*19aa95e4SMarcin Wojtas 	union enetc_rx_bd *desc;
1253*19aa95e4SMarcin Wojtas 	qidx_t pidx, queue_len;
1254*19aa95e4SMarcin Wojtas 	uint64_t *paddrs;
1255*19aa95e4SMarcin Wojtas 	int i, count;
1256*19aa95e4SMarcin Wojtas 
1257*19aa95e4SMarcin Wojtas 	queue = &sc->rx_queues[iru->iru_qsidx];
1258*19aa95e4SMarcin Wojtas 	paddrs = iru->iru_paddrs;
1259*19aa95e4SMarcin Wojtas 	pidx = iru->iru_pidx;
1260*19aa95e4SMarcin Wojtas 	count = iru->iru_count;
1261*19aa95e4SMarcin Wojtas 	queue_len = sc->rx_queue_size;
1262*19aa95e4SMarcin Wojtas 
1263*19aa95e4SMarcin Wojtas 	for (i = 0; i < count; i++) {
1264*19aa95e4SMarcin Wojtas 		desc = &queue->ring[pidx];
1265*19aa95e4SMarcin Wojtas 		bzero(desc, sizeof(*desc));
1266*19aa95e4SMarcin Wojtas 
1267*19aa95e4SMarcin Wojtas 		desc->w.addr = paddrs[i];
1268*19aa95e4SMarcin Wojtas 		if (++pidx == queue_len)
1269*19aa95e4SMarcin Wojtas 			pidx = 0;
1270*19aa95e4SMarcin Wojtas 	}
1271*19aa95e4SMarcin Wojtas 	/*
1272*19aa95e4SMarcin Wojtas 	 * After enabling the queue NIC will prefetch the first
1273*19aa95e4SMarcin Wojtas 	 * 8 descriptors. It probably assumes that the RX is fully
1274*19aa95e4SMarcin Wojtas 	 * refilled when cidx == pidx.
1275*19aa95e4SMarcin Wojtas 	 * Enable it only if we have enough decriptors ready on the ring.
1276*19aa95e4SMarcin Wojtas 	 */
1277*19aa95e4SMarcin Wojtas 	if (!queue->enabled && pidx >= 8) {
1278*19aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, iru->iru_qsidx, ENETC_RBMR, sc->rbmr);
1279*19aa95e4SMarcin Wojtas 		queue->enabled = true;
1280*19aa95e4SMarcin Wojtas 	}
1281*19aa95e4SMarcin Wojtas }
1282*19aa95e4SMarcin Wojtas 
1283*19aa95e4SMarcin Wojtas static void
1284*19aa95e4SMarcin Wojtas enetc_isc_rxd_flush(void *data, uint16_t qid, uint8_t flid, qidx_t pidx)
1285*19aa95e4SMarcin Wojtas {
1286*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
1287*19aa95e4SMarcin Wojtas 
1288*19aa95e4SMarcin Wojtas 	ENETC_RXQ_WR4(sc, qid, ENETC_RBCIR, pidx);
1289*19aa95e4SMarcin Wojtas }
1290*19aa95e4SMarcin Wojtas 
1291*19aa95e4SMarcin Wojtas static uint64_t
1292*19aa95e4SMarcin Wojtas enetc_get_counter(if_ctx_t ctx, ift_counter cnt)
1293*19aa95e4SMarcin Wojtas {
1294*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1295*19aa95e4SMarcin Wojtas 	struct ifnet *ifp;
1296*19aa95e4SMarcin Wojtas 
1297*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
1298*19aa95e4SMarcin Wojtas 	ifp = iflib_get_ifp(ctx);
1299*19aa95e4SMarcin Wojtas 
1300*19aa95e4SMarcin Wojtas 	switch (cnt) {
1301*19aa95e4SMarcin Wojtas 	case IFCOUNTER_IERRORS:
1302*19aa95e4SMarcin Wojtas 		return (ENETC_PORT_RD8(sc, ENETC_PM0_RERR));
1303*19aa95e4SMarcin Wojtas 	case IFCOUNTER_OERRORS:
1304*19aa95e4SMarcin Wojtas 		return (ENETC_PORT_RD8(sc, ENETC_PM0_TERR));
1305*19aa95e4SMarcin Wojtas 	default:
1306*19aa95e4SMarcin Wojtas 		return (if_get_counter_default(ifp, cnt));
1307*19aa95e4SMarcin Wojtas 	}
1308*19aa95e4SMarcin Wojtas }
1309*19aa95e4SMarcin Wojtas 
1310*19aa95e4SMarcin Wojtas static int
1311*19aa95e4SMarcin Wojtas enetc_mtu_set(if_ctx_t ctx, uint32_t mtu)
1312*19aa95e4SMarcin Wojtas {
1313*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc = iflib_get_softc(ctx);
1314*19aa95e4SMarcin Wojtas 	uint32_t max_frame_size;
1315*19aa95e4SMarcin Wojtas 
1316*19aa95e4SMarcin Wojtas 	max_frame_size = mtu +
1317*19aa95e4SMarcin Wojtas 	    ETHER_HDR_LEN +
1318*19aa95e4SMarcin Wojtas 	    ETHER_CRC_LEN +
1319*19aa95e4SMarcin Wojtas 	    sizeof(struct ether_vlan_header);
1320*19aa95e4SMarcin Wojtas 
1321*19aa95e4SMarcin Wojtas 	if (max_frame_size > ENETC_MAX_FRAME_LEN)
1322*19aa95e4SMarcin Wojtas 		return (EINVAL);
1323*19aa95e4SMarcin Wojtas 
1324*19aa95e4SMarcin Wojtas 	sc->shared->isc_max_frame_size = max_frame_size;
1325*19aa95e4SMarcin Wojtas 
1326*19aa95e4SMarcin Wojtas 	return (0);
1327*19aa95e4SMarcin Wojtas }
1328*19aa95e4SMarcin Wojtas 
1329*19aa95e4SMarcin Wojtas static int
1330*19aa95e4SMarcin Wojtas enetc_promisc_set(if_ctx_t ctx, int flags)
1331*19aa95e4SMarcin Wojtas {
1332*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1333*19aa95e4SMarcin Wojtas 	uint32_t reg = 0;
1334*19aa95e4SMarcin Wojtas 
1335*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
1336*19aa95e4SMarcin Wojtas 
1337*19aa95e4SMarcin Wojtas 	if (flags & IFF_PROMISC)
1338*19aa95e4SMarcin Wojtas 		reg = ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0);
1339*19aa95e4SMarcin Wojtas 	else if (flags & IFF_ALLMULTI)
1340*19aa95e4SMarcin Wojtas 		reg = ENETC_PSIPMR_SET_MP(0);
1341*19aa95e4SMarcin Wojtas 
1342*19aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIPMR, reg);
1343*19aa95e4SMarcin Wojtas 
1344*19aa95e4SMarcin Wojtas 	return (0);
1345*19aa95e4SMarcin Wojtas }
1346*19aa95e4SMarcin Wojtas 
1347*19aa95e4SMarcin Wojtas static void
1348*19aa95e4SMarcin Wojtas enetc_timer(if_ctx_t ctx, uint16_t qid)
1349*19aa95e4SMarcin Wojtas {
1350*19aa95e4SMarcin Wojtas 	/*
1351*19aa95e4SMarcin Wojtas 	 * Poll PHY status. Do this only for qid 0 to save
1352*19aa95e4SMarcin Wojtas 	 * some cycles.
1353*19aa95e4SMarcin Wojtas 	 */
1354*19aa95e4SMarcin Wojtas 	if (qid == 0)
1355*19aa95e4SMarcin Wojtas 		iflib_admin_intr_deferred(ctx);
1356*19aa95e4SMarcin Wojtas }
1357*19aa95e4SMarcin Wojtas 
1358*19aa95e4SMarcin Wojtas static void
1359*19aa95e4SMarcin Wojtas enetc_update_admin_status(if_ctx_t ctx)
1360*19aa95e4SMarcin Wojtas {
1361*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1362*19aa95e4SMarcin Wojtas 	struct mii_data *miid;
1363*19aa95e4SMarcin Wojtas 
1364*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
1365*19aa95e4SMarcin Wojtas 
1366*19aa95e4SMarcin Wojtas 	if (!sc->fixed_link) {
1367*19aa95e4SMarcin Wojtas 		miid = device_get_softc(sc->miibus);
1368*19aa95e4SMarcin Wojtas 		mii_tick(miid);
1369*19aa95e4SMarcin Wojtas 	}
1370*19aa95e4SMarcin Wojtas }
1371*19aa95e4SMarcin Wojtas 
1372*19aa95e4SMarcin Wojtas static int
1373*19aa95e4SMarcin Wojtas enetc_miibus_readreg(device_t dev, int phy, int reg)
1374*19aa95e4SMarcin Wojtas {
1375*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1376*19aa95e4SMarcin Wojtas 
1377*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(device_get_softc(dev));
1378*19aa95e4SMarcin Wojtas 	return (enetc_mdio_read(sc->regs, ENETC_PORT_BASE + ENETC_EMDIO_BASE,
1379*19aa95e4SMarcin Wojtas 	    phy, reg));
1380*19aa95e4SMarcin Wojtas }
1381*19aa95e4SMarcin Wojtas 
1382*19aa95e4SMarcin Wojtas static int
1383*19aa95e4SMarcin Wojtas enetc_miibus_writereg(device_t dev, int phy, int reg, int data)
1384*19aa95e4SMarcin Wojtas {
1385*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1386*19aa95e4SMarcin Wojtas 
1387*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(device_get_softc(dev));
1388*19aa95e4SMarcin Wojtas 	return (enetc_mdio_write(sc->regs, ENETC_PORT_BASE + ENETC_EMDIO_BASE,
1389*19aa95e4SMarcin Wojtas 	    phy, reg, data));
1390*19aa95e4SMarcin Wojtas }
1391*19aa95e4SMarcin Wojtas 
1392*19aa95e4SMarcin Wojtas static void
1393*19aa95e4SMarcin Wojtas enetc_miibus_linkchg(device_t dev)
1394*19aa95e4SMarcin Wojtas {
1395*19aa95e4SMarcin Wojtas 
1396*19aa95e4SMarcin Wojtas 	enetc_miibus_statchg(dev);
1397*19aa95e4SMarcin Wojtas }
1398*19aa95e4SMarcin Wojtas 
1399*19aa95e4SMarcin Wojtas static void
1400*19aa95e4SMarcin Wojtas enetc_miibus_statchg(device_t dev)
1401*19aa95e4SMarcin Wojtas {
1402*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1403*19aa95e4SMarcin Wojtas 	struct mii_data *miid;
1404*19aa95e4SMarcin Wojtas 	int link_state, baudrate;
1405*19aa95e4SMarcin Wojtas 
1406*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(device_get_softc(dev));
1407*19aa95e4SMarcin Wojtas 	miid = device_get_softc(sc->miibus);
1408*19aa95e4SMarcin Wojtas 
1409*19aa95e4SMarcin Wojtas 	baudrate = ifmedia_baudrate(miid->mii_media_active);
1410*19aa95e4SMarcin Wojtas 	if (miid->mii_media_status & IFM_AVALID) {
1411*19aa95e4SMarcin Wojtas 		if (miid->mii_media_status & IFM_ACTIVE)
1412*19aa95e4SMarcin Wojtas 			link_state = LINK_STATE_UP;
1413*19aa95e4SMarcin Wojtas 		else
1414*19aa95e4SMarcin Wojtas 			link_state = LINK_STATE_DOWN;
1415*19aa95e4SMarcin Wojtas 	} else {
1416*19aa95e4SMarcin Wojtas 		link_state = LINK_STATE_UNKNOWN;
1417*19aa95e4SMarcin Wojtas 	}
1418*19aa95e4SMarcin Wojtas 
1419*19aa95e4SMarcin Wojtas 	iflib_link_state_change(sc->ctx, link_state, baudrate);
1420*19aa95e4SMarcin Wojtas 
1421*19aa95e4SMarcin Wojtas }
1422*19aa95e4SMarcin Wojtas 
1423*19aa95e4SMarcin Wojtas static int
1424*19aa95e4SMarcin Wojtas enetc_media_change(if_t ifp)
1425*19aa95e4SMarcin Wojtas {
1426*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1427*19aa95e4SMarcin Wojtas 	struct mii_data *miid;
1428*19aa95e4SMarcin Wojtas 
1429*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ifp->if_softc);
1430*19aa95e4SMarcin Wojtas 	miid = device_get_softc(sc->miibus);
1431*19aa95e4SMarcin Wojtas 
1432*19aa95e4SMarcin Wojtas 	mii_mediachg(miid);
1433*19aa95e4SMarcin Wojtas 	return (0);
1434*19aa95e4SMarcin Wojtas }
1435*19aa95e4SMarcin Wojtas 
1436*19aa95e4SMarcin Wojtas static void
1437*19aa95e4SMarcin Wojtas enetc_media_status(if_t ifp, struct ifmediareq* ifmr)
1438*19aa95e4SMarcin Wojtas {
1439*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1440*19aa95e4SMarcin Wojtas 	struct mii_data *miid;
1441*19aa95e4SMarcin Wojtas 
1442*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ifp->if_softc);
1443*19aa95e4SMarcin Wojtas 	miid = device_get_softc(sc->miibus);
1444*19aa95e4SMarcin Wojtas 
1445*19aa95e4SMarcin Wojtas 	mii_pollstat(miid);
1446*19aa95e4SMarcin Wojtas 
1447*19aa95e4SMarcin Wojtas 	ifmr->ifm_active = miid->mii_media_active;
1448*19aa95e4SMarcin Wojtas 	ifmr->ifm_status = miid->mii_media_status;
1449*19aa95e4SMarcin Wojtas }
1450*19aa95e4SMarcin Wojtas 
1451*19aa95e4SMarcin Wojtas static int
1452*19aa95e4SMarcin Wojtas enetc_fixed_media_change(if_t ifp)
1453*19aa95e4SMarcin Wojtas {
1454*19aa95e4SMarcin Wojtas 
1455*19aa95e4SMarcin Wojtas 	if_printf(ifp, "Can't change media in fixed-link mode.\n");
1456*19aa95e4SMarcin Wojtas 	return (0);
1457*19aa95e4SMarcin Wojtas }
1458*19aa95e4SMarcin Wojtas static void
1459*19aa95e4SMarcin Wojtas enetc_fixed_media_status(if_t ifp, struct ifmediareq* ifmr)
1460*19aa95e4SMarcin Wojtas {
1461*19aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
1462*19aa95e4SMarcin Wojtas 
1463*19aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ifp->if_softc);
1464*19aa95e4SMarcin Wojtas 
1465*19aa95e4SMarcin Wojtas 	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
1466*19aa95e4SMarcin Wojtas 	ifmr->ifm_active = sc->fixed_ifmedia.ifm_cur->ifm_media;
1467*19aa95e4SMarcin Wojtas 	return;
1468*19aa95e4SMarcin Wojtas }
1469