xref: /freebsd/sys/dev/enetc/if_enetc.c (revision 5ad6d28cbe6b3ff85e49607a7e04cb68db3ed6df)
119aa95e4SMarcin Wojtas /*-
219aa95e4SMarcin Wojtas  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
319aa95e4SMarcin Wojtas  *
419aa95e4SMarcin Wojtas  * Copyright (c) 2021 Alstom Group.
519aa95e4SMarcin Wojtas  * Copyright (c) 2021 Semihalf.
619aa95e4SMarcin Wojtas  *
719aa95e4SMarcin Wojtas  * Redistribution and use in source and binary forms, with or without
819aa95e4SMarcin Wojtas  * modification, are permitted provided that the following conditions
919aa95e4SMarcin Wojtas  * are met:
1019aa95e4SMarcin Wojtas  * 1. Redistributions of source code must retain the above copyright
1119aa95e4SMarcin Wojtas  *    notice, this list of conditions and the following disclaimer.
1219aa95e4SMarcin Wojtas  * 2. Redistributions in binary form must reproduce the above copyright
1319aa95e4SMarcin Wojtas  *    notice, this list of conditions and the following disclaimer in the
1419aa95e4SMarcin Wojtas  *    documentation and/or other materials provided with the distribution.
1519aa95e4SMarcin Wojtas  *
1619aa95e4SMarcin Wojtas  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1719aa95e4SMarcin Wojtas  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1819aa95e4SMarcin Wojtas  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1919aa95e4SMarcin Wojtas  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2019aa95e4SMarcin Wojtas  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2119aa95e4SMarcin Wojtas  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2219aa95e4SMarcin Wojtas  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2319aa95e4SMarcin Wojtas  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2419aa95e4SMarcin Wojtas  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2519aa95e4SMarcin Wojtas  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2619aa95e4SMarcin Wojtas  */
2719aa95e4SMarcin Wojtas 
2819aa95e4SMarcin Wojtas #include <sys/cdefs.h>
2919aa95e4SMarcin Wojtas __FBSDID("$FreeBSD$");
3019aa95e4SMarcin Wojtas 
3119aa95e4SMarcin Wojtas #include <sys/param.h>
3219aa95e4SMarcin Wojtas #include <sys/bus.h>
3319aa95e4SMarcin Wojtas #include <sys/endian.h>
3419aa95e4SMarcin Wojtas #include <sys/kernel.h>
3519aa95e4SMarcin Wojtas #include <sys/module.h>
3619aa95e4SMarcin Wojtas #include <sys/rman.h>
3719aa95e4SMarcin Wojtas #include <sys/socket.h>
3819aa95e4SMarcin Wojtas #include <sys/sockio.h>
3919aa95e4SMarcin Wojtas 
4019aa95e4SMarcin Wojtas #include <machine/bus.h>
4119aa95e4SMarcin Wojtas #include <machine/resource.h>
4219aa95e4SMarcin Wojtas 
4319aa95e4SMarcin Wojtas #include <net/ethernet.h>
4419aa95e4SMarcin Wojtas #include <net/if.h>
4519aa95e4SMarcin Wojtas #include <net/if_dl.h>
4619aa95e4SMarcin Wojtas #include <net/if_var.h>
4719aa95e4SMarcin Wojtas #include <net/if_types.h>
4819aa95e4SMarcin Wojtas #include <net/if_media.h>
4919aa95e4SMarcin Wojtas #include <net/iflib.h>
5019aa95e4SMarcin Wojtas 
5119aa95e4SMarcin Wojtas #include <dev/enetc/enetc_hw.h>
5219aa95e4SMarcin Wojtas #include <dev/enetc/enetc.h>
5319aa95e4SMarcin Wojtas #include <dev/enetc/enetc_mdio.h>
5419aa95e4SMarcin Wojtas #include <dev/mii/mii.h>
5519aa95e4SMarcin Wojtas #include <dev/mii/miivar.h>
5619aa95e4SMarcin Wojtas #include <dev/pci/pcireg.h>
5719aa95e4SMarcin Wojtas #include <dev/pci/pcivar.h>
5819aa95e4SMarcin Wojtas 
5919aa95e4SMarcin Wojtas #include <dev/ofw/ofw_bus.h>
6019aa95e4SMarcin Wojtas #include <dev/ofw/ofw_bus_subr.h>
6119aa95e4SMarcin Wojtas 
6219aa95e4SMarcin Wojtas #include "ifdi_if.h"
6319aa95e4SMarcin Wojtas #include "miibus_if.h"
6419aa95e4SMarcin Wojtas 
6519aa95e4SMarcin Wojtas static device_register_t		enetc_register;
6619aa95e4SMarcin Wojtas 
6719aa95e4SMarcin Wojtas static ifdi_attach_pre_t		enetc_attach_pre;
6819aa95e4SMarcin Wojtas static ifdi_attach_post_t		enetc_attach_post;
6919aa95e4SMarcin Wojtas static ifdi_detach_t			enetc_detach;
7019aa95e4SMarcin Wojtas 
7119aa95e4SMarcin Wojtas static ifdi_tx_queues_alloc_t		enetc_tx_queues_alloc;
7219aa95e4SMarcin Wojtas static ifdi_rx_queues_alloc_t		enetc_rx_queues_alloc;
7319aa95e4SMarcin Wojtas static ifdi_queues_free_t		enetc_queues_free;
7419aa95e4SMarcin Wojtas 
7519aa95e4SMarcin Wojtas static ifdi_init_t			enetc_init;
7619aa95e4SMarcin Wojtas static ifdi_stop_t			enetc_stop;
7719aa95e4SMarcin Wojtas 
7819aa95e4SMarcin Wojtas static ifdi_msix_intr_assign_t		enetc_msix_intr_assign;
7919aa95e4SMarcin Wojtas static ifdi_tx_queue_intr_enable_t	enetc_tx_queue_intr_enable;
8019aa95e4SMarcin Wojtas static ifdi_rx_queue_intr_enable_t	enetc_rx_queue_intr_enable;
8119aa95e4SMarcin Wojtas static ifdi_intr_enable_t		enetc_intr_enable;
8219aa95e4SMarcin Wojtas static ifdi_intr_disable_t		enetc_intr_disable;
8319aa95e4SMarcin Wojtas 
8419aa95e4SMarcin Wojtas static int	enetc_isc_txd_encap(void*, if_pkt_info_t);
8519aa95e4SMarcin Wojtas static void	enetc_isc_txd_flush(void*, uint16_t, qidx_t);
8619aa95e4SMarcin Wojtas static int	enetc_isc_txd_credits_update(void*, uint16_t, bool);
8719aa95e4SMarcin Wojtas static int	enetc_isc_rxd_available(void*, uint16_t, qidx_t, qidx_t);
8819aa95e4SMarcin Wojtas static int	enetc_isc_rxd_pkt_get(void*, if_rxd_info_t);
8919aa95e4SMarcin Wojtas static void	enetc_isc_rxd_refill(void*, if_rxd_update_t);
9019aa95e4SMarcin Wojtas static void	enetc_isc_rxd_flush(void*, uint16_t, uint8_t, qidx_t);
9119aa95e4SMarcin Wojtas 
9219aa95e4SMarcin Wojtas static void	enetc_vlan_register(if_ctx_t, uint16_t);
9319aa95e4SMarcin Wojtas static void	enetc_vlan_unregister(if_ctx_t, uint16_t);
9419aa95e4SMarcin Wojtas 
9519aa95e4SMarcin Wojtas static uint64_t	enetc_get_counter(if_ctx_t, ift_counter);
9619aa95e4SMarcin Wojtas static int	enetc_promisc_set(if_ctx_t, int);
9719aa95e4SMarcin Wojtas static int	enetc_mtu_set(if_ctx_t, uint32_t);
9819aa95e4SMarcin Wojtas static void	enetc_setup_multicast(if_ctx_t);
9919aa95e4SMarcin Wojtas static void	enetc_timer(if_ctx_t, uint16_t);
10019aa95e4SMarcin Wojtas static void	enetc_update_admin_status(if_ctx_t);
10119aa95e4SMarcin Wojtas 
10219aa95e4SMarcin Wojtas static miibus_readreg_t		enetc_miibus_readreg;
10319aa95e4SMarcin Wojtas static miibus_writereg_t	enetc_miibus_writereg;
10419aa95e4SMarcin Wojtas static miibus_linkchg_t		enetc_miibus_linkchg;
10519aa95e4SMarcin Wojtas static miibus_statchg_t		enetc_miibus_statchg;
10619aa95e4SMarcin Wojtas 
10719aa95e4SMarcin Wojtas static int			enetc_media_change(if_t);
10819aa95e4SMarcin Wojtas static void			enetc_media_status(if_t, struct ifmediareq*);
10919aa95e4SMarcin Wojtas 
11019aa95e4SMarcin Wojtas static int			enetc_fixed_media_change(if_t);
11119aa95e4SMarcin Wojtas static void			enetc_fixed_media_status(if_t, struct ifmediareq*);
11219aa95e4SMarcin Wojtas 
11319aa95e4SMarcin Wojtas static void			enetc_max_nqueues(struct enetc_softc*, int*, int*);
11419aa95e4SMarcin Wojtas static int			enetc_setup_phy(struct enetc_softc*);
11519aa95e4SMarcin Wojtas 
11619aa95e4SMarcin Wojtas static void			enetc_get_hwaddr(struct enetc_softc*);
11719aa95e4SMarcin Wojtas static void			enetc_set_hwaddr(struct enetc_softc*);
11819aa95e4SMarcin Wojtas static int			enetc_setup_rss(struct enetc_softc*);
11919aa95e4SMarcin Wojtas 
12019aa95e4SMarcin Wojtas static void			enetc_init_hw(struct enetc_softc*);
12119aa95e4SMarcin Wojtas static void			enetc_init_ctrl(struct enetc_softc*);
12219aa95e4SMarcin Wojtas static void			enetc_init_tx(struct enetc_softc*);
12319aa95e4SMarcin Wojtas static void			enetc_init_rx(struct enetc_softc*);
12419aa95e4SMarcin Wojtas 
12519aa95e4SMarcin Wojtas static int			enetc_ctrl_send(struct enetc_softc*,
12619aa95e4SMarcin Wojtas 				    uint16_t, uint16_t, iflib_dma_info_t);
12719aa95e4SMarcin Wojtas 
12819aa95e4SMarcin Wojtas static const char enetc_driver_version[] = "1.0.0";
12919aa95e4SMarcin Wojtas 
13019aa95e4SMarcin Wojtas static pci_vendor_info_t enetc_vendor_info_array[] = {
13119aa95e4SMarcin Wojtas 	PVID(PCI_VENDOR_FREESCALE, ENETC_DEV_ID_PF,
13219aa95e4SMarcin Wojtas 	    "Freescale ENETC PCIe Gigabit Ethernet Controller"),
13319aa95e4SMarcin Wojtas 	PVID_END
13419aa95e4SMarcin Wojtas };
13519aa95e4SMarcin Wojtas 
13619aa95e4SMarcin Wojtas #define ENETC_IFCAPS (IFCAP_VLAN_MTU | IFCAP_RXCSUM | IFCAP_JUMBO_MTU | \
13719aa95e4SMarcin Wojtas 	IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWFILTER)
13819aa95e4SMarcin Wojtas 
13919aa95e4SMarcin Wojtas static device_method_t enetc_methods[] = {
14019aa95e4SMarcin Wojtas 	DEVMETHOD(device_register,	enetc_register),
14119aa95e4SMarcin Wojtas 	DEVMETHOD(device_probe,		iflib_device_probe),
14219aa95e4SMarcin Wojtas 	DEVMETHOD(device_attach,	iflib_device_attach),
14319aa95e4SMarcin Wojtas 	DEVMETHOD(device_detach,	iflib_device_detach),
14419aa95e4SMarcin Wojtas 	DEVMETHOD(device_shutdown,	iflib_device_shutdown),
14519aa95e4SMarcin Wojtas 	DEVMETHOD(device_suspend,	iflib_device_suspend),
14619aa95e4SMarcin Wojtas 	DEVMETHOD(device_resume,	iflib_device_resume),
14719aa95e4SMarcin Wojtas 
14819aa95e4SMarcin Wojtas 	DEVMETHOD(miibus_readreg,	enetc_miibus_readreg),
14919aa95e4SMarcin Wojtas 	DEVMETHOD(miibus_writereg,	enetc_miibus_writereg),
15019aa95e4SMarcin Wojtas 	DEVMETHOD(miibus_linkchg,	enetc_miibus_linkchg),
15119aa95e4SMarcin Wojtas 	DEVMETHOD(miibus_statchg,	enetc_miibus_statchg),
15219aa95e4SMarcin Wojtas 
15319aa95e4SMarcin Wojtas 	DEVMETHOD_END
15419aa95e4SMarcin Wojtas };
15519aa95e4SMarcin Wojtas 
15619aa95e4SMarcin Wojtas static driver_t enetc_driver = {
15719aa95e4SMarcin Wojtas 	"enetc", enetc_methods, sizeof(struct enetc_softc)
15819aa95e4SMarcin Wojtas };
15919aa95e4SMarcin Wojtas 
16019aa95e4SMarcin Wojtas static devclass_t enetc_devclass;
16119aa95e4SMarcin Wojtas DRIVER_MODULE(miibus, enetc, miibus_driver, miibus_devclass, NULL, NULL);
162*5ad6d28cSKornel Duleba DRIVER_MODULE(enetc, pci, enetc_driver, enetc_devclass, NULL, NULL);
16319aa95e4SMarcin Wojtas MODULE_VERSION(enetc, 1);
16419aa95e4SMarcin Wojtas 
16519aa95e4SMarcin Wojtas IFLIB_PNP_INFO(pci, enetc, enetc_vendor_info_array);
16619aa95e4SMarcin Wojtas 
16719aa95e4SMarcin Wojtas MODULE_DEPEND(enetc, ether, 1, 1, 1);
16819aa95e4SMarcin Wojtas MODULE_DEPEND(enetc, iflib, 1, 1, 1);
16919aa95e4SMarcin Wojtas MODULE_DEPEND(enetc, miibus, 1, 1, 1);
17019aa95e4SMarcin Wojtas 
17119aa95e4SMarcin Wojtas static device_method_t enetc_iflib_methods[] = {
17219aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_attach_pre,		enetc_attach_pre),
17319aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_attach_post,		enetc_attach_post),
17419aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_detach,			enetc_detach),
17519aa95e4SMarcin Wojtas 
17619aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_init,			enetc_init),
17719aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_stop,			enetc_stop),
17819aa95e4SMarcin Wojtas 
17919aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_tx_queues_alloc,		enetc_tx_queues_alloc),
18019aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_rx_queues_alloc,		enetc_rx_queues_alloc),
18119aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_queues_free,		enetc_queues_free),
18219aa95e4SMarcin Wojtas 
18319aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_msix_intr_assign,	enetc_msix_intr_assign),
18419aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_tx_queue_intr_enable,	enetc_tx_queue_intr_enable),
18519aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_rx_queue_intr_enable,	enetc_rx_queue_intr_enable),
18619aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_intr_enable,		enetc_intr_enable),
18719aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_intr_disable,		enetc_intr_disable),
18819aa95e4SMarcin Wojtas 
18919aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_vlan_register,		enetc_vlan_register),
19019aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_vlan_unregister,		enetc_vlan_unregister),
19119aa95e4SMarcin Wojtas 
19219aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_get_counter,		enetc_get_counter),
19319aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_mtu_set,			enetc_mtu_set),
19419aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_multi_set,		enetc_setup_multicast),
19519aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_promisc_set,		enetc_promisc_set),
19619aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_timer,			enetc_timer),
19719aa95e4SMarcin Wojtas 	DEVMETHOD(ifdi_update_admin_status,	enetc_update_admin_status),
19819aa95e4SMarcin Wojtas 
19919aa95e4SMarcin Wojtas 	DEVMETHOD_END
20019aa95e4SMarcin Wojtas };
20119aa95e4SMarcin Wojtas 
20219aa95e4SMarcin Wojtas static driver_t enetc_iflib_driver = {
20319aa95e4SMarcin Wojtas 	"enetc", enetc_iflib_methods, sizeof(struct enetc_softc)
20419aa95e4SMarcin Wojtas };
20519aa95e4SMarcin Wojtas 
20619aa95e4SMarcin Wojtas static struct if_txrx enetc_txrx = {
20719aa95e4SMarcin Wojtas 	.ift_txd_encap = enetc_isc_txd_encap,
20819aa95e4SMarcin Wojtas 	.ift_txd_flush = enetc_isc_txd_flush,
20919aa95e4SMarcin Wojtas 	.ift_txd_credits_update = enetc_isc_txd_credits_update,
21019aa95e4SMarcin Wojtas 	.ift_rxd_available = enetc_isc_rxd_available,
21119aa95e4SMarcin Wojtas 	.ift_rxd_pkt_get = enetc_isc_rxd_pkt_get,
21219aa95e4SMarcin Wojtas 	.ift_rxd_refill = enetc_isc_rxd_refill,
21319aa95e4SMarcin Wojtas 	.ift_rxd_flush = enetc_isc_rxd_flush
21419aa95e4SMarcin Wojtas };
21519aa95e4SMarcin Wojtas 
21619aa95e4SMarcin Wojtas static struct if_shared_ctx enetc_sctx_init = {
21719aa95e4SMarcin Wojtas 	.isc_magic = IFLIB_MAGIC,
21819aa95e4SMarcin Wojtas 
21919aa95e4SMarcin Wojtas 	.isc_q_align = ENETC_RING_ALIGN,
22019aa95e4SMarcin Wojtas 
22119aa95e4SMarcin Wojtas 	.isc_tx_maxsize = ENETC_MAX_FRAME_LEN,
22219aa95e4SMarcin Wojtas 	.isc_tx_maxsegsize = PAGE_SIZE,
22319aa95e4SMarcin Wojtas 
22419aa95e4SMarcin Wojtas 	.isc_rx_maxsize = ENETC_MAX_FRAME_LEN,
22519aa95e4SMarcin Wojtas 	.isc_rx_maxsegsize = ENETC_MAX_FRAME_LEN,
22619aa95e4SMarcin Wojtas 	.isc_rx_nsegments = ENETC_MAX_SCATTER,
22719aa95e4SMarcin Wojtas 
22819aa95e4SMarcin Wojtas 	.isc_admin_intrcnt = 0,
22919aa95e4SMarcin Wojtas 
23019aa95e4SMarcin Wojtas 	.isc_nfl = 1,
23119aa95e4SMarcin Wojtas 	.isc_nrxqs = 1,
23219aa95e4SMarcin Wojtas 	.isc_ntxqs = 1,
23319aa95e4SMarcin Wojtas 
23419aa95e4SMarcin Wojtas 	.isc_vendor_info = enetc_vendor_info_array,
23519aa95e4SMarcin Wojtas 	.isc_driver_version = enetc_driver_version,
23619aa95e4SMarcin Wojtas 	.isc_driver = &enetc_iflib_driver,
23719aa95e4SMarcin Wojtas 
23819aa95e4SMarcin Wojtas 	.isc_flags = IFLIB_DRIVER_MEDIA | IFLIB_PRESERVE_TX_INDICES,
23919aa95e4SMarcin Wojtas 	.isc_ntxd_min = {ENETC_MIN_DESC},
24019aa95e4SMarcin Wojtas 	.isc_ntxd_max = {ENETC_MAX_DESC},
24119aa95e4SMarcin Wojtas 	.isc_ntxd_default = {ENETC_DEFAULT_DESC},
24219aa95e4SMarcin Wojtas 	.isc_nrxd_min = {ENETC_MIN_DESC},
24319aa95e4SMarcin Wojtas 	.isc_nrxd_max = {ENETC_MAX_DESC},
24419aa95e4SMarcin Wojtas 	.isc_nrxd_default = {ENETC_DEFAULT_DESC}
24519aa95e4SMarcin Wojtas };
24619aa95e4SMarcin Wojtas 
24719aa95e4SMarcin Wojtas static void*
24819aa95e4SMarcin Wojtas enetc_register(device_t dev)
24919aa95e4SMarcin Wojtas {
25019aa95e4SMarcin Wojtas 
25119aa95e4SMarcin Wojtas 	if (!ofw_bus_status_okay(dev))
25219aa95e4SMarcin Wojtas 		return (NULL);
25319aa95e4SMarcin Wojtas 
25419aa95e4SMarcin Wojtas 	return (&enetc_sctx_init);
25519aa95e4SMarcin Wojtas }
25619aa95e4SMarcin Wojtas 
25719aa95e4SMarcin Wojtas static void
25819aa95e4SMarcin Wojtas enetc_max_nqueues(struct enetc_softc *sc, int *max_tx_nqueues,
25919aa95e4SMarcin Wojtas     int *max_rx_nqueues)
26019aa95e4SMarcin Wojtas {
26119aa95e4SMarcin Wojtas 	uint32_t val;
26219aa95e4SMarcin Wojtas 
26319aa95e4SMarcin Wojtas 	val = ENETC_PORT_RD4(sc, ENETC_PCAPR0);
26419aa95e4SMarcin Wojtas 	*max_tx_nqueues = MIN(ENETC_PCAPR0_TXBDR(val), ENETC_MAX_QUEUES);
26519aa95e4SMarcin Wojtas 	*max_rx_nqueues = MIN(ENETC_PCAPR0_RXBDR(val), ENETC_MAX_QUEUES);
26619aa95e4SMarcin Wojtas }
26719aa95e4SMarcin Wojtas 
26819aa95e4SMarcin Wojtas static int
26919aa95e4SMarcin Wojtas enetc_setup_fixed(struct enetc_softc *sc, phandle_t node)
27019aa95e4SMarcin Wojtas {
27119aa95e4SMarcin Wojtas 	ssize_t size;
27219aa95e4SMarcin Wojtas 	int speed;
27319aa95e4SMarcin Wojtas 
27419aa95e4SMarcin Wojtas 	size = OF_getencprop(node, "speed", &speed, sizeof(speed));
27519aa95e4SMarcin Wojtas 	if (size <= 0) {
27619aa95e4SMarcin Wojtas 		device_printf(sc->dev,
27719aa95e4SMarcin Wojtas 		    "Device has fixed-link node without link speed specified\n");
27819aa95e4SMarcin Wojtas 		return (ENXIO);
27919aa95e4SMarcin Wojtas 	}
28019aa95e4SMarcin Wojtas 	switch (speed) {
28119aa95e4SMarcin Wojtas 	case 10:
28219aa95e4SMarcin Wojtas 		speed = IFM_10_T;
28319aa95e4SMarcin Wojtas 		break;
28419aa95e4SMarcin Wojtas 	case 100:
28519aa95e4SMarcin Wojtas 		speed = IFM_100_TX;
28619aa95e4SMarcin Wojtas 		break;
28719aa95e4SMarcin Wojtas 	case 1000:
28819aa95e4SMarcin Wojtas 		speed = IFM_1000_T;
28919aa95e4SMarcin Wojtas 		break;
290382376f3SWojciech Macek 	case 2500:
291382376f3SWojciech Macek 		speed = IFM_2500_T;
292382376f3SWojciech Macek 		break;
29319aa95e4SMarcin Wojtas 	default:
29419aa95e4SMarcin Wojtas 		device_printf(sc->dev, "Unsupported link speed value of %d\n",
29519aa95e4SMarcin Wojtas 		    speed);
29619aa95e4SMarcin Wojtas 		return (ENXIO);
29719aa95e4SMarcin Wojtas 	}
29819aa95e4SMarcin Wojtas 	speed |= IFM_ETHER;
29919aa95e4SMarcin Wojtas 
30019aa95e4SMarcin Wojtas 	if (OF_hasprop(node, "full-duplex"))
30119aa95e4SMarcin Wojtas 		speed |= IFM_FDX;
30219aa95e4SMarcin Wojtas 	else
30319aa95e4SMarcin Wojtas 		speed |= IFM_HDX;
30419aa95e4SMarcin Wojtas 
30519aa95e4SMarcin Wojtas 	sc->fixed_link = true;
30619aa95e4SMarcin Wojtas 
30719aa95e4SMarcin Wojtas 	ifmedia_init(&sc->fixed_ifmedia, 0, enetc_fixed_media_change,
30819aa95e4SMarcin Wojtas 	    enetc_fixed_media_status);
30919aa95e4SMarcin Wojtas 	ifmedia_add(&sc->fixed_ifmedia, speed, 0, NULL);
31019aa95e4SMarcin Wojtas 	ifmedia_set(&sc->fixed_ifmedia, speed);
31119aa95e4SMarcin Wojtas 	sc->shared->isc_media = &sc->fixed_ifmedia;
31219aa95e4SMarcin Wojtas 
31319aa95e4SMarcin Wojtas 	return (0);
31419aa95e4SMarcin Wojtas }
31519aa95e4SMarcin Wojtas 
31619aa95e4SMarcin Wojtas static int
31719aa95e4SMarcin Wojtas enetc_setup_phy(struct enetc_softc *sc)
31819aa95e4SMarcin Wojtas {
31919aa95e4SMarcin Wojtas 	phandle_t node, fixed_link, phy_handle;
32019aa95e4SMarcin Wojtas 	struct mii_data *miid;
32119aa95e4SMarcin Wojtas 	int phy_addr, error;
32219aa95e4SMarcin Wojtas 	ssize_t size;
32319aa95e4SMarcin Wojtas 
32419aa95e4SMarcin Wojtas 	node = ofw_bus_get_node(sc->dev);
32519aa95e4SMarcin Wojtas 	fixed_link = ofw_bus_find_child(node, "fixed-link");
32619aa95e4SMarcin Wojtas 	if (fixed_link != 0)
32719aa95e4SMarcin Wojtas 		return (enetc_setup_fixed(sc, fixed_link));
32819aa95e4SMarcin Wojtas 
32919aa95e4SMarcin Wojtas 	size = OF_getencprop(node, "phy-handle", &phy_handle, sizeof(phy_handle));
33019aa95e4SMarcin Wojtas 	if (size <= 0) {
33119aa95e4SMarcin Wojtas 		device_printf(sc->dev,
33219aa95e4SMarcin Wojtas 		    "Failed to acquire PHY handle from FDT.\n");
33319aa95e4SMarcin Wojtas 		return (ENXIO);
33419aa95e4SMarcin Wojtas 	}
33519aa95e4SMarcin Wojtas 	phy_handle = OF_node_from_xref(phy_handle);
33619aa95e4SMarcin Wojtas 	size = OF_getencprop(phy_handle, "reg", &phy_addr, sizeof(phy_addr));
33719aa95e4SMarcin Wojtas 	if (size <= 0) {
33819aa95e4SMarcin Wojtas 		device_printf(sc->dev, "Failed to obtain PHY address\n");
33919aa95e4SMarcin Wojtas 		return (ENXIO);
34019aa95e4SMarcin Wojtas 	}
34119aa95e4SMarcin Wojtas 	error = mii_attach(sc->dev, &sc->miibus, iflib_get_ifp(sc->ctx),
34219aa95e4SMarcin Wojtas 	    enetc_media_change, enetc_media_status,
34319aa95e4SMarcin Wojtas 	    BMSR_DEFCAPMASK, phy_addr, MII_OFFSET_ANY, MIIF_DOPAUSE);
34419aa95e4SMarcin Wojtas 	if (error != 0) {
34519aa95e4SMarcin Wojtas 		device_printf(sc->dev, "mii_attach failed\n");
34619aa95e4SMarcin Wojtas 		return (error);
34719aa95e4SMarcin Wojtas 	}
34819aa95e4SMarcin Wojtas 	miid = device_get_softc(sc->miibus);
34919aa95e4SMarcin Wojtas 	sc->shared->isc_media = &miid->mii_media;
35019aa95e4SMarcin Wojtas 
35119aa95e4SMarcin Wojtas 	return (0);
35219aa95e4SMarcin Wojtas }
35319aa95e4SMarcin Wojtas 
35419aa95e4SMarcin Wojtas static int
35519aa95e4SMarcin Wojtas enetc_attach_pre(if_ctx_t ctx)
35619aa95e4SMarcin Wojtas {
35719aa95e4SMarcin Wojtas 	struct ifnet *ifp;
35819aa95e4SMarcin Wojtas 	if_softc_ctx_t scctx;
35919aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
36019aa95e4SMarcin Wojtas 	int error, rid;
36119aa95e4SMarcin Wojtas 
36219aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
36319aa95e4SMarcin Wojtas 	scctx = iflib_get_softc_ctx(ctx);
36419aa95e4SMarcin Wojtas 	sc->ctx = ctx;
36519aa95e4SMarcin Wojtas 	sc->dev = iflib_get_dev(ctx);
36619aa95e4SMarcin Wojtas 	sc->shared = scctx;
36719aa95e4SMarcin Wojtas 	ifp = iflib_get_ifp(ctx);
36819aa95e4SMarcin Wojtas 
369*5ad6d28cSKornel Duleba 	pci_save_state(sc->dev);
370*5ad6d28cSKornel Duleba 	pcie_flr(sc->dev, 1000, false);
371*5ad6d28cSKornel Duleba 	pci_restore_state(sc->dev);
372*5ad6d28cSKornel Duleba 
37319aa95e4SMarcin Wojtas 	rid = PCIR_BAR(ENETC_BAR_REGS);
37419aa95e4SMarcin Wojtas 	sc->regs = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
37519aa95e4SMarcin Wojtas 	if (sc->regs == NULL) {
37619aa95e4SMarcin Wojtas 		device_printf(sc->dev,
37719aa95e4SMarcin Wojtas 		    "Failed to allocate BAR %d\n", ENETC_BAR_REGS);
37819aa95e4SMarcin Wojtas 		return (ENXIO);
37919aa95e4SMarcin Wojtas 	}
38019aa95e4SMarcin Wojtas 
38119aa95e4SMarcin Wojtas 	error = iflib_dma_alloc_align(ctx,
38219aa95e4SMarcin Wojtas 	    ENETC_MIN_DESC * sizeof(struct enetc_cbd),
38319aa95e4SMarcin Wojtas 	    ENETC_RING_ALIGN,
38419aa95e4SMarcin Wojtas 	    &sc->ctrl_queue.dma,
38519aa95e4SMarcin Wojtas 	    0);
38619aa95e4SMarcin Wojtas 	if (error != 0) {
38719aa95e4SMarcin Wojtas 		device_printf(sc->dev, "Failed to allocate control ring\n");
38819aa95e4SMarcin Wojtas 		goto fail;
38919aa95e4SMarcin Wojtas 	}
39019aa95e4SMarcin Wojtas 	sc->ctrl_queue.ring = (struct enetc_cbd*)sc->ctrl_queue.dma.idi_vaddr;
39119aa95e4SMarcin Wojtas 
39219aa95e4SMarcin Wojtas 	scctx->isc_txrx = &enetc_txrx;
39319aa95e4SMarcin Wojtas 	scctx->isc_tx_nsegments = ENETC_MAX_SCATTER;
39419aa95e4SMarcin Wojtas 	enetc_max_nqueues(sc, &scctx->isc_nrxqsets_max, &scctx->isc_ntxqsets_max);
39519aa95e4SMarcin Wojtas 
39619aa95e4SMarcin Wojtas 	if (scctx->isc_ntxd[0] % ENETC_DESC_ALIGN != 0) {
39719aa95e4SMarcin Wojtas 		device_printf(sc->dev,
39819aa95e4SMarcin Wojtas 		    "The number of TX descriptors has to be a multiple of %d\n",
39919aa95e4SMarcin Wojtas 		    ENETC_DESC_ALIGN);
40019aa95e4SMarcin Wojtas 		error = EINVAL;
40119aa95e4SMarcin Wojtas 		goto fail;
40219aa95e4SMarcin Wojtas 	}
40319aa95e4SMarcin Wojtas 	if (scctx->isc_nrxd[0] % ENETC_DESC_ALIGN != 0) {
40419aa95e4SMarcin Wojtas 		device_printf(sc->dev,
40519aa95e4SMarcin Wojtas 		    "The number of RX descriptors has to be a multiple of %d\n",
40619aa95e4SMarcin Wojtas 		    ENETC_DESC_ALIGN);
40719aa95e4SMarcin Wojtas 		error = EINVAL;
40819aa95e4SMarcin Wojtas 		goto fail;
40919aa95e4SMarcin Wojtas 	}
41019aa95e4SMarcin Wojtas 	scctx->isc_txqsizes[0] = scctx->isc_ntxd[0] * sizeof(union enetc_tx_bd);
41119aa95e4SMarcin Wojtas 	scctx->isc_rxqsizes[0] = scctx->isc_nrxd[0] * sizeof(union enetc_rx_bd);
41219aa95e4SMarcin Wojtas 	scctx->isc_txd_size[0] = sizeof(union enetc_tx_bd);
41319aa95e4SMarcin Wojtas 	scctx->isc_rxd_size[0] = sizeof(union enetc_rx_bd);
41419aa95e4SMarcin Wojtas 	scctx->isc_tx_csum_flags = 0;
41519aa95e4SMarcin Wojtas 	scctx->isc_capabilities = scctx->isc_capenable = ENETC_IFCAPS;
41619aa95e4SMarcin Wojtas 
41719aa95e4SMarcin Wojtas 	error = enetc_mtu_set(ctx, ETHERMTU);
41819aa95e4SMarcin Wojtas 	if (error != 0)
41919aa95e4SMarcin Wojtas 		goto fail;
42019aa95e4SMarcin Wojtas 
42119aa95e4SMarcin Wojtas 	scctx->isc_msix_bar = pci_msix_table_bar(sc->dev);
42219aa95e4SMarcin Wojtas 
42319aa95e4SMarcin Wojtas 	error = enetc_setup_phy(sc);
42419aa95e4SMarcin Wojtas 	if (error != 0)
42519aa95e4SMarcin Wojtas 		goto fail;
42619aa95e4SMarcin Wojtas 
42719aa95e4SMarcin Wojtas 	enetc_get_hwaddr(sc);
42819aa95e4SMarcin Wojtas 
42919aa95e4SMarcin Wojtas 	return (0);
43019aa95e4SMarcin Wojtas fail:
43119aa95e4SMarcin Wojtas 	enetc_detach(ctx);
43219aa95e4SMarcin Wojtas 	return (error);
43319aa95e4SMarcin Wojtas }
43419aa95e4SMarcin Wojtas 
43519aa95e4SMarcin Wojtas static int
43619aa95e4SMarcin Wojtas enetc_attach_post(if_ctx_t ctx)
43719aa95e4SMarcin Wojtas {
43819aa95e4SMarcin Wojtas 
43919aa95e4SMarcin Wojtas 	enetc_init_hw(iflib_get_softc(ctx));
44019aa95e4SMarcin Wojtas 	return (0);
44119aa95e4SMarcin Wojtas }
44219aa95e4SMarcin Wojtas 
44319aa95e4SMarcin Wojtas static int
44419aa95e4SMarcin Wojtas enetc_detach(if_ctx_t ctx)
44519aa95e4SMarcin Wojtas {
44619aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
44719aa95e4SMarcin Wojtas 	int error = 0, i;
44819aa95e4SMarcin Wojtas 
44919aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
45019aa95e4SMarcin Wojtas 
45119aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++)
45219aa95e4SMarcin Wojtas 		iflib_irq_free(ctx, &sc->rx_queues[i].irq);
45319aa95e4SMarcin Wojtas 
45419aa95e4SMarcin Wojtas 	if (sc->miibus != NULL)
45519aa95e4SMarcin Wojtas 		device_delete_child(sc->dev, sc->miibus);
45619aa95e4SMarcin Wojtas 
45719aa95e4SMarcin Wojtas 	if (sc->regs != NULL)
45819aa95e4SMarcin Wojtas 		error = bus_release_resource(sc->dev, SYS_RES_MEMORY,
45919aa95e4SMarcin Wojtas 		    rman_get_rid(sc->regs), sc->regs);
46019aa95e4SMarcin Wojtas 
46119aa95e4SMarcin Wojtas 	if (sc->ctrl_queue.dma.idi_size != 0)
46219aa95e4SMarcin Wojtas 		iflib_dma_free(&sc->ctrl_queue.dma);
46319aa95e4SMarcin Wojtas 
46419aa95e4SMarcin Wojtas 	return (error);
46519aa95e4SMarcin Wojtas }
46619aa95e4SMarcin Wojtas 
46719aa95e4SMarcin Wojtas static int
46819aa95e4SMarcin Wojtas enetc_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
46919aa95e4SMarcin Wojtas     int ntxqs, int ntxqsets)
47019aa95e4SMarcin Wojtas {
47119aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
47219aa95e4SMarcin Wojtas 	struct enetc_tx_queue *queue;
47319aa95e4SMarcin Wojtas 	int i;
47419aa95e4SMarcin Wojtas 
47519aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
47619aa95e4SMarcin Wojtas 
47719aa95e4SMarcin Wojtas 	MPASS(ntxqs == 1);
47819aa95e4SMarcin Wojtas 
47919aa95e4SMarcin Wojtas 	sc->tx_queues = mallocarray(sc->tx_num_queues,
48019aa95e4SMarcin Wojtas 	    sizeof(struct enetc_tx_queue), M_DEVBUF, M_NOWAIT | M_ZERO);
48119aa95e4SMarcin Wojtas 	if (sc->tx_queues == NULL) {
48219aa95e4SMarcin Wojtas 		device_printf(sc->dev,
48319aa95e4SMarcin Wojtas 		    "Failed to allocate memory for TX queues.\n");
48419aa95e4SMarcin Wojtas 		return (ENOMEM);
48519aa95e4SMarcin Wojtas 	}
48619aa95e4SMarcin Wojtas 
48719aa95e4SMarcin Wojtas 	for (i = 0; i < sc->tx_num_queues; i++) {
48819aa95e4SMarcin Wojtas 		queue = &sc->tx_queues[i];
48919aa95e4SMarcin Wojtas 		queue->sc = sc;
49019aa95e4SMarcin Wojtas 		queue->ring = (union enetc_tx_bd*)(vaddrs[i]);
49119aa95e4SMarcin Wojtas 		queue->ring_paddr = paddrs[i];
49219aa95e4SMarcin Wojtas 		queue->next_to_clean = 0;
49319aa95e4SMarcin Wojtas 		queue->ring_full = false;
49419aa95e4SMarcin Wojtas 	}
49519aa95e4SMarcin Wojtas 
49619aa95e4SMarcin Wojtas 	return (0);
49719aa95e4SMarcin Wojtas }
49819aa95e4SMarcin Wojtas 
49919aa95e4SMarcin Wojtas static int
50019aa95e4SMarcin Wojtas enetc_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
50119aa95e4SMarcin Wojtas     int nrxqs, int nrxqsets)
50219aa95e4SMarcin Wojtas {
50319aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
50419aa95e4SMarcin Wojtas 	struct enetc_rx_queue *queue;
50519aa95e4SMarcin Wojtas 	int i;
50619aa95e4SMarcin Wojtas 
50719aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
50819aa95e4SMarcin Wojtas 	MPASS(nrxqs == 1);
50919aa95e4SMarcin Wojtas 
51019aa95e4SMarcin Wojtas 	sc->rx_queues = mallocarray(sc->rx_num_queues,
51119aa95e4SMarcin Wojtas 	    sizeof(struct enetc_rx_queue), M_DEVBUF, M_NOWAIT | M_ZERO);
51219aa95e4SMarcin Wojtas 	if (sc->rx_queues == NULL) {
51319aa95e4SMarcin Wojtas 		device_printf(sc->dev,
51419aa95e4SMarcin Wojtas 		    "Failed to allocate memory for RX queues.\n");
51519aa95e4SMarcin Wojtas 		return (ENOMEM);
51619aa95e4SMarcin Wojtas 	}
51719aa95e4SMarcin Wojtas 
51819aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++) {
51919aa95e4SMarcin Wojtas 		queue = &sc->rx_queues[i];
52019aa95e4SMarcin Wojtas 		queue->sc = sc;
52119aa95e4SMarcin Wojtas 		queue->qid = i;
52219aa95e4SMarcin Wojtas 		queue->ring = (union enetc_rx_bd*)(vaddrs[i]);
52319aa95e4SMarcin Wojtas 		queue->ring_paddr = paddrs[i];
52419aa95e4SMarcin Wojtas 	}
52519aa95e4SMarcin Wojtas 
52619aa95e4SMarcin Wojtas 	return (0);
52719aa95e4SMarcin Wojtas }
52819aa95e4SMarcin Wojtas 
52919aa95e4SMarcin Wojtas static void
53019aa95e4SMarcin Wojtas enetc_queues_free(if_ctx_t ctx)
53119aa95e4SMarcin Wojtas {
53219aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
53319aa95e4SMarcin Wojtas 
53419aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
53519aa95e4SMarcin Wojtas 
53619aa95e4SMarcin Wojtas 	if (sc->tx_queues != NULL) {
53719aa95e4SMarcin Wojtas 		free(sc->tx_queues, M_DEVBUF);
53819aa95e4SMarcin Wojtas 		sc->tx_queues = NULL;
53919aa95e4SMarcin Wojtas 	}
54019aa95e4SMarcin Wojtas 	if (sc->rx_queues != NULL) {
54119aa95e4SMarcin Wojtas 		free(sc->rx_queues, M_DEVBUF);
54219aa95e4SMarcin Wojtas 		sc->rx_queues = NULL;
54319aa95e4SMarcin Wojtas 	}
54419aa95e4SMarcin Wojtas }
54519aa95e4SMarcin Wojtas 
54619aa95e4SMarcin Wojtas static void
54719aa95e4SMarcin Wojtas enetc_get_hwaddr(struct enetc_softc *sc)
54819aa95e4SMarcin Wojtas {
54919aa95e4SMarcin Wojtas 	struct ether_addr hwaddr;
55019aa95e4SMarcin Wojtas 	uint16_t high;
55119aa95e4SMarcin Wojtas 	uint32_t low;
55219aa95e4SMarcin Wojtas 
55319aa95e4SMarcin Wojtas 	low = ENETC_PORT_RD4(sc, ENETC_PSIPMAR0(0));
55419aa95e4SMarcin Wojtas 	high = ENETC_PORT_RD2(sc, ENETC_PSIPMAR1(0));
55519aa95e4SMarcin Wojtas 
55619aa95e4SMarcin Wojtas 	memcpy(&hwaddr.octet[0], &low, 4);
55719aa95e4SMarcin Wojtas 	memcpy(&hwaddr.octet[4], &high, 2);
55819aa95e4SMarcin Wojtas 
55919aa95e4SMarcin Wojtas 	if (ETHER_IS_BROADCAST(hwaddr.octet) ||
56019aa95e4SMarcin Wojtas 	    ETHER_IS_MULTICAST(hwaddr.octet) ||
56119aa95e4SMarcin Wojtas 	    ETHER_IS_ZERO(hwaddr.octet)) {
56219aa95e4SMarcin Wojtas 		ether_gen_addr(iflib_get_ifp(sc->ctx), &hwaddr);
56319aa95e4SMarcin Wojtas 		device_printf(sc->dev,
56419aa95e4SMarcin Wojtas 		    "Failed to obtain MAC address, using a random one\n");
56519aa95e4SMarcin Wojtas 		memcpy(&low, &hwaddr.octet[0], 4);
56619aa95e4SMarcin Wojtas 		memcpy(&high, &hwaddr.octet[4], 2);
56719aa95e4SMarcin Wojtas 	}
56819aa95e4SMarcin Wojtas 
56919aa95e4SMarcin Wojtas 	iflib_set_mac(sc->ctx, hwaddr.octet);
57019aa95e4SMarcin Wojtas }
57119aa95e4SMarcin Wojtas 
57219aa95e4SMarcin Wojtas static void
57319aa95e4SMarcin Wojtas enetc_set_hwaddr(struct enetc_softc *sc)
57419aa95e4SMarcin Wojtas {
57519aa95e4SMarcin Wojtas 	struct ifnet *ifp;
57619aa95e4SMarcin Wojtas 	uint16_t high;
57719aa95e4SMarcin Wojtas 	uint32_t low;
57819aa95e4SMarcin Wojtas 	uint8_t *hwaddr;
57919aa95e4SMarcin Wojtas 
58019aa95e4SMarcin Wojtas 	ifp = iflib_get_ifp(sc->ctx);
58119aa95e4SMarcin Wojtas 	hwaddr = (uint8_t*)if_getlladdr(ifp);
58219aa95e4SMarcin Wojtas 	low = *((uint32_t*)hwaddr);
58319aa95e4SMarcin Wojtas 	high = *((uint16_t*)(hwaddr+4));
58419aa95e4SMarcin Wojtas 
58519aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIPMAR0(0), low);
58619aa95e4SMarcin Wojtas 	ENETC_PORT_WR2(sc, ENETC_PSIPMAR1(0), high);
58719aa95e4SMarcin Wojtas }
58819aa95e4SMarcin Wojtas 
58919aa95e4SMarcin Wojtas static int
59019aa95e4SMarcin Wojtas enetc_setup_rss(struct enetc_softc *sc)
59119aa95e4SMarcin Wojtas {
59219aa95e4SMarcin Wojtas 	struct iflib_dma_info dma;
59319aa95e4SMarcin Wojtas 	int error, i, buckets_num = 0;
59419aa95e4SMarcin Wojtas 	uint8_t *rss_table;
59519aa95e4SMarcin Wojtas 	uint32_t reg;
59619aa95e4SMarcin Wojtas 
59719aa95e4SMarcin Wojtas 	reg = ENETC_RD4(sc, ENETC_SIPCAPR0);
59819aa95e4SMarcin Wojtas 	if (reg & ENETC_SIPCAPR0_RSS) {
59919aa95e4SMarcin Wojtas 		reg = ENETC_RD4(sc, ENETC_SIRSSCAPR);
60019aa95e4SMarcin Wojtas 		buckets_num = ENETC_SIRSSCAPR_GET_NUM_RSS(reg);
60119aa95e4SMarcin Wojtas         }
60219aa95e4SMarcin Wojtas 	if (buckets_num == 0)
60319aa95e4SMarcin Wojtas 		return (ENOTSUP);
60419aa95e4SMarcin Wojtas 
60519aa95e4SMarcin Wojtas 	for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / sizeof(uint32_t); i++) {
60619aa95e4SMarcin Wojtas 		arc4rand((uint8_t *)&reg, sizeof(reg), 0);
60719aa95e4SMarcin Wojtas 		ENETC_PORT_WR4(sc, ENETC_PRSSK(i), reg);
60819aa95e4SMarcin Wojtas 	}
60919aa95e4SMarcin Wojtas 
61019aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SIRBGCR, sc->rx_num_queues);
61119aa95e4SMarcin Wojtas 
61219aa95e4SMarcin Wojtas 	error = iflib_dma_alloc_align(sc->ctx,
61319aa95e4SMarcin Wojtas 	    buckets_num * sizeof(*rss_table),
61419aa95e4SMarcin Wojtas 	    ENETC_RING_ALIGN,
61519aa95e4SMarcin Wojtas 	    &dma,
61619aa95e4SMarcin Wojtas 	    0);
61719aa95e4SMarcin Wojtas 	if (error != 0) {
61819aa95e4SMarcin Wojtas 		device_printf(sc->dev, "Failed to allocate DMA buffer for RSS\n");
61919aa95e4SMarcin Wojtas 		return (error);
62019aa95e4SMarcin Wojtas 	}
62119aa95e4SMarcin Wojtas 	rss_table = (uint8_t *)dma.idi_vaddr;
62219aa95e4SMarcin Wojtas 
62319aa95e4SMarcin Wojtas 	for (i = 0; i < buckets_num; i++)
62419aa95e4SMarcin Wojtas 		rss_table[i] = i % sc->rx_num_queues;
62519aa95e4SMarcin Wojtas 
62619aa95e4SMarcin Wojtas 	error = enetc_ctrl_send(sc, (BDCR_CMD_RSS << 8) | BDCR_CMD_RSS_WRITE,
62719aa95e4SMarcin Wojtas 	    buckets_num * sizeof(*rss_table), &dma);
62819aa95e4SMarcin Wojtas 	if (error != 0)
62919aa95e4SMarcin Wojtas 		device_printf(sc->dev, "Failed to setup RSS table\n");
63019aa95e4SMarcin Wojtas 
63119aa95e4SMarcin Wojtas 	iflib_dma_free(&dma);
63219aa95e4SMarcin Wojtas 
63319aa95e4SMarcin Wojtas 	return (error);
63419aa95e4SMarcin Wojtas }
63519aa95e4SMarcin Wojtas 
63619aa95e4SMarcin Wojtas static int
63719aa95e4SMarcin Wojtas enetc_ctrl_send(struct enetc_softc *sc, uint16_t cmd, uint16_t size,
63819aa95e4SMarcin Wojtas     iflib_dma_info_t dma)
63919aa95e4SMarcin Wojtas {
64019aa95e4SMarcin Wojtas 	struct enetc_ctrl_queue *queue;
64119aa95e4SMarcin Wojtas 	struct enetc_cbd *desc;
64219aa95e4SMarcin Wojtas 	int timeout = 1000;
64319aa95e4SMarcin Wojtas 
64419aa95e4SMarcin Wojtas 	queue = &sc->ctrl_queue;
64519aa95e4SMarcin Wojtas 	desc = &queue->ring[queue->pidx];
64619aa95e4SMarcin Wojtas 
64719aa95e4SMarcin Wojtas 	if (++queue->pidx == ENETC_MIN_DESC)
64819aa95e4SMarcin Wojtas 		queue->pidx = 0;
64919aa95e4SMarcin Wojtas 
65019aa95e4SMarcin Wojtas 	desc->addr[0] = (uint32_t)dma->idi_paddr;
65119aa95e4SMarcin Wojtas 	desc->addr[1] = (uint32_t)(dma->idi_paddr >> 32);
65219aa95e4SMarcin Wojtas 	desc->index = 0;
65319aa95e4SMarcin Wojtas 	desc->length = (uint16_t)size;
65419aa95e4SMarcin Wojtas 	desc->cmd = (uint8_t)cmd;
65519aa95e4SMarcin Wojtas 	desc->cls = (uint8_t)(cmd >> 8);
65619aa95e4SMarcin Wojtas 	desc->status_flags = 0;
65719aa95e4SMarcin Wojtas 
65819aa95e4SMarcin Wojtas 	/* Sync command packet, */
65919aa95e4SMarcin Wojtas 	bus_dmamap_sync(dma->idi_tag, dma->idi_map, BUS_DMASYNC_PREWRITE);
66019aa95e4SMarcin Wojtas 	/* and the control ring. */
66119aa95e4SMarcin Wojtas 	bus_dmamap_sync(queue->dma.idi_tag, queue->dma.idi_map, BUS_DMASYNC_PREWRITE);
66219aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRPIR, queue->pidx);
66319aa95e4SMarcin Wojtas 
66419aa95e4SMarcin Wojtas 	while (--timeout != 0) {
66519aa95e4SMarcin Wojtas 		DELAY(20);
66619aa95e4SMarcin Wojtas 		if (ENETC_RD4(sc, ENETC_SICBDRCIR) == queue->pidx)
66719aa95e4SMarcin Wojtas 			break;
66819aa95e4SMarcin Wojtas 	}
66919aa95e4SMarcin Wojtas 
67019aa95e4SMarcin Wojtas 	if (timeout == 0)
67119aa95e4SMarcin Wojtas 		return (ETIMEDOUT);
67219aa95e4SMarcin Wojtas 
67319aa95e4SMarcin Wojtas 	bus_dmamap_sync(dma->idi_tag, dma->idi_map, BUS_DMASYNC_POSTREAD);
67419aa95e4SMarcin Wojtas 	return (0);
67519aa95e4SMarcin Wojtas }
67619aa95e4SMarcin Wojtas 
67719aa95e4SMarcin Wojtas static void
67819aa95e4SMarcin Wojtas enetc_init_hw(struct enetc_softc *sc)
67919aa95e4SMarcin Wojtas {
68019aa95e4SMarcin Wojtas 	uint32_t val;
68119aa95e4SMarcin Wojtas 	int error;
68219aa95e4SMarcin Wojtas 
68319aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PM0_CMD_CFG,
68419aa95e4SMarcin Wojtas 	    ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC |
68519aa95e4SMarcin Wojtas 	    ENETC_PM0_TX_EN | ENETC_PM0_RX_EN);
68619aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PM0_RX_FIFO, ENETC_PM0_RX_FIFO_VAL);
68719aa95e4SMarcin Wojtas 	val = ENETC_PSICFGR0_SET_TXBDR(sc->tx_num_queues);
68819aa95e4SMarcin Wojtas 	val |= ENETC_PSICFGR0_SET_RXBDR(sc->rx_num_queues);
68919aa95e4SMarcin Wojtas 	val |= ENETC_PSICFGR0_SIVC(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S);
69019aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSICFGR0(0), val);
69119aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIPVMR, ENETC_PSIPVMR_SET_VUTA(1));
69219aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PVCLCTR,  ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S);
69319aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIVLANFMR, ENETC_PSIVLANFMR_VS);
69419aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PAR_PORT_CFG, ENETC_PAR_PORT_L4CD);
69519aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PMR, ENETC_PMR_SI0EN | ENETC_PMR_PSPEED_1000M);
69619aa95e4SMarcin Wojtas 
69719aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICAR0,
69819aa95e4SMarcin Wojtas 	    ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);
69919aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICAR1, ENETC_SICAR_MSI);
70019aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICAR2,
70119aa95e4SMarcin Wojtas 	    ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);
70219aa95e4SMarcin Wojtas 
70319aa95e4SMarcin Wojtas 	enetc_init_ctrl(sc);
70419aa95e4SMarcin Wojtas 	error = enetc_setup_rss(sc);
70519aa95e4SMarcin Wojtas 	if (error != 0)
70619aa95e4SMarcin Wojtas 		ENETC_WR4(sc, ENETC_SIMR, ENETC_SIMR_EN);
70719aa95e4SMarcin Wojtas 	else
70819aa95e4SMarcin Wojtas 		ENETC_WR4(sc, ENETC_SIMR, ENETC_SIMR_EN | ENETC_SIMR_RSSE);
70919aa95e4SMarcin Wojtas 
71019aa95e4SMarcin Wojtas }
71119aa95e4SMarcin Wojtas 
71219aa95e4SMarcin Wojtas static void
71319aa95e4SMarcin Wojtas enetc_init_ctrl(struct enetc_softc *sc)
71419aa95e4SMarcin Wojtas {
71519aa95e4SMarcin Wojtas 	struct enetc_ctrl_queue *queue = &sc->ctrl_queue;
71619aa95e4SMarcin Wojtas 
71719aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRBAR0,
71819aa95e4SMarcin Wojtas 	    (uint32_t)queue->dma.idi_paddr);
71919aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRBAR1,
72019aa95e4SMarcin Wojtas 	    (uint32_t)(queue->dma.idi_paddr >> 32));
72119aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRLENR,
72219aa95e4SMarcin Wojtas 	    queue->dma.idi_size / sizeof(struct enetc_cbd));
72319aa95e4SMarcin Wojtas 
72419aa95e4SMarcin Wojtas 	queue->pidx = 0;
72519aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRPIR, queue->pidx);
72619aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRCIR, queue->pidx);
72719aa95e4SMarcin Wojtas 	ENETC_WR4(sc, ENETC_SICBDRMR, ENETC_SICBDRMR_EN);
72819aa95e4SMarcin Wojtas }
72919aa95e4SMarcin Wojtas 
73019aa95e4SMarcin Wojtas static void
73119aa95e4SMarcin Wojtas enetc_init_tx(struct enetc_softc *sc)
73219aa95e4SMarcin Wojtas {
73319aa95e4SMarcin Wojtas 	struct enetc_tx_queue *queue;
73419aa95e4SMarcin Wojtas 	int i;
73519aa95e4SMarcin Wojtas 
73619aa95e4SMarcin Wojtas 	for (i = 0; i < sc->tx_num_queues; i++) {
73719aa95e4SMarcin Wojtas 		queue = &sc->tx_queues[i];
73819aa95e4SMarcin Wojtas 
73919aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBBAR0,
74019aa95e4SMarcin Wojtas 		    (uint32_t)queue->ring_paddr);
74119aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBBAR1,
74219aa95e4SMarcin Wojtas 		    (uint32_t)(queue->ring_paddr >> 32));
74319aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBLENR, sc->tx_queue_size);
74419aa95e4SMarcin Wojtas 
74519aa95e4SMarcin Wojtas 		/*
74619aa95e4SMarcin Wojtas 		 * Even though it is undoccumented resetting the TX ring
74719aa95e4SMarcin Wojtas 		 * indices results in TX hang.
74819aa95e4SMarcin Wojtas 		 * Do the same as Linux and simply keep those unchanged
74919aa95e4SMarcin Wojtas 		 * for the drivers lifetime.
75019aa95e4SMarcin Wojtas 		 */
75119aa95e4SMarcin Wojtas #if 0
75219aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBPIR, 0);
75319aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBCIR, 0);
75419aa95e4SMarcin Wojtas #endif
75519aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBMR, ENETC_TBMR_EN);
75619aa95e4SMarcin Wojtas 	}
75719aa95e4SMarcin Wojtas 
75819aa95e4SMarcin Wojtas }
75919aa95e4SMarcin Wojtas 
76019aa95e4SMarcin Wojtas static void
76119aa95e4SMarcin Wojtas enetc_init_rx(struct enetc_softc *sc)
76219aa95e4SMarcin Wojtas {
76319aa95e4SMarcin Wojtas 	struct enetc_rx_queue *queue;
76419aa95e4SMarcin Wojtas 	uint32_t rx_buf_size;
76519aa95e4SMarcin Wojtas 	int i;
76619aa95e4SMarcin Wojtas 
76719aa95e4SMarcin Wojtas 	rx_buf_size = iflib_get_rx_mbuf_sz(sc->ctx);
76819aa95e4SMarcin Wojtas 
76919aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++) {
77019aa95e4SMarcin Wojtas 		queue = &sc->rx_queues[i];
77119aa95e4SMarcin Wojtas 
77219aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBBAR0,
77319aa95e4SMarcin Wojtas 		    (uint32_t)queue->ring_paddr);
77419aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBBAR1,
77519aa95e4SMarcin Wojtas 		    (uint32_t)(queue->ring_paddr >> 32));
77619aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBLENR, sc->rx_queue_size);
77719aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBBSR, rx_buf_size);
77819aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBPIR, 0);
77919aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBCIR, 0);
78019aa95e4SMarcin Wojtas 		queue->enabled = false;
78119aa95e4SMarcin Wojtas 	}
78219aa95e4SMarcin Wojtas }
78319aa95e4SMarcin Wojtas 
78419aa95e4SMarcin Wojtas static u_int
78519aa95e4SMarcin Wojtas enetc_hash_mac(void *arg, struct sockaddr_dl *sdl, u_int cnt)
78619aa95e4SMarcin Wojtas {
78719aa95e4SMarcin Wojtas 	uint64_t *bitmap = arg;
78819aa95e4SMarcin Wojtas 	uint64_t address = 0;
78919aa95e4SMarcin Wojtas 	uint8_t hash = 0;
79019aa95e4SMarcin Wojtas 	bool bit;
79119aa95e4SMarcin Wojtas 	int i, j;
79219aa95e4SMarcin Wojtas 
79319aa95e4SMarcin Wojtas 	bcopy(LLADDR(sdl), &address, ETHER_ADDR_LEN);
79419aa95e4SMarcin Wojtas 
79519aa95e4SMarcin Wojtas 	/*
79619aa95e4SMarcin Wojtas 	 * The six bit hash is calculated by xoring every
79719aa95e4SMarcin Wojtas 	 * 6th bit of the address.
79819aa95e4SMarcin Wojtas 	 * It is then used as an index in a bitmap that is
79919aa95e4SMarcin Wojtas 	 * written to the device.
80019aa95e4SMarcin Wojtas 	 */
80119aa95e4SMarcin Wojtas 	for (i = 0; i < 6; i++) {
80219aa95e4SMarcin Wojtas 		bit = 0;
80319aa95e4SMarcin Wojtas 		for (j = 0; j < 8; j++)
80419aa95e4SMarcin Wojtas 			bit ^= address & BIT(i + j*6);
80519aa95e4SMarcin Wojtas 
80619aa95e4SMarcin Wojtas 		hash |= bit << i;
80719aa95e4SMarcin Wojtas 	}
80819aa95e4SMarcin Wojtas 
80919aa95e4SMarcin Wojtas 	*bitmap |= (1 << hash);
81019aa95e4SMarcin Wojtas 	return (1);
81119aa95e4SMarcin Wojtas }
81219aa95e4SMarcin Wojtas 
81319aa95e4SMarcin Wojtas static void
81419aa95e4SMarcin Wojtas enetc_setup_multicast(if_ctx_t ctx)
81519aa95e4SMarcin Wojtas {
81619aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
81719aa95e4SMarcin Wojtas 	struct ifnet *ifp;
81819aa95e4SMarcin Wojtas 	uint64_t bitmap = 0;
81919aa95e4SMarcin Wojtas 	uint8_t revid;
82019aa95e4SMarcin Wojtas 
82119aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
82219aa95e4SMarcin Wojtas 	ifp = iflib_get_ifp(ctx);
82319aa95e4SMarcin Wojtas 	revid = pci_get_revid(sc->dev);
82419aa95e4SMarcin Wojtas 
82519aa95e4SMarcin Wojtas 	if_foreach_llmaddr(ifp, enetc_hash_mac, &bitmap);
82619aa95e4SMarcin Wojtas 
82719aa95e4SMarcin Wojtas 	/*
82819aa95e4SMarcin Wojtas 	 * In revid 1 of this chip the positions multicast and unicast
82919aa95e4SMarcin Wojtas 	 * hash filter registers are flipped.
83019aa95e4SMarcin Wojtas 	 */
83119aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIMMHFR0(0, revid == 1), bitmap & UINT32_MAX);
83219aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIMMHFR1(0), bitmap >> 32);
83319aa95e4SMarcin Wojtas 
83419aa95e4SMarcin Wojtas }
83519aa95e4SMarcin Wojtas 
83619aa95e4SMarcin Wojtas static uint8_t
83719aa95e4SMarcin Wojtas enetc_hash_vid(uint16_t vid)
83819aa95e4SMarcin Wojtas {
83919aa95e4SMarcin Wojtas 	uint8_t hash = 0;
84019aa95e4SMarcin Wojtas 	bool bit;
84119aa95e4SMarcin Wojtas 	int i;
84219aa95e4SMarcin Wojtas 
84319aa95e4SMarcin Wojtas 	for (i = 0;i < 6;i++) {
84419aa95e4SMarcin Wojtas 		bit = vid & BIT(i);
84519aa95e4SMarcin Wojtas 		bit ^= vid & BIT(i + 6);
84619aa95e4SMarcin Wojtas 		hash |= bit << i;
84719aa95e4SMarcin Wojtas 	}
84819aa95e4SMarcin Wojtas 
84919aa95e4SMarcin Wojtas 	return (hash);
85019aa95e4SMarcin Wojtas }
85119aa95e4SMarcin Wojtas 
85219aa95e4SMarcin Wojtas static void
85319aa95e4SMarcin Wojtas enetc_vlan_register(if_ctx_t ctx, uint16_t vid)
85419aa95e4SMarcin Wojtas {
85519aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
85619aa95e4SMarcin Wojtas 	uint8_t hash;
85719aa95e4SMarcin Wojtas 	uint64_t bitmap;
85819aa95e4SMarcin Wojtas 
85919aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
86019aa95e4SMarcin Wojtas 	hash = enetc_hash_vid(vid);
86119aa95e4SMarcin Wojtas 
86219aa95e4SMarcin Wojtas 	/* Check if hash is alredy present in the bitmap. */
86319aa95e4SMarcin Wojtas 	if (++sc->vlan_bitmap[hash] != 1)
86419aa95e4SMarcin Wojtas 		return;
86519aa95e4SMarcin Wojtas 
86619aa95e4SMarcin Wojtas 	bitmap = ENETC_PORT_RD4(sc, ENETC_PSIVHFR0(0));
86719aa95e4SMarcin Wojtas 	bitmap |= (uint64_t)ENETC_PORT_RD4(sc, ENETC_PSIVHFR1(0)) << 32;
86819aa95e4SMarcin Wojtas 	bitmap |= BIT(hash);
86919aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIVHFR0(0), bitmap & UINT32_MAX);
87019aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIVHFR1(0), bitmap >> 32);
87119aa95e4SMarcin Wojtas }
87219aa95e4SMarcin Wojtas 
87319aa95e4SMarcin Wojtas static void
87419aa95e4SMarcin Wojtas enetc_vlan_unregister(if_ctx_t ctx, uint16_t vid)
87519aa95e4SMarcin Wojtas {
87619aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
87719aa95e4SMarcin Wojtas 	uint8_t hash;
87819aa95e4SMarcin Wojtas 	uint64_t bitmap;
87919aa95e4SMarcin Wojtas 
88019aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
88119aa95e4SMarcin Wojtas 	hash = enetc_hash_vid(vid);
88219aa95e4SMarcin Wojtas 
88319aa95e4SMarcin Wojtas 	MPASS(sc->vlan_bitmap[hash] > 0);
88419aa95e4SMarcin Wojtas 	if (--sc->vlan_bitmap[hash] != 0)
88519aa95e4SMarcin Wojtas 		return;
88619aa95e4SMarcin Wojtas 
88719aa95e4SMarcin Wojtas 	bitmap = ENETC_PORT_RD4(sc, ENETC_PSIVHFR0(0));
88819aa95e4SMarcin Wojtas 	bitmap |= (uint64_t)ENETC_PORT_RD4(sc, ENETC_PSIVHFR1(0)) << 32;
88919aa95e4SMarcin Wojtas 	bitmap &= ~BIT(hash);
89019aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIVHFR0(0), bitmap & UINT32_MAX);
89119aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIVHFR1(0), bitmap >> 32);
89219aa95e4SMarcin Wojtas }
89319aa95e4SMarcin Wojtas 
89419aa95e4SMarcin Wojtas static void
89519aa95e4SMarcin Wojtas enetc_init(if_ctx_t ctx)
89619aa95e4SMarcin Wojtas {
89719aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
89819aa95e4SMarcin Wojtas 	struct mii_data *miid;
89919aa95e4SMarcin Wojtas 	struct ifnet *ifp;
90019aa95e4SMarcin Wojtas 	uint16_t max_frame_length;
90119aa95e4SMarcin Wojtas 	int baudrate;
90219aa95e4SMarcin Wojtas 
90319aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
90419aa95e4SMarcin Wojtas 	ifp = iflib_get_ifp(ctx);
90519aa95e4SMarcin Wojtas 
90619aa95e4SMarcin Wojtas 	max_frame_length = sc->shared->isc_max_frame_size;
90719aa95e4SMarcin Wojtas 	MPASS(max_frame_length < ENETC_MAX_FRAME_LEN);
90819aa95e4SMarcin Wojtas 
90919aa95e4SMarcin Wojtas 	/* Set max RX and TX frame lengths. */
91019aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PM0_MAXFRM, max_frame_length);
91119aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PTCMSDUR(0), max_frame_length);
91219aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PTXMBAR, 2 * max_frame_length);
91319aa95e4SMarcin Wojtas 
91419aa95e4SMarcin Wojtas 	/* Set "VLAN promiscious" mode if filtering is disabled. */
91519aa95e4SMarcin Wojtas 	if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0)
91619aa95e4SMarcin Wojtas 		ENETC_PORT_WR4(sc, ENETC_PSIPVMR,
91719aa95e4SMarcin Wojtas 		    ENETC_PSIPVMR_SET_VUTA(1) | ENETC_PSIPVMR_SET_VP(1));
91819aa95e4SMarcin Wojtas 	else
91919aa95e4SMarcin Wojtas 		ENETC_PORT_WR4(sc, ENETC_PSIPVMR,
92019aa95e4SMarcin Wojtas 		    ENETC_PSIPVMR_SET_VUTA(1));
92119aa95e4SMarcin Wojtas 
92219aa95e4SMarcin Wojtas 	sc->rbmr = ENETC_RBMR_EN | ENETC_RBMR_AL;
92319aa95e4SMarcin Wojtas 
92419aa95e4SMarcin Wojtas 	if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING)
92519aa95e4SMarcin Wojtas 		sc->rbmr |= ENETC_RBMR_VTE;
92619aa95e4SMarcin Wojtas 
92719aa95e4SMarcin Wojtas 	/* Write MAC address to hardware. */
92819aa95e4SMarcin Wojtas 	enetc_set_hwaddr(sc);
92919aa95e4SMarcin Wojtas 
93019aa95e4SMarcin Wojtas 	enetc_init_tx(sc);
93119aa95e4SMarcin Wojtas 	enetc_init_rx(sc);
93219aa95e4SMarcin Wojtas 
93319aa95e4SMarcin Wojtas 	if (sc->fixed_link) {
93419aa95e4SMarcin Wojtas 		baudrate = ifmedia_baudrate(sc->fixed_ifmedia.ifm_cur->ifm_media);
93519aa95e4SMarcin Wojtas 		iflib_link_state_change(sc->ctx, LINK_STATE_UP, baudrate);
93619aa95e4SMarcin Wojtas 	} else {
93719aa95e4SMarcin Wojtas 		/*
93819aa95e4SMarcin Wojtas 		 * Can't return an error from this function, there is not much
93919aa95e4SMarcin Wojtas 		 * we can do if this fails.
94019aa95e4SMarcin Wojtas 		 */
94119aa95e4SMarcin Wojtas 		miid = device_get_softc(sc->miibus);
94219aa95e4SMarcin Wojtas 		(void)mii_mediachg(miid);
94319aa95e4SMarcin Wojtas 	}
94419aa95e4SMarcin Wojtas 
94519aa95e4SMarcin Wojtas 	enetc_promisc_set(ctx, if_getflags(ifp));
94619aa95e4SMarcin Wojtas }
94719aa95e4SMarcin Wojtas 
94819aa95e4SMarcin Wojtas static void
94919aa95e4SMarcin Wojtas enetc_stop(if_ctx_t ctx)
95019aa95e4SMarcin Wojtas {
95119aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
95219aa95e4SMarcin Wojtas 	int i;
95319aa95e4SMarcin Wojtas 
95419aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
95519aa95e4SMarcin Wojtas 
95619aa95e4SMarcin Wojtas 	for (i = 0; i < sc->tx_num_queues; i++)
95719aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBMR, 0);
95819aa95e4SMarcin Wojtas 
95919aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++)
96019aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBMR, 0);
96119aa95e4SMarcin Wojtas }
96219aa95e4SMarcin Wojtas 
96319aa95e4SMarcin Wojtas static int
96419aa95e4SMarcin Wojtas enetc_msix_intr_assign(if_ctx_t ctx, int msix)
96519aa95e4SMarcin Wojtas {
96619aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
96719aa95e4SMarcin Wojtas 	struct enetc_rx_queue *rx_queue;
96819aa95e4SMarcin Wojtas 	struct enetc_tx_queue *tx_queue;
96919aa95e4SMarcin Wojtas 	int vector = 0, i, error;
97019aa95e4SMarcin Wojtas 	char irq_name[16];
97119aa95e4SMarcin Wojtas 
97219aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
97319aa95e4SMarcin Wojtas 
97419aa95e4SMarcin Wojtas 	MPASS(sc->rx_num_queues + 1 <= ENETC_MSIX_COUNT);
97519aa95e4SMarcin Wojtas 	MPASS(sc->rx_num_queues == sc->tx_num_queues);
97619aa95e4SMarcin Wojtas 
97719aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++, vector++) {
97819aa95e4SMarcin Wojtas 		rx_queue = &sc->rx_queues[i];
97919aa95e4SMarcin Wojtas 		snprintf(irq_name, sizeof(irq_name), "rxtxq%d", i);
98019aa95e4SMarcin Wojtas 		error = iflib_irq_alloc_generic(ctx,
98119aa95e4SMarcin Wojtas 		    &rx_queue->irq, vector + 1, IFLIB_INTR_RXTX,
98219aa95e4SMarcin Wojtas 		    NULL, rx_queue, i, irq_name);
98319aa95e4SMarcin Wojtas 		if (error != 0)
98419aa95e4SMarcin Wojtas 			goto fail;
98519aa95e4SMarcin Wojtas 
98619aa95e4SMarcin Wojtas 		ENETC_WR4(sc, ENETC_SIMSIRRV(i), vector);
98719aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBICR1, ENETC_RX_INTR_TIME_THR);
98819aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBICR0,
98919aa95e4SMarcin Wojtas 		    ENETC_RBICR0_ICEN | ENETC_RBICR0_SET_ICPT(ENETC_RX_INTR_PKT_THR));
99019aa95e4SMarcin Wojtas 	}
99119aa95e4SMarcin Wojtas 	vector = 0;
99219aa95e4SMarcin Wojtas 	for (i = 0;i < sc->tx_num_queues; i++, vector++) {
99319aa95e4SMarcin Wojtas 		tx_queue = &sc->tx_queues[i];
99419aa95e4SMarcin Wojtas 		snprintf(irq_name, sizeof(irq_name), "txq%d", i);
99519aa95e4SMarcin Wojtas 		iflib_softirq_alloc_generic(ctx, &tx_queue->irq,
99619aa95e4SMarcin Wojtas 		    IFLIB_INTR_TX, tx_queue, i, irq_name);
99719aa95e4SMarcin Wojtas 
99819aa95e4SMarcin Wojtas 		ENETC_WR4(sc, ENETC_SIMSITRV(i), vector);
99919aa95e4SMarcin Wojtas 	}
100019aa95e4SMarcin Wojtas 
100119aa95e4SMarcin Wojtas 	return (0);
100219aa95e4SMarcin Wojtas fail:
100319aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++) {
100419aa95e4SMarcin Wojtas 		rx_queue = &sc->rx_queues[i];
100519aa95e4SMarcin Wojtas 		iflib_irq_free(ctx, &rx_queue->irq);
100619aa95e4SMarcin Wojtas 	}
100719aa95e4SMarcin Wojtas 	return (error);
100819aa95e4SMarcin Wojtas }
100919aa95e4SMarcin Wojtas 
101019aa95e4SMarcin Wojtas static int
101119aa95e4SMarcin Wojtas enetc_tx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
101219aa95e4SMarcin Wojtas {
101319aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
101419aa95e4SMarcin Wojtas 
101519aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
101619aa95e4SMarcin Wojtas 	ENETC_TXQ_RD4(sc, qid, ENETC_TBIDR);
101719aa95e4SMarcin Wojtas 	return (0);
101819aa95e4SMarcin Wojtas }
101919aa95e4SMarcin Wojtas 
102019aa95e4SMarcin Wojtas static int
102119aa95e4SMarcin Wojtas enetc_rx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
102219aa95e4SMarcin Wojtas {
102319aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
102419aa95e4SMarcin Wojtas 
102519aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
102619aa95e4SMarcin Wojtas 	ENETC_RXQ_RD4(sc, qid, ENETC_RBIDR);
102719aa95e4SMarcin Wojtas 	return (0);
102819aa95e4SMarcin Wojtas }
102919aa95e4SMarcin Wojtas static void
103019aa95e4SMarcin Wojtas enetc_intr_enable(if_ctx_t ctx)
103119aa95e4SMarcin Wojtas {
103219aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
103319aa95e4SMarcin Wojtas 	int i;
103419aa95e4SMarcin Wojtas 
103519aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
103619aa95e4SMarcin Wojtas 
103719aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++)
103819aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBIER, ENETC_RBIER_RXTIE);
103919aa95e4SMarcin Wojtas 
104019aa95e4SMarcin Wojtas 	for (i = 0; i < sc->tx_num_queues; i++)
104119aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBIER, ENETC_TBIER_TXF);
104219aa95e4SMarcin Wojtas }
104319aa95e4SMarcin Wojtas 
104419aa95e4SMarcin Wojtas static void
104519aa95e4SMarcin Wojtas enetc_intr_disable(if_ctx_t ctx)
104619aa95e4SMarcin Wojtas {
104719aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
104819aa95e4SMarcin Wojtas 	int i;
104919aa95e4SMarcin Wojtas 
105019aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
105119aa95e4SMarcin Wojtas 
105219aa95e4SMarcin Wojtas 	for (i = 0; i < sc->rx_num_queues; i++)
105319aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, i, ENETC_RBIER, 0);
105419aa95e4SMarcin Wojtas 
105519aa95e4SMarcin Wojtas 	for (i = 0; i < sc->tx_num_queues; i++)
105619aa95e4SMarcin Wojtas 		ENETC_TXQ_WR4(sc, i, ENETC_TBIER, 0);
105719aa95e4SMarcin Wojtas }
105819aa95e4SMarcin Wojtas 
105919aa95e4SMarcin Wojtas static int
106019aa95e4SMarcin Wojtas enetc_isc_txd_encap(void *data, if_pkt_info_t ipi)
106119aa95e4SMarcin Wojtas {
106219aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
106319aa95e4SMarcin Wojtas 	struct enetc_tx_queue *queue;
106419aa95e4SMarcin Wojtas 	union enetc_tx_bd *desc;
106519aa95e4SMarcin Wojtas 	bus_dma_segment_t *segs;
106619aa95e4SMarcin Wojtas 	qidx_t pidx, queue_len;
106719aa95e4SMarcin Wojtas 	qidx_t i = 0;
106819aa95e4SMarcin Wojtas 
106919aa95e4SMarcin Wojtas 	queue = &sc->tx_queues[ipi->ipi_qsidx];
107019aa95e4SMarcin Wojtas 	segs = ipi->ipi_segs;
107119aa95e4SMarcin Wojtas 	pidx = ipi->ipi_pidx;
107219aa95e4SMarcin Wojtas 	queue_len = sc->tx_queue_size;
107319aa95e4SMarcin Wojtas 
107419aa95e4SMarcin Wojtas 	/*
107519aa95e4SMarcin Wojtas 	 * First descriptor is special. We use it to set frame
107619aa95e4SMarcin Wojtas 	 * related information and offloads, e.g. VLAN tag.
107719aa95e4SMarcin Wojtas 	 */
107819aa95e4SMarcin Wojtas 	desc = &queue->ring[pidx];
107919aa95e4SMarcin Wojtas 	bzero(desc, sizeof(*desc));
108019aa95e4SMarcin Wojtas 	desc->frm_len = ipi->ipi_len;
108119aa95e4SMarcin Wojtas 	desc->addr = segs[i].ds_addr;
108219aa95e4SMarcin Wojtas 	desc->buf_len = segs[i].ds_len;
108319aa95e4SMarcin Wojtas 	if (ipi->ipi_flags & IPI_TX_INTR)
108419aa95e4SMarcin Wojtas 		desc->flags = ENETC_TXBD_FLAGS_FI;
108519aa95e4SMarcin Wojtas 
108619aa95e4SMarcin Wojtas 	i++;
108719aa95e4SMarcin Wojtas 	if (++pidx == queue_len)
108819aa95e4SMarcin Wojtas 		pidx = 0;
108919aa95e4SMarcin Wojtas 
109019aa95e4SMarcin Wojtas 	if (ipi->ipi_mflags & M_VLANTAG) {
109119aa95e4SMarcin Wojtas 		/* VLAN tag is inserted in a separate descriptor. */
109219aa95e4SMarcin Wojtas 		desc->flags |= ENETC_TXBD_FLAGS_EX;
109319aa95e4SMarcin Wojtas 		desc = &queue->ring[pidx];
109419aa95e4SMarcin Wojtas 		bzero(desc, sizeof(*desc));
109519aa95e4SMarcin Wojtas 		desc->ext.vid = ipi->ipi_vtag;
109619aa95e4SMarcin Wojtas 		desc->ext.e_flags = ENETC_TXBD_E_FLAGS_VLAN_INS;
109719aa95e4SMarcin Wojtas 		if (++pidx == queue_len)
109819aa95e4SMarcin Wojtas 			pidx = 0;
109919aa95e4SMarcin Wojtas 	}
110019aa95e4SMarcin Wojtas 
110119aa95e4SMarcin Wojtas 	/* Now add remaining descriptors. */
110219aa95e4SMarcin Wojtas 	for (;i < ipi->ipi_nsegs; i++) {
110319aa95e4SMarcin Wojtas 		desc = &queue->ring[pidx];
110419aa95e4SMarcin Wojtas 		bzero(desc, sizeof(*desc));
110519aa95e4SMarcin Wojtas 		desc->addr = segs[i].ds_addr;
110619aa95e4SMarcin Wojtas 		desc->buf_len = segs[i].ds_len;
110719aa95e4SMarcin Wojtas 
110819aa95e4SMarcin Wojtas 		if (++pidx == queue_len)
110919aa95e4SMarcin Wojtas 			pidx = 0;
111019aa95e4SMarcin Wojtas 	}
111119aa95e4SMarcin Wojtas 
111219aa95e4SMarcin Wojtas 	desc->flags |= ENETC_TXBD_FLAGS_F;
111319aa95e4SMarcin Wojtas 	ipi->ipi_new_pidx = pidx;
111419aa95e4SMarcin Wojtas 	if (pidx == queue->next_to_clean)
111519aa95e4SMarcin Wojtas 		queue->ring_full = true;
111619aa95e4SMarcin Wojtas 
111719aa95e4SMarcin Wojtas 	return (0);
111819aa95e4SMarcin Wojtas }
111919aa95e4SMarcin Wojtas 
112019aa95e4SMarcin Wojtas static void
112119aa95e4SMarcin Wojtas enetc_isc_txd_flush(void *data, uint16_t qid, qidx_t pidx)
112219aa95e4SMarcin Wojtas {
112319aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
112419aa95e4SMarcin Wojtas 
112519aa95e4SMarcin Wojtas 	ENETC_TXQ_WR4(sc, qid, ENETC_TBPIR, pidx);
112619aa95e4SMarcin Wojtas }
112719aa95e4SMarcin Wojtas 
112819aa95e4SMarcin Wojtas static int
112919aa95e4SMarcin Wojtas enetc_isc_txd_credits_update(void *data, uint16_t qid, bool clear)
113019aa95e4SMarcin Wojtas {
113119aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
113219aa95e4SMarcin Wojtas 	struct enetc_tx_queue *queue;
113319aa95e4SMarcin Wojtas 	qidx_t next_to_clean, next_to_process;
113419aa95e4SMarcin Wojtas 	int clean_count;
113519aa95e4SMarcin Wojtas 
113619aa95e4SMarcin Wojtas 	queue = &sc->tx_queues[qid];
113719aa95e4SMarcin Wojtas 	next_to_process =
113819aa95e4SMarcin Wojtas 	    ENETC_TXQ_RD4(sc, qid, ENETC_TBCIR) & ENETC_TBCIR_IDX_MASK;
113919aa95e4SMarcin Wojtas 	next_to_clean = queue->next_to_clean;
114019aa95e4SMarcin Wojtas 
114119aa95e4SMarcin Wojtas 	if (next_to_clean == next_to_process && !queue->ring_full)
114219aa95e4SMarcin Wojtas 		return (0);
114319aa95e4SMarcin Wojtas 
114419aa95e4SMarcin Wojtas 	if (!clear)
114519aa95e4SMarcin Wojtas 		return (1);
114619aa95e4SMarcin Wojtas 
114719aa95e4SMarcin Wojtas 	clean_count = next_to_process - next_to_clean;
114819aa95e4SMarcin Wojtas 	if (clean_count <= 0)
114919aa95e4SMarcin Wojtas 		clean_count += sc->tx_queue_size;
115019aa95e4SMarcin Wojtas 
115119aa95e4SMarcin Wojtas 	queue->next_to_clean = next_to_process;
115219aa95e4SMarcin Wojtas 	queue->ring_full = false;
115319aa95e4SMarcin Wojtas 
115419aa95e4SMarcin Wojtas 	return (clean_count);
115519aa95e4SMarcin Wojtas }
115619aa95e4SMarcin Wojtas 
115719aa95e4SMarcin Wojtas static int
115819aa95e4SMarcin Wojtas enetc_isc_rxd_available(void *data, uint16_t qid, qidx_t pidx, qidx_t budget)
115919aa95e4SMarcin Wojtas {
116019aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
116119aa95e4SMarcin Wojtas 	struct enetc_rx_queue *queue;
116219aa95e4SMarcin Wojtas 	qidx_t hw_pidx, queue_len;
116319aa95e4SMarcin Wojtas 	union enetc_rx_bd *desc;
116419aa95e4SMarcin Wojtas 	int count = 0;
116519aa95e4SMarcin Wojtas 
116619aa95e4SMarcin Wojtas 	queue = &sc->rx_queues[qid];
116719aa95e4SMarcin Wojtas 	desc = &queue->ring[pidx];
116819aa95e4SMarcin Wojtas 	queue_len = sc->rx_queue_size;
116919aa95e4SMarcin Wojtas 
117019aa95e4SMarcin Wojtas 	if (desc->r.lstatus == 0)
117119aa95e4SMarcin Wojtas 		return (0);
117219aa95e4SMarcin Wojtas 
117319aa95e4SMarcin Wojtas 	if (budget == 1)
117419aa95e4SMarcin Wojtas 		return (1);
117519aa95e4SMarcin Wojtas 
117619aa95e4SMarcin Wojtas 	hw_pidx = ENETC_RXQ_RD4(sc, qid, ENETC_RBPIR);
117719aa95e4SMarcin Wojtas 	while (pidx != hw_pidx && count < budget) {
117819aa95e4SMarcin Wojtas 		desc = &queue->ring[pidx];
117919aa95e4SMarcin Wojtas 		if (desc->r.lstatus & ENETC_RXBD_LSTATUS_F)
118019aa95e4SMarcin Wojtas 			count++;
118119aa95e4SMarcin Wojtas 
118219aa95e4SMarcin Wojtas 		if (++pidx == queue_len)
118319aa95e4SMarcin Wojtas 			pidx = 0;
118419aa95e4SMarcin Wojtas 	}
118519aa95e4SMarcin Wojtas 
118619aa95e4SMarcin Wojtas 	return (count);
118719aa95e4SMarcin Wojtas }
118819aa95e4SMarcin Wojtas 
118919aa95e4SMarcin Wojtas static int
119019aa95e4SMarcin Wojtas enetc_isc_rxd_pkt_get(void *data, if_rxd_info_t ri)
119119aa95e4SMarcin Wojtas {
119219aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
119319aa95e4SMarcin Wojtas 	struct enetc_rx_queue *queue;
119419aa95e4SMarcin Wojtas 	union enetc_rx_bd *desc;
119519aa95e4SMarcin Wojtas 	uint16_t buf_len, pkt_size = 0;
119619aa95e4SMarcin Wojtas 	qidx_t cidx, queue_len;
119719aa95e4SMarcin Wojtas 	uint32_t status;
119819aa95e4SMarcin Wojtas 	int i;
119919aa95e4SMarcin Wojtas 
120019aa95e4SMarcin Wojtas 	cidx = ri->iri_cidx;
120119aa95e4SMarcin Wojtas 	queue = &sc->rx_queues[ri->iri_qsidx];
120219aa95e4SMarcin Wojtas 	desc = &queue->ring[cidx];
120319aa95e4SMarcin Wojtas 	status = desc->r.lstatus;
120419aa95e4SMarcin Wojtas 	queue_len = sc->rx_queue_size;
120519aa95e4SMarcin Wojtas 
120619aa95e4SMarcin Wojtas 	/*
120719aa95e4SMarcin Wojtas 	 * Ready bit will be set only when all descriptors
120819aa95e4SMarcin Wojtas 	 * in the chain have been processed.
120919aa95e4SMarcin Wojtas 	 */
121019aa95e4SMarcin Wojtas 	if ((status & ENETC_RXBD_LSTATUS_R) == 0)
121119aa95e4SMarcin Wojtas 		return (EAGAIN);
121219aa95e4SMarcin Wojtas 
121319aa95e4SMarcin Wojtas 	/* Pass RSS hash. */
121419aa95e4SMarcin Wojtas 	if (status & ENETC_RXBD_FLAG_RSSV) {
121519aa95e4SMarcin Wojtas 		ri->iri_flowid = desc->r.rss_hash;
121619aa95e4SMarcin Wojtas 		ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
121719aa95e4SMarcin Wojtas 	}
121819aa95e4SMarcin Wojtas 
121919aa95e4SMarcin Wojtas 	/* Pass IP checksum status. */
122019aa95e4SMarcin Wojtas 	ri->iri_csum_flags = CSUM_IP_CHECKED;
122119aa95e4SMarcin Wojtas 	if ((desc->r.parse_summary & ENETC_RXBD_PARSER_ERROR) == 0)
122219aa95e4SMarcin Wojtas 		ri->iri_csum_flags |= CSUM_IP_VALID;
122319aa95e4SMarcin Wojtas 
122419aa95e4SMarcin Wojtas 	/* Pass extracted VLAN tag. */
122519aa95e4SMarcin Wojtas 	if (status & ENETC_RXBD_FLAG_VLAN) {
122619aa95e4SMarcin Wojtas 		ri->iri_vtag = desc->r.vlan_opt;
122719aa95e4SMarcin Wojtas 		ri->iri_flags = M_VLANTAG;
122819aa95e4SMarcin Wojtas 	}
122919aa95e4SMarcin Wojtas 
123019aa95e4SMarcin Wojtas 	for (i = 0; i < ENETC_MAX_SCATTER; i++) {
123119aa95e4SMarcin Wojtas 		buf_len = desc->r.buf_len;
123219aa95e4SMarcin Wojtas 		ri->iri_frags[i].irf_idx = cidx;
123319aa95e4SMarcin Wojtas 		ri->iri_frags[i].irf_len = buf_len;
123419aa95e4SMarcin Wojtas 		pkt_size += buf_len;
123519aa95e4SMarcin Wojtas 		if (desc->r.lstatus & ENETC_RXBD_LSTATUS_F)
123619aa95e4SMarcin Wojtas 			break;
123719aa95e4SMarcin Wojtas 
123819aa95e4SMarcin Wojtas 		if (++cidx == queue_len)
123919aa95e4SMarcin Wojtas 			cidx = 0;
124019aa95e4SMarcin Wojtas 
124119aa95e4SMarcin Wojtas 		desc = &queue->ring[cidx];
124219aa95e4SMarcin Wojtas 	}
124319aa95e4SMarcin Wojtas 	ri->iri_nfrags = i + 1;
124419aa95e4SMarcin Wojtas 	ri->iri_len = pkt_size + ENETC_RX_IP_ALIGN;
124519aa95e4SMarcin Wojtas 	ri->iri_pad = ENETC_RX_IP_ALIGN;
124619aa95e4SMarcin Wojtas 
124719aa95e4SMarcin Wojtas 	MPASS(desc->r.lstatus & ENETC_RXBD_LSTATUS_F);
124819aa95e4SMarcin Wojtas 	if (status & ENETC_RXBD_LSTATUS(ENETC_RXBD_ERR_MASK))
124919aa95e4SMarcin Wojtas 		return (EBADMSG);
125019aa95e4SMarcin Wojtas 
125119aa95e4SMarcin Wojtas 	return (0);
125219aa95e4SMarcin Wojtas }
125319aa95e4SMarcin Wojtas 
125419aa95e4SMarcin Wojtas static void
125519aa95e4SMarcin Wojtas enetc_isc_rxd_refill(void *data, if_rxd_update_t iru)
125619aa95e4SMarcin Wojtas {
125719aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
125819aa95e4SMarcin Wojtas 	struct enetc_rx_queue *queue;
125919aa95e4SMarcin Wojtas 	union enetc_rx_bd *desc;
126019aa95e4SMarcin Wojtas 	qidx_t pidx, queue_len;
126119aa95e4SMarcin Wojtas 	uint64_t *paddrs;
126219aa95e4SMarcin Wojtas 	int i, count;
126319aa95e4SMarcin Wojtas 
126419aa95e4SMarcin Wojtas 	queue = &sc->rx_queues[iru->iru_qsidx];
126519aa95e4SMarcin Wojtas 	paddrs = iru->iru_paddrs;
126619aa95e4SMarcin Wojtas 	pidx = iru->iru_pidx;
126719aa95e4SMarcin Wojtas 	count = iru->iru_count;
126819aa95e4SMarcin Wojtas 	queue_len = sc->rx_queue_size;
126919aa95e4SMarcin Wojtas 
127019aa95e4SMarcin Wojtas 	for (i = 0; i < count; i++) {
127119aa95e4SMarcin Wojtas 		desc = &queue->ring[pidx];
127219aa95e4SMarcin Wojtas 		bzero(desc, sizeof(*desc));
127319aa95e4SMarcin Wojtas 
127419aa95e4SMarcin Wojtas 		desc->w.addr = paddrs[i];
127519aa95e4SMarcin Wojtas 		if (++pidx == queue_len)
127619aa95e4SMarcin Wojtas 			pidx = 0;
127719aa95e4SMarcin Wojtas 	}
127819aa95e4SMarcin Wojtas 	/*
127919aa95e4SMarcin Wojtas 	 * After enabling the queue NIC will prefetch the first
128019aa95e4SMarcin Wojtas 	 * 8 descriptors. It probably assumes that the RX is fully
128119aa95e4SMarcin Wojtas 	 * refilled when cidx == pidx.
128219aa95e4SMarcin Wojtas 	 * Enable it only if we have enough decriptors ready on the ring.
128319aa95e4SMarcin Wojtas 	 */
128419aa95e4SMarcin Wojtas 	if (!queue->enabled && pidx >= 8) {
128519aa95e4SMarcin Wojtas 		ENETC_RXQ_WR4(sc, iru->iru_qsidx, ENETC_RBMR, sc->rbmr);
128619aa95e4SMarcin Wojtas 		queue->enabled = true;
128719aa95e4SMarcin Wojtas 	}
128819aa95e4SMarcin Wojtas }
128919aa95e4SMarcin Wojtas 
129019aa95e4SMarcin Wojtas static void
129119aa95e4SMarcin Wojtas enetc_isc_rxd_flush(void *data, uint16_t qid, uint8_t flid, qidx_t pidx)
129219aa95e4SMarcin Wojtas {
129319aa95e4SMarcin Wojtas 	struct enetc_softc *sc = data;
129419aa95e4SMarcin Wojtas 
129519aa95e4SMarcin Wojtas 	ENETC_RXQ_WR4(sc, qid, ENETC_RBCIR, pidx);
129619aa95e4SMarcin Wojtas }
129719aa95e4SMarcin Wojtas 
129819aa95e4SMarcin Wojtas static uint64_t
129919aa95e4SMarcin Wojtas enetc_get_counter(if_ctx_t ctx, ift_counter cnt)
130019aa95e4SMarcin Wojtas {
130119aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
130219aa95e4SMarcin Wojtas 	struct ifnet *ifp;
130319aa95e4SMarcin Wojtas 
130419aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
130519aa95e4SMarcin Wojtas 	ifp = iflib_get_ifp(ctx);
130619aa95e4SMarcin Wojtas 
130719aa95e4SMarcin Wojtas 	switch (cnt) {
130819aa95e4SMarcin Wojtas 	case IFCOUNTER_IERRORS:
130919aa95e4SMarcin Wojtas 		return (ENETC_PORT_RD8(sc, ENETC_PM0_RERR));
131019aa95e4SMarcin Wojtas 	case IFCOUNTER_OERRORS:
131119aa95e4SMarcin Wojtas 		return (ENETC_PORT_RD8(sc, ENETC_PM0_TERR));
131219aa95e4SMarcin Wojtas 	default:
131319aa95e4SMarcin Wojtas 		return (if_get_counter_default(ifp, cnt));
131419aa95e4SMarcin Wojtas 	}
131519aa95e4SMarcin Wojtas }
131619aa95e4SMarcin Wojtas 
131719aa95e4SMarcin Wojtas static int
131819aa95e4SMarcin Wojtas enetc_mtu_set(if_ctx_t ctx, uint32_t mtu)
131919aa95e4SMarcin Wojtas {
132019aa95e4SMarcin Wojtas 	struct enetc_softc *sc = iflib_get_softc(ctx);
132119aa95e4SMarcin Wojtas 	uint32_t max_frame_size;
132219aa95e4SMarcin Wojtas 
132319aa95e4SMarcin Wojtas 	max_frame_size = mtu +
132419aa95e4SMarcin Wojtas 	    ETHER_HDR_LEN +
132519aa95e4SMarcin Wojtas 	    ETHER_CRC_LEN +
132619aa95e4SMarcin Wojtas 	    sizeof(struct ether_vlan_header);
132719aa95e4SMarcin Wojtas 
132819aa95e4SMarcin Wojtas 	if (max_frame_size > ENETC_MAX_FRAME_LEN)
132919aa95e4SMarcin Wojtas 		return (EINVAL);
133019aa95e4SMarcin Wojtas 
133119aa95e4SMarcin Wojtas 	sc->shared->isc_max_frame_size = max_frame_size;
133219aa95e4SMarcin Wojtas 
133319aa95e4SMarcin Wojtas 	return (0);
133419aa95e4SMarcin Wojtas }
133519aa95e4SMarcin Wojtas 
133619aa95e4SMarcin Wojtas static int
133719aa95e4SMarcin Wojtas enetc_promisc_set(if_ctx_t ctx, int flags)
133819aa95e4SMarcin Wojtas {
133919aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
134019aa95e4SMarcin Wojtas 	uint32_t reg = 0;
134119aa95e4SMarcin Wojtas 
134219aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
134319aa95e4SMarcin Wojtas 
134419aa95e4SMarcin Wojtas 	if (flags & IFF_PROMISC)
134519aa95e4SMarcin Wojtas 		reg = ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0);
134619aa95e4SMarcin Wojtas 	else if (flags & IFF_ALLMULTI)
134719aa95e4SMarcin Wojtas 		reg = ENETC_PSIPMR_SET_MP(0);
134819aa95e4SMarcin Wojtas 
134919aa95e4SMarcin Wojtas 	ENETC_PORT_WR4(sc, ENETC_PSIPMR, reg);
135019aa95e4SMarcin Wojtas 
135119aa95e4SMarcin Wojtas 	return (0);
135219aa95e4SMarcin Wojtas }
135319aa95e4SMarcin Wojtas 
135419aa95e4SMarcin Wojtas static void
135519aa95e4SMarcin Wojtas enetc_timer(if_ctx_t ctx, uint16_t qid)
135619aa95e4SMarcin Wojtas {
135719aa95e4SMarcin Wojtas 	/*
135819aa95e4SMarcin Wojtas 	 * Poll PHY status. Do this only for qid 0 to save
135919aa95e4SMarcin Wojtas 	 * some cycles.
136019aa95e4SMarcin Wojtas 	 */
136119aa95e4SMarcin Wojtas 	if (qid == 0)
136219aa95e4SMarcin Wojtas 		iflib_admin_intr_deferred(ctx);
136319aa95e4SMarcin Wojtas }
136419aa95e4SMarcin Wojtas 
136519aa95e4SMarcin Wojtas static void
136619aa95e4SMarcin Wojtas enetc_update_admin_status(if_ctx_t ctx)
136719aa95e4SMarcin Wojtas {
136819aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
136919aa95e4SMarcin Wojtas 	struct mii_data *miid;
137019aa95e4SMarcin Wojtas 
137119aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ctx);
137219aa95e4SMarcin Wojtas 
137319aa95e4SMarcin Wojtas 	if (!sc->fixed_link) {
137419aa95e4SMarcin Wojtas 		miid = device_get_softc(sc->miibus);
137519aa95e4SMarcin Wojtas 		mii_tick(miid);
137619aa95e4SMarcin Wojtas 	}
137719aa95e4SMarcin Wojtas }
137819aa95e4SMarcin Wojtas 
137919aa95e4SMarcin Wojtas static int
138019aa95e4SMarcin Wojtas enetc_miibus_readreg(device_t dev, int phy, int reg)
138119aa95e4SMarcin Wojtas {
138219aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
138319aa95e4SMarcin Wojtas 
138419aa95e4SMarcin Wojtas 	sc = iflib_get_softc(device_get_softc(dev));
138519aa95e4SMarcin Wojtas 	return (enetc_mdio_read(sc->regs, ENETC_PORT_BASE + ENETC_EMDIO_BASE,
138619aa95e4SMarcin Wojtas 	    phy, reg));
138719aa95e4SMarcin Wojtas }
138819aa95e4SMarcin Wojtas 
138919aa95e4SMarcin Wojtas static int
139019aa95e4SMarcin Wojtas enetc_miibus_writereg(device_t dev, int phy, int reg, int data)
139119aa95e4SMarcin Wojtas {
139219aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
139319aa95e4SMarcin Wojtas 
139419aa95e4SMarcin Wojtas 	sc = iflib_get_softc(device_get_softc(dev));
139519aa95e4SMarcin Wojtas 	return (enetc_mdio_write(sc->regs, ENETC_PORT_BASE + ENETC_EMDIO_BASE,
139619aa95e4SMarcin Wojtas 	    phy, reg, data));
139719aa95e4SMarcin Wojtas }
139819aa95e4SMarcin Wojtas 
139919aa95e4SMarcin Wojtas static void
140019aa95e4SMarcin Wojtas enetc_miibus_linkchg(device_t dev)
140119aa95e4SMarcin Wojtas {
140219aa95e4SMarcin Wojtas 
140319aa95e4SMarcin Wojtas 	enetc_miibus_statchg(dev);
140419aa95e4SMarcin Wojtas }
140519aa95e4SMarcin Wojtas 
140619aa95e4SMarcin Wojtas static void
140719aa95e4SMarcin Wojtas enetc_miibus_statchg(device_t dev)
140819aa95e4SMarcin Wojtas {
140919aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
141019aa95e4SMarcin Wojtas 	struct mii_data *miid;
141119aa95e4SMarcin Wojtas 	int link_state, baudrate;
141219aa95e4SMarcin Wojtas 
141319aa95e4SMarcin Wojtas 	sc = iflib_get_softc(device_get_softc(dev));
141419aa95e4SMarcin Wojtas 	miid = device_get_softc(sc->miibus);
141519aa95e4SMarcin Wojtas 
141619aa95e4SMarcin Wojtas 	baudrate = ifmedia_baudrate(miid->mii_media_active);
141719aa95e4SMarcin Wojtas 	if (miid->mii_media_status & IFM_AVALID) {
141819aa95e4SMarcin Wojtas 		if (miid->mii_media_status & IFM_ACTIVE)
141919aa95e4SMarcin Wojtas 			link_state = LINK_STATE_UP;
142019aa95e4SMarcin Wojtas 		else
142119aa95e4SMarcin Wojtas 			link_state = LINK_STATE_DOWN;
142219aa95e4SMarcin Wojtas 	} else {
142319aa95e4SMarcin Wojtas 		link_state = LINK_STATE_UNKNOWN;
142419aa95e4SMarcin Wojtas 	}
142519aa95e4SMarcin Wojtas 
142619aa95e4SMarcin Wojtas 	iflib_link_state_change(sc->ctx, link_state, baudrate);
142719aa95e4SMarcin Wojtas 
142819aa95e4SMarcin Wojtas }
142919aa95e4SMarcin Wojtas 
143019aa95e4SMarcin Wojtas static int
143119aa95e4SMarcin Wojtas enetc_media_change(if_t ifp)
143219aa95e4SMarcin Wojtas {
143319aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
143419aa95e4SMarcin Wojtas 	struct mii_data *miid;
143519aa95e4SMarcin Wojtas 
143619aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ifp->if_softc);
143719aa95e4SMarcin Wojtas 	miid = device_get_softc(sc->miibus);
143819aa95e4SMarcin Wojtas 
143919aa95e4SMarcin Wojtas 	mii_mediachg(miid);
144019aa95e4SMarcin Wojtas 	return (0);
144119aa95e4SMarcin Wojtas }
144219aa95e4SMarcin Wojtas 
144319aa95e4SMarcin Wojtas static void
144419aa95e4SMarcin Wojtas enetc_media_status(if_t ifp, struct ifmediareq* ifmr)
144519aa95e4SMarcin Wojtas {
144619aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
144719aa95e4SMarcin Wojtas 	struct mii_data *miid;
144819aa95e4SMarcin Wojtas 
144919aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ifp->if_softc);
145019aa95e4SMarcin Wojtas 	miid = device_get_softc(sc->miibus);
145119aa95e4SMarcin Wojtas 
145219aa95e4SMarcin Wojtas 	mii_pollstat(miid);
145319aa95e4SMarcin Wojtas 
145419aa95e4SMarcin Wojtas 	ifmr->ifm_active = miid->mii_media_active;
145519aa95e4SMarcin Wojtas 	ifmr->ifm_status = miid->mii_media_status;
145619aa95e4SMarcin Wojtas }
145719aa95e4SMarcin Wojtas 
145819aa95e4SMarcin Wojtas static int
145919aa95e4SMarcin Wojtas enetc_fixed_media_change(if_t ifp)
146019aa95e4SMarcin Wojtas {
146119aa95e4SMarcin Wojtas 
146219aa95e4SMarcin Wojtas 	if_printf(ifp, "Can't change media in fixed-link mode.\n");
146319aa95e4SMarcin Wojtas 	return (0);
146419aa95e4SMarcin Wojtas }
146519aa95e4SMarcin Wojtas static void
146619aa95e4SMarcin Wojtas enetc_fixed_media_status(if_t ifp, struct ifmediareq* ifmr)
146719aa95e4SMarcin Wojtas {
146819aa95e4SMarcin Wojtas 	struct enetc_softc *sc;
146919aa95e4SMarcin Wojtas 
147019aa95e4SMarcin Wojtas 	sc = iflib_get_softc(ifp->if_softc);
147119aa95e4SMarcin Wojtas 
147219aa95e4SMarcin Wojtas 	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
147319aa95e4SMarcin Wojtas 	ifmr->ifm_active = sc->fixed_ifmedia.ifm_cur->ifm_media;
147419aa95e4SMarcin Wojtas 	return;
147519aa95e4SMarcin Wojtas }
1476