xref: /freebsd/sys/dev/mgb/if_mgb.c (revision fcb71d3f)
18890ab77SEd Maste /*-
28890ab77SEd Maste  * SPDX-License-Identifier: BSD-2-Clause
38890ab77SEd Maste  *
48890ab77SEd Maste  * Copyright (c) 2019 The FreeBSD Foundation, Inc.
58890ab77SEd Maste  *
68890ab77SEd Maste  * This driver was written by Gerald ND Aryeetey <gndaryee@uwaterloo.ca>
78890ab77SEd Maste  * under sponsorship from the FreeBSD Foundation.
88890ab77SEd Maste  *
98890ab77SEd Maste  * Redistribution and use in source and binary forms, with or without
108890ab77SEd Maste  * modification, are permitted provided that the following conditions
118890ab77SEd Maste  * are met:
128890ab77SEd Maste  * 1. Redistributions of source code must retain the above copyright
138890ab77SEd Maste  *    notice, this list of conditions and the following disclaimer.
148890ab77SEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
158890ab77SEd Maste  *    notice, this list of conditions and the following disclaimer in the
168890ab77SEd Maste  *    documentation and/or other materials provided with the distribution.
178890ab77SEd Maste  *
188890ab77SEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
198890ab77SEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
208890ab77SEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
218890ab77SEd Maste  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
228890ab77SEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
238890ab77SEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
248890ab77SEd Maste  * OR SERVICES; LOSS OF USE DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
258890ab77SEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
268890ab77SEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
278890ab77SEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
288890ab77SEd Maste  * SUCH DAMAGE.
298890ab77SEd Maste  */
308890ab77SEd Maste #include <sys/cdefs.h>
318890ab77SEd Maste __FBSDID("$FreeBSD$");
328890ab77SEd Maste 
338890ab77SEd Maste /*
348890ab77SEd Maste  * Microchip LAN7430/LAN7431 PCIe to Gigabit Ethernet Controller driver.
358890ab77SEd Maste  *
368890ab77SEd Maste  * Product information:
378890ab77SEd Maste  * LAN7430 https://www.microchip.com/wwwproducts/en/LAN7430
388890ab77SEd Maste  *   - Integrated IEEE 802.3 compliant PHY
398890ab77SEd Maste  * LAN7431 https://www.microchip.com/wwwproducts/en/LAN7431
408890ab77SEd Maste  *   - RGMII Interface
418890ab77SEd Maste  *
428890ab77SEd Maste  * This driver uses the iflib interface and the default 'ukphy' PHY driver.
438890ab77SEd Maste  *
448890ab77SEd Maste  * UNIMPLEMENTED FEATURES
458890ab77SEd Maste  * ----------------------
468890ab77SEd Maste  * A number of features supported by LAN743X device are not yet implemented in
478890ab77SEd Maste  * this driver:
488890ab77SEd Maste  *
498890ab77SEd Maste  * - Multiple (up to 4) RX queues support
508890ab77SEd Maste  *   - Just needs to remove asserts and malloc multiple `rx_ring_data`
518890ab77SEd Maste  *     structs based on ncpus.
528890ab77SEd Maste  * - RX/TX Checksum Offloading support
538890ab77SEd Maste  * - VLAN support
54fcb71d3fSEd Maste  * - Receive Packet Filtering (Multicast Perfect/Hash Address) support
558890ab77SEd Maste  * - Wake on LAN (WoL) support
568890ab77SEd Maste  * - TX LSO support
57fcb71d3fSEd Maste  * - Receive Side Scaling (RSS) support
588890ab77SEd Maste  * - Debugging Capabilities:
598890ab77SEd Maste  *   - Could include MAC statistics and
608890ab77SEd Maste  *     error status registers in sysctl.
618890ab77SEd Maste  */
628890ab77SEd Maste 
638890ab77SEd Maste #include <sys/param.h>
648890ab77SEd Maste #include <sys/bus.h>
658890ab77SEd Maste #include <sys/endian.h>
668890ab77SEd Maste #include <sys/kdb.h>
678890ab77SEd Maste #include <sys/kernel.h>
688890ab77SEd Maste #include <sys/module.h>
698890ab77SEd Maste #include <sys/rman.h>
708890ab77SEd Maste #include <sys/socket.h>
718890ab77SEd Maste #include <sys/sockio.h>
728890ab77SEd Maste #include <machine/bus.h>
738890ab77SEd Maste #include <machine/resource.h>
748890ab77SEd Maste 
758890ab77SEd Maste #include <net/ethernet.h>
768890ab77SEd Maste #include <net/if.h>
778890ab77SEd Maste #include <net/if_var.h>
788890ab77SEd Maste #include <net/if_types.h>
798890ab77SEd Maste #include <net/if_media.h>
808890ab77SEd Maste #include <net/iflib.h>
818890ab77SEd Maste 
828890ab77SEd Maste #include <dev/mgb/if_mgb.h>
838890ab77SEd Maste #include <dev/mii/mii.h>
848890ab77SEd Maste #include <dev/mii/miivar.h>
858890ab77SEd Maste #include <dev/pci/pcireg.h>
868890ab77SEd Maste #include <dev/pci/pcivar.h>
878890ab77SEd Maste 
888890ab77SEd Maste #include "ifdi_if.h"
898890ab77SEd Maste #include "miibus_if.h"
908890ab77SEd Maste 
918890ab77SEd Maste static pci_vendor_info_t mgb_vendor_info_array[] = {
928890ab77SEd Maste 	PVID(MGB_MICROCHIP_VENDOR_ID, MGB_LAN7430_DEVICE_ID,
938890ab77SEd Maste 	    "Microchip LAN7430 PCIe Gigabit Ethernet Controller"),
948890ab77SEd Maste 	PVID(MGB_MICROCHIP_VENDOR_ID, MGB_LAN7431_DEVICE_ID,
958890ab77SEd Maste 	    "Microchip LAN7431 PCIe Gigabit Ethernet Controller"),
968890ab77SEd Maste 	PVID_END
978890ab77SEd Maste };
988890ab77SEd Maste 
998890ab77SEd Maste /* Device methods */
1008890ab77SEd Maste static device_register_t		mgb_register;
1018890ab77SEd Maste 
1028890ab77SEd Maste /* IFLIB methods */
1038890ab77SEd Maste static ifdi_attach_pre_t		mgb_attach_pre;
1048890ab77SEd Maste static ifdi_attach_post_t		mgb_attach_post;
1058890ab77SEd Maste static ifdi_detach_t			mgb_detach;
1068890ab77SEd Maste 
1078890ab77SEd Maste static ifdi_tx_queues_alloc_t		mgb_tx_queues_alloc;
1088890ab77SEd Maste static ifdi_rx_queues_alloc_t		mgb_rx_queues_alloc;
1098890ab77SEd Maste static ifdi_queues_free_t		mgb_queues_free;
1108890ab77SEd Maste 
1118890ab77SEd Maste static ifdi_init_t			mgb_init;
1128890ab77SEd Maste static ifdi_stop_t			mgb_stop;
1138890ab77SEd Maste 
1148890ab77SEd Maste static ifdi_msix_intr_assign_t		mgb_msix_intr_assign;
1158890ab77SEd Maste static ifdi_tx_queue_intr_enable_t	mgb_tx_queue_intr_enable;
1168890ab77SEd Maste static ifdi_rx_queue_intr_enable_t	mgb_rx_queue_intr_enable;
1178890ab77SEd Maste static ifdi_intr_enable_t		mgb_intr_enable_all;
1188890ab77SEd Maste static ifdi_intr_disable_t		mgb_intr_disable_all;
1198890ab77SEd Maste 
1208890ab77SEd Maste /* IFLIB_TXRX methods */
1218890ab77SEd Maste static int				mgb_isc_txd_encap(void *,
1228890ab77SEd Maste 					    if_pkt_info_t);
1238890ab77SEd Maste static void				mgb_isc_txd_flush(void *,
1248890ab77SEd Maste 					    uint16_t, qidx_t);
1258890ab77SEd Maste static int				mgb_isc_txd_credits_update(void *,
1268890ab77SEd Maste 					    uint16_t, bool);
1278890ab77SEd Maste static int				mgb_isc_rxd_available(void *,
1288890ab77SEd Maste 					    uint16_t, qidx_t, qidx_t);
1298890ab77SEd Maste static int				mgb_isc_rxd_pkt_get(void *,
1308890ab77SEd Maste 					    if_rxd_info_t);
1318890ab77SEd Maste static void				mgb_isc_rxd_refill(void *,
1328890ab77SEd Maste 					    if_rxd_update_t);
1338890ab77SEd Maste static void				mgb_isc_rxd_flush(void *,
1348890ab77SEd Maste 					    uint16_t, uint8_t, qidx_t);
1358890ab77SEd Maste 
1368890ab77SEd Maste /* Interrupts */
1378890ab77SEd Maste static driver_filter_t			mgb_legacy_intr;
1388890ab77SEd Maste static driver_filter_t			mgb_admin_intr;
1398890ab77SEd Maste static driver_filter_t			mgb_rxq_intr;
1408890ab77SEd Maste static bool				mgb_intr_test(struct mgb_softc *);
1418890ab77SEd Maste 
1428890ab77SEd Maste /* MII methods */
1438890ab77SEd Maste static miibus_readreg_t			mgb_miibus_readreg;
1448890ab77SEd Maste static miibus_writereg_t		mgb_miibus_writereg;
1458890ab77SEd Maste static miibus_linkchg_t			mgb_miibus_linkchg;
1468890ab77SEd Maste static miibus_statchg_t			mgb_miibus_statchg;
1478890ab77SEd Maste 
1488890ab77SEd Maste static int				mgb_media_change(if_t);
1498890ab77SEd Maste static void				mgb_media_status(if_t,
1508890ab77SEd Maste 					    struct ifmediareq *);
1518890ab77SEd Maste 
1528890ab77SEd Maste /* Helper/Test functions */
1538890ab77SEd Maste static int				mgb_test_bar(struct mgb_softc *);
1548890ab77SEd Maste static int				mgb_alloc_regs(struct mgb_softc *);
1558890ab77SEd Maste static int				mgb_release_regs(struct mgb_softc *);
1568890ab77SEd Maste 
1578890ab77SEd Maste static void				mgb_get_ethaddr(struct mgb_softc *,
1588890ab77SEd Maste 					    struct ether_addr *);
1598890ab77SEd Maste 
1608890ab77SEd Maste static int				mgb_wait_for_bits(struct mgb_softc *,
1618890ab77SEd Maste 					    int, int, int);
1628890ab77SEd Maste 
1638890ab77SEd Maste /* H/W init, reset and teardown helpers */
1648890ab77SEd Maste static int				mgb_hw_init(struct mgb_softc *);
1658890ab77SEd Maste static int				mgb_hw_teardown(struct mgb_softc *);
1668890ab77SEd Maste static int				mgb_hw_reset(struct mgb_softc *);
1678890ab77SEd Maste static int				mgb_mac_init(struct mgb_softc *);
1688890ab77SEd Maste static int				mgb_dmac_reset(struct mgb_softc *);
1698890ab77SEd Maste static int				mgb_phy_reset(struct mgb_softc *);
1708890ab77SEd Maste 
1718890ab77SEd Maste static int				mgb_dma_init(struct mgb_softc *);
1728890ab77SEd Maste static int				mgb_dma_tx_ring_init(struct mgb_softc *,
1738890ab77SEd Maste 					    int);
1748890ab77SEd Maste static int				mgb_dma_rx_ring_init(struct mgb_softc *,
1758890ab77SEd Maste 					    int);
1768890ab77SEd Maste 
1778890ab77SEd Maste static int				mgb_dmac_control(struct mgb_softc *,
1788890ab77SEd Maste 					    int, int, enum mgb_dmac_cmd);
1798890ab77SEd Maste static int				mgb_fct_control(struct mgb_softc *,
1808890ab77SEd Maste 					    int, int, enum mgb_fct_cmd);
1818890ab77SEd Maste 
1828890ab77SEd Maste /*********************************************************************
1838890ab77SEd Maste  *  FreeBSD Device Interface Entry Points
1848890ab77SEd Maste  *********************************************************************/
1858890ab77SEd Maste 
1868890ab77SEd Maste static device_method_t mgb_methods[] = {
1878890ab77SEd Maste 	/* Device interface */
1888890ab77SEd Maste 	DEVMETHOD(device_register,	mgb_register),
1898890ab77SEd Maste 	DEVMETHOD(device_probe,		iflib_device_probe),
1908890ab77SEd Maste 	DEVMETHOD(device_attach,	iflib_device_attach),
1918890ab77SEd Maste 	DEVMETHOD(device_detach,	iflib_device_detach),
1928890ab77SEd Maste 	DEVMETHOD(device_shutdown,	iflib_device_shutdown),
1938890ab77SEd Maste 	DEVMETHOD(device_suspend,	iflib_device_suspend),
1948890ab77SEd Maste 	DEVMETHOD(device_resume,	iflib_device_resume),
1958890ab77SEd Maste 
1968890ab77SEd Maste 	/* MII Interface */
1978890ab77SEd Maste 	DEVMETHOD(miibus_readreg,	mgb_miibus_readreg),
1988890ab77SEd Maste 	DEVMETHOD(miibus_writereg,	mgb_miibus_writereg),
1998890ab77SEd Maste 	DEVMETHOD(miibus_linkchg,	mgb_miibus_linkchg),
2008890ab77SEd Maste 	DEVMETHOD(miibus_statchg,	mgb_miibus_statchg),
2018890ab77SEd Maste 
2028890ab77SEd Maste 	DEVMETHOD_END
2038890ab77SEd Maste };
2048890ab77SEd Maste 
2058890ab77SEd Maste static driver_t mgb_driver = {
2068890ab77SEd Maste 	"mgb", mgb_methods, sizeof(struct mgb_softc)
2078890ab77SEd Maste };
2088890ab77SEd Maste 
2098890ab77SEd Maste devclass_t mgb_devclass;
2108890ab77SEd Maste DRIVER_MODULE(mgb, pci, mgb_driver, mgb_devclass, NULL, NULL);
2118890ab77SEd Maste IFLIB_PNP_INFO(pci, mgb, mgb_vendor_info_array);
2128890ab77SEd Maste MODULE_VERSION(mgb, 1);
2138890ab77SEd Maste 
2148890ab77SEd Maste #if 0 /* MIIBUS_DEBUG */
2158890ab77SEd Maste /* If MIIBUS debug stuff is in attach then order matters. Use below instead. */
2168890ab77SEd Maste DRIVER_MODULE_ORDERED(miibus, mgb, miibus_driver, miibus_devclass, NULL, NULL,
2178890ab77SEd Maste     SI_ORDER_ANY);
2188890ab77SEd Maste #endif /* MIIBUS_DEBUG */
2198890ab77SEd Maste DRIVER_MODULE(miibus, mgb, miibus_driver, miibus_devclass, NULL, NULL);
2208890ab77SEd Maste 
2218890ab77SEd Maste MODULE_DEPEND(mgb, pci, 1, 1, 1);
2228890ab77SEd Maste MODULE_DEPEND(mgb, ether, 1, 1, 1);
2238890ab77SEd Maste MODULE_DEPEND(mgb, miibus, 1, 1, 1);
2248890ab77SEd Maste MODULE_DEPEND(mgb, iflib, 1, 1, 1);
2258890ab77SEd Maste 
2268890ab77SEd Maste static device_method_t mgb_iflib_methods[] = {
2278890ab77SEd Maste 	DEVMETHOD(ifdi_attach_pre, mgb_attach_pre),
2288890ab77SEd Maste 	DEVMETHOD(ifdi_attach_post, mgb_attach_post),
2298890ab77SEd Maste 	DEVMETHOD(ifdi_detach, mgb_detach),
2308890ab77SEd Maste 
2318890ab77SEd Maste 	DEVMETHOD(ifdi_init, mgb_init),
2328890ab77SEd Maste 	DEVMETHOD(ifdi_stop, mgb_stop),
2338890ab77SEd Maste 
2348890ab77SEd Maste 	DEVMETHOD(ifdi_tx_queues_alloc, mgb_tx_queues_alloc),
2358890ab77SEd Maste 	DEVMETHOD(ifdi_rx_queues_alloc, mgb_rx_queues_alloc),
2368890ab77SEd Maste 	DEVMETHOD(ifdi_queues_free, mgb_queues_free),
2378890ab77SEd Maste 
2388890ab77SEd Maste 	DEVMETHOD(ifdi_msix_intr_assign, mgb_msix_intr_assign),
2398890ab77SEd Maste 	DEVMETHOD(ifdi_tx_queue_intr_enable, mgb_tx_queue_intr_enable),
2408890ab77SEd Maste 	DEVMETHOD(ifdi_rx_queue_intr_enable, mgb_rx_queue_intr_enable),
2418890ab77SEd Maste 	DEVMETHOD(ifdi_intr_enable, mgb_intr_enable_all),
2428890ab77SEd Maste 	DEVMETHOD(ifdi_intr_disable, mgb_intr_disable_all),
2438890ab77SEd Maste 
2448890ab77SEd Maste 
2458890ab77SEd Maste #if 0 /* Not yet implemented IFLIB methods */
2468890ab77SEd Maste 	/*
2478890ab77SEd Maste 	 * Set multicast addresses, mtu and promiscuous mode
2488890ab77SEd Maste 	 */
2498890ab77SEd Maste 	DEVMETHOD(ifdi_multi_set, mgb_multi_set),
2508890ab77SEd Maste 	DEVMETHOD(ifdi_mtu_set, mgb_mtu_set),
2518890ab77SEd Maste 	DEVMETHOD(ifdi_promisc_set, mgb_promisc_set),
2528890ab77SEd Maste 
2538890ab77SEd Maste 	/*
2548890ab77SEd Maste 	 * Needed for VLAN support
2558890ab77SEd Maste 	 */
2568890ab77SEd Maste 	DEVMETHOD(ifdi_vlan_register, mgb_vlan_register),
2578890ab77SEd Maste 	DEVMETHOD(ifdi_vlan_unregister, mgb_vlan_unregister),
2588890ab77SEd Maste 
2598890ab77SEd Maste 	/*
2608890ab77SEd Maste 	 * Needed for WOL support
2618890ab77SEd Maste 	 * at the very least.
2628890ab77SEd Maste 	 */
2638890ab77SEd Maste 	DEVMETHOD(ifdi_shutdown, mgb_shutdown),
2648890ab77SEd Maste 	DEVMETHOD(ifdi_suspend, mgb_suspend),
2658890ab77SEd Maste 	DEVMETHOD(ifdi_resume, mgb_resume),
2668890ab77SEd Maste #endif /* UNUSED_IFLIB_METHODS */
2678890ab77SEd Maste 	DEVMETHOD_END
2688890ab77SEd Maste };
2698890ab77SEd Maste 
2708890ab77SEd Maste static driver_t mgb_iflib_driver = {
2718890ab77SEd Maste 	"mgb", mgb_iflib_methods, sizeof(struct mgb_softc)
2728890ab77SEd Maste };
2738890ab77SEd Maste 
2748890ab77SEd Maste struct if_txrx mgb_txrx  = {
2758890ab77SEd Maste 	.ift_txd_encap = mgb_isc_txd_encap,
2768890ab77SEd Maste 	.ift_txd_flush = mgb_isc_txd_flush,
2778890ab77SEd Maste 	.ift_txd_credits_update = mgb_isc_txd_credits_update,
2788890ab77SEd Maste 	.ift_rxd_available = mgb_isc_rxd_available,
2798890ab77SEd Maste 	.ift_rxd_pkt_get = mgb_isc_rxd_pkt_get,
2808890ab77SEd Maste 	.ift_rxd_refill = mgb_isc_rxd_refill,
2818890ab77SEd Maste 	.ift_rxd_flush = mgb_isc_rxd_flush,
2828890ab77SEd Maste 
2838890ab77SEd Maste 	.ift_legacy_intr = mgb_legacy_intr
2848890ab77SEd Maste };
2858890ab77SEd Maste 
2868890ab77SEd Maste struct if_shared_ctx mgb_sctx_init = {
2878890ab77SEd Maste 	.isc_magic = IFLIB_MAGIC,
2888890ab77SEd Maste 
2898890ab77SEd Maste 	.isc_q_align = PAGE_SIZE,
2908890ab77SEd Maste 	.isc_admin_intrcnt = 1,
2918890ab77SEd Maste 	.isc_flags = IFLIB_DRIVER_MEDIA /* | IFLIB_HAS_RXCQ | IFLIB_HAS_TXCQ*/,
2928890ab77SEd Maste 
2938890ab77SEd Maste 	.isc_vendor_info = mgb_vendor_info_array,
2948890ab77SEd Maste 	.isc_driver_version = "1",
2958890ab77SEd Maste 	.isc_driver = &mgb_iflib_driver,
2968890ab77SEd Maste 	/* 2 queues per set for TX and RX (ring queue, head writeback queue) */
2978890ab77SEd Maste 	.isc_ntxqs = 2,
2988890ab77SEd Maste 
2998890ab77SEd Maste 	.isc_tx_maxsize = MGB_DMA_MAXSEGS  * MCLBYTES,
3008890ab77SEd Maste 	/* .isc_tx_nsegments = MGB_DMA_MAXSEGS, */
3018890ab77SEd Maste 	.isc_tx_maxsegsize = MCLBYTES,
3028890ab77SEd Maste 
3038890ab77SEd Maste 	.isc_ntxd_min = {1, 1}, /* Will want to make this bigger */
3048890ab77SEd Maste 	.isc_ntxd_max = {MGB_DMA_RING_SIZE, 1},
3058890ab77SEd Maste 	.isc_ntxd_default = {MGB_DMA_RING_SIZE, 1},
3068890ab77SEd Maste 
3078890ab77SEd Maste 	.isc_nrxqs = 2,
3088890ab77SEd Maste 
3098890ab77SEd Maste 	.isc_rx_maxsize = MCLBYTES,
3108890ab77SEd Maste 	.isc_rx_nsegments = 1,
3118890ab77SEd Maste 	.isc_rx_maxsegsize = MCLBYTES,
3128890ab77SEd Maste 
3138890ab77SEd Maste 	.isc_nrxd_min = {1, 1}, /* Will want to make this bigger */
3148890ab77SEd Maste 	.isc_nrxd_max = {MGB_DMA_RING_SIZE, 1},
3158890ab77SEd Maste 	.isc_nrxd_default = {MGB_DMA_RING_SIZE, 1},
3168890ab77SEd Maste 
3178890ab77SEd Maste 	.isc_nfl = 1, /*one free list since there is only one queue */
3188890ab77SEd Maste #if 0 /* UNUSED_CTX */
3198890ab77SEd Maste 
3208890ab77SEd Maste 	.isc_tso_maxsize = MGB_TSO_MAXSIZE + sizeof(struct ether_vlan_header),
3218890ab77SEd Maste 	.isc_tso_maxsegsize = MGB_TX_MAXSEGSIZE,
3228890ab77SEd Maste #endif /* UNUSED_CTX */
3238890ab77SEd Maste };
3248890ab77SEd Maste 
3258890ab77SEd Maste /*********************************************************************/
3268890ab77SEd Maste 
3278890ab77SEd Maste 
3288890ab77SEd Maste static void *
3298890ab77SEd Maste mgb_register(device_t dev)
3308890ab77SEd Maste {
3318890ab77SEd Maste 
3328890ab77SEd Maste 	return (&mgb_sctx_init);
3338890ab77SEd Maste }
3348890ab77SEd Maste 
3358890ab77SEd Maste static int
3368890ab77SEd Maste mgb_attach_pre(if_ctx_t ctx)
3378890ab77SEd Maste {
3388890ab77SEd Maste 	struct mgb_softc *sc;
3398890ab77SEd Maste 	if_softc_ctx_t scctx;
3408890ab77SEd Maste 	int error, phyaddr, rid;
3418890ab77SEd Maste 	struct ether_addr hwaddr;
3428890ab77SEd Maste 	struct mii_data *miid;
3438890ab77SEd Maste 
3448890ab77SEd Maste 	sc = iflib_get_softc(ctx);
3458890ab77SEd Maste 	sc->ctx = ctx;
3468890ab77SEd Maste 	sc->dev = iflib_get_dev(ctx);
3478890ab77SEd Maste 	scctx = iflib_get_softc_ctx(ctx);
3488890ab77SEd Maste 
3498890ab77SEd Maste 	/* IFLIB required setup */
3508890ab77SEd Maste 	scctx->isc_txrx = &mgb_txrx;
3518890ab77SEd Maste 	scctx->isc_tx_nsegments = MGB_DMA_MAXSEGS;
3528890ab77SEd Maste 	/* Ring desc queues */
3538890ab77SEd Maste 	scctx->isc_txqsizes[0] = sizeof(struct mgb_ring_desc) *
3548890ab77SEd Maste 	    scctx->isc_ntxd[0];
3558890ab77SEd Maste 	scctx->isc_rxqsizes[0] = sizeof(struct mgb_ring_desc) *
3568890ab77SEd Maste 	    scctx->isc_nrxd[0];
3578890ab77SEd Maste 
3588890ab77SEd Maste 	/* Head WB queues */
3598890ab77SEd Maste 	scctx->isc_txqsizes[1] = sizeof(uint32_t) * scctx->isc_ntxd[1];
3608890ab77SEd Maste 	scctx->isc_rxqsizes[1] = sizeof(uint32_t) * scctx->isc_nrxd[1];
3618890ab77SEd Maste 
3628890ab77SEd Maste 	/* XXX: Must have 1 txqset, but can have up to 4 rxqsets */
3638890ab77SEd Maste 	scctx->isc_nrxqsets = 1;
3648890ab77SEd Maste 	scctx->isc_ntxqsets = 1;
3658890ab77SEd Maste 
3668890ab77SEd Maste 	/* scctx->isc_tx_csum_flags = (CSUM_TCP | CSUM_UDP) |
3678890ab77SEd Maste 	    (CSUM_TCP_IPV6 | CSUM_UDP_IPV6) | CSUM_TSO */
3688890ab77SEd Maste 	scctx->isc_tx_csum_flags = 0;
3698890ab77SEd Maste 	scctx->isc_capabilities = scctx->isc_capenable = 0;
3708890ab77SEd Maste #if 0
3718890ab77SEd Maste 	/*
3728890ab77SEd Maste 	 * CSUM, TSO and VLAN support are TBD
3738890ab77SEd Maste 	 */
3748890ab77SEd Maste 	    IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6 |
3758890ab77SEd Maste 	    IFCAP_TSO4 | IFCAP_TSO6 |
3768890ab77SEd Maste 	    IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 |
3778890ab77SEd Maste 	    IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
3788890ab77SEd Maste 	    IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO |
3798890ab77SEd Maste 	    IFCAP_JUMBO_MTU;
3808890ab77SEd Maste 	scctx->isc_capabilities |= IFCAP_LRO | IFCAP_VLAN_HWFILTER;
3818890ab77SEd Maste #endif
3828890ab77SEd Maste 
3838890ab77SEd Maste 	/* get the BAR */
3848890ab77SEd Maste 	error = mgb_alloc_regs(sc);
3858890ab77SEd Maste 	if (error != 0) {
3868890ab77SEd Maste 		device_printf(sc->dev,
3878890ab77SEd Maste 		    "Unable to allocate bus resource: registers.\n");
3888890ab77SEd Maste 		goto fail;
3898890ab77SEd Maste 	}
3908890ab77SEd Maste 
3918890ab77SEd Maste 	error = mgb_test_bar(sc);
3928890ab77SEd Maste 	if (error != 0)
3938890ab77SEd Maste 		goto fail;
3948890ab77SEd Maste 
3958890ab77SEd Maste 	error = mgb_hw_init(sc);
3968890ab77SEd Maste 	if (error != 0) {
3978890ab77SEd Maste 		device_printf(sc->dev,
3988890ab77SEd Maste 		    "MGB device init failed. (err: %d)\n", error);
3998890ab77SEd Maste 		goto fail;
4008890ab77SEd Maste 	}
4018890ab77SEd Maste 
4028890ab77SEd Maste 	switch (pci_get_device(sc->dev))
4038890ab77SEd Maste 	{
4048890ab77SEd Maste 	case MGB_LAN7430_DEVICE_ID:
4058890ab77SEd Maste 		phyaddr = 1;
4068890ab77SEd Maste 		break;
4078890ab77SEd Maste 	case MGB_LAN7431_DEVICE_ID:
4088890ab77SEd Maste 	default:
4098890ab77SEd Maste 		phyaddr = MII_PHY_ANY;
4108890ab77SEd Maste 		break;
4118890ab77SEd Maste 	}
4128890ab77SEd Maste 
4138890ab77SEd Maste 	/* XXX: Would be nice(r) if locked methods were here */
4148890ab77SEd Maste 	error = mii_attach(sc->dev, &sc->miibus, iflib_get_ifp(ctx),
4158890ab77SEd Maste 	    mgb_media_change, mgb_media_status,
4168890ab77SEd Maste 	    BMSR_DEFCAPMASK, phyaddr, MII_OFFSET_ANY, MIIF_DOPAUSE);
4178890ab77SEd Maste 	if (error != 0) {
4188890ab77SEd Maste 		device_printf(sc->dev, "Failed to attach MII interface\n");
4198890ab77SEd Maste 		goto fail;
4208890ab77SEd Maste 	}
4218890ab77SEd Maste 
4228890ab77SEd Maste 	miid = device_get_softc(sc->miibus);
4238890ab77SEd Maste 	scctx->isc_media = &miid->mii_media;
4248890ab77SEd Maste 
4258890ab77SEd Maste 	scctx->isc_msix_bar = pci_msix_table_bar(sc->dev);
4268890ab77SEd Maste 	/** Setup PBA BAR **/
4278890ab77SEd Maste 	rid = pci_msix_pba_bar(sc->dev);
4288890ab77SEd Maste 	if (rid != scctx->isc_msix_bar) {
4298890ab77SEd Maste 		sc->pba = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
4308890ab77SEd Maste 		    &rid, RF_ACTIVE);
4318890ab77SEd Maste 		if (sc->pba == NULL) {
4328890ab77SEd Maste 			error = ENXIO;
4338890ab77SEd Maste 			device_printf(sc->dev, "Failed to setup PBA BAR\n");
4348890ab77SEd Maste 			goto fail;
4358890ab77SEd Maste 		}
4368890ab77SEd Maste 	}
4378890ab77SEd Maste 
4388890ab77SEd Maste 	mgb_get_ethaddr(sc, &hwaddr);
4398890ab77SEd Maste 	if (ETHER_IS_BROADCAST(hwaddr.octet) ||
4408890ab77SEd Maste 	    ETHER_IS_MULTICAST(hwaddr.octet) ||
4418890ab77SEd Maste 	    ETHER_IS_ZERO(hwaddr.octet))
4428890ab77SEd Maste 		ether_gen_addr(iflib_get_ifp(ctx), &hwaddr);
4438890ab77SEd Maste 
4448890ab77SEd Maste 	/*
4458890ab77SEd Maste 	 * XXX: if the MAC address was generated the linux driver
4468890ab77SEd Maste 	 * writes it back to the device.
4478890ab77SEd Maste 	 */
4488890ab77SEd Maste 	iflib_set_mac(ctx, hwaddr.octet);
4498890ab77SEd Maste 
4508890ab77SEd Maste 	/* Map all vectors to vector 0 (admin interrupts) by default. */
4518890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_VEC_RX_MAP, 0);
4528890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_VEC_TX_MAP, 0);
4538890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_VEC_OTHER_MAP, 0);
4548890ab77SEd Maste 
4558890ab77SEd Maste 	return (0);
4568890ab77SEd Maste 
4578890ab77SEd Maste fail:
4588890ab77SEd Maste 	mgb_detach(ctx);
4598890ab77SEd Maste 	return (error);
4608890ab77SEd Maste }
4618890ab77SEd Maste 
4628890ab77SEd Maste static int
4638890ab77SEd Maste mgb_attach_post(if_ctx_t ctx)
4648890ab77SEd Maste {
4658890ab77SEd Maste 	struct mgb_softc *sc;
4668890ab77SEd Maste 
4678890ab77SEd Maste 	sc = iflib_get_softc(ctx);
4688890ab77SEd Maste 
4698890ab77SEd Maste 	device_printf(sc->dev, "Interrupt test: %s\n",
4708890ab77SEd Maste 	    (mgb_intr_test(sc) ? "PASS" : "FAIL"));
4718890ab77SEd Maste 
4728890ab77SEd Maste 	return (0);
4738890ab77SEd Maste }
4748890ab77SEd Maste 
4758890ab77SEd Maste static int
4768890ab77SEd Maste mgb_detach(if_ctx_t ctx)
4778890ab77SEd Maste {
4788890ab77SEd Maste 	struct mgb_softc *sc;
4798890ab77SEd Maste 	int error;
4808890ab77SEd Maste 
4818890ab77SEd Maste 	sc = iflib_get_softc(ctx);
4828890ab77SEd Maste 
4838890ab77SEd Maste 	/* XXX: Should report errors but still detach everything. */
4848890ab77SEd Maste 	error = mgb_hw_teardown(sc);
4858890ab77SEd Maste 
4868890ab77SEd Maste 	/* Release IRQs */
4878890ab77SEd Maste 	iflib_irq_free(ctx, &sc->rx_irq);
4888890ab77SEd Maste 	iflib_irq_free(ctx, &sc->admin_irq);
4898890ab77SEd Maste 
4908890ab77SEd Maste 	if (sc->miibus != NULL)
4918890ab77SEd Maste 		device_delete_child(sc->dev, sc->miibus);
4928890ab77SEd Maste 
4938890ab77SEd Maste 	if (sc->pba != NULL)
4948890ab77SEd Maste 		error = bus_release_resource(sc->dev, SYS_RES_MEMORY,
4958890ab77SEd Maste 		    rman_get_rid(sc->pba), sc->pba);
4968890ab77SEd Maste 	sc->pba = NULL;
4978890ab77SEd Maste 
4988890ab77SEd Maste 	error = mgb_release_regs(sc);
4998890ab77SEd Maste 
5008890ab77SEd Maste 	return (error);
5018890ab77SEd Maste }
5028890ab77SEd Maste 
5038890ab77SEd Maste static int
5048890ab77SEd Maste mgb_media_change(if_t ifp)
5058890ab77SEd Maste {
5068890ab77SEd Maste 	struct mii_data *miid;
5078890ab77SEd Maste 	struct mii_softc *miisc;
5088890ab77SEd Maste 	struct mgb_softc *sc;
5098890ab77SEd Maste 	if_ctx_t ctx;
5108890ab77SEd Maste 	int needs_reset;
5118890ab77SEd Maste 
5128890ab77SEd Maste 	ctx = if_getsoftc(ifp);
5138890ab77SEd Maste 	sc = iflib_get_softc(ctx);
5148890ab77SEd Maste 	miid = device_get_softc(sc->miibus);
5158890ab77SEd Maste 	LIST_FOREACH(miisc, &miid->mii_phys, mii_list)
5168890ab77SEd Maste 		PHY_RESET(miisc);
5178890ab77SEd Maste 
5188890ab77SEd Maste 	needs_reset = mii_mediachg(miid);
5198890ab77SEd Maste 	if (needs_reset != 0)
5208890ab77SEd Maste 		ifp->if_init(ctx);
5218890ab77SEd Maste 	return (needs_reset);
5228890ab77SEd Maste }
5238890ab77SEd Maste 
5248890ab77SEd Maste static void
5258890ab77SEd Maste mgb_media_status(if_t ifp, struct ifmediareq *ifmr)
5268890ab77SEd Maste {
5278890ab77SEd Maste 	struct mgb_softc *sc;
5288890ab77SEd Maste 	struct mii_data *miid;
5298890ab77SEd Maste 
5308890ab77SEd Maste 	sc = iflib_get_softc(if_getsoftc(ifp));
5318890ab77SEd Maste 	miid = device_get_softc(sc->miibus);
5328890ab77SEd Maste 	if ((if_getflags(ifp) & IFF_UP) == 0)
5338890ab77SEd Maste 		return;
5348890ab77SEd Maste 
5358890ab77SEd Maste 	mii_pollstat(miid);
5368890ab77SEd Maste 	ifmr->ifm_active = miid->mii_media_active;
5378890ab77SEd Maste 	ifmr->ifm_status = miid->mii_media_status;
5388890ab77SEd Maste }
5398890ab77SEd Maste 
5408890ab77SEd Maste static int
5418890ab77SEd Maste mgb_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs,
5428890ab77SEd Maste     int ntxqsets)
5438890ab77SEd Maste {
5448890ab77SEd Maste 	struct mgb_softc *sc;
5458890ab77SEd Maste 	struct mgb_ring_data *rdata;
5468890ab77SEd Maste 	int q;
5478890ab77SEd Maste 
5488890ab77SEd Maste 	sc = iflib_get_softc(ctx);
5498890ab77SEd Maste 	KASSERT(ntxqsets == 1, ("ntxqsets = %d", ntxqsets));
5508890ab77SEd Maste 	rdata = &sc->tx_ring_data;
5518890ab77SEd Maste 	for (q = 0; q < ntxqsets; q++) {
5528890ab77SEd Maste 		KASSERT(ntxqs == 2, ("ntxqs = %d", ntxqs));
5538890ab77SEd Maste 		/* Ring */
5548890ab77SEd Maste 		rdata->ring = (struct mgb_ring_desc *) vaddrs[q * ntxqs + 0];
5558890ab77SEd Maste 		rdata->ring_bus_addr = paddrs[q * ntxqs + 0];
5568890ab77SEd Maste 
5578890ab77SEd Maste 		/* Head WB */
5588890ab77SEd Maste 		rdata->head_wb = (uint32_t *) vaddrs[q * ntxqs + 1];
5598890ab77SEd Maste 		rdata->head_wb_bus_addr = paddrs[q * ntxqs + 1];
5608890ab77SEd Maste 	}
5618890ab77SEd Maste 	return 0;
5628890ab77SEd Maste }
5638890ab77SEd Maste 
5648890ab77SEd Maste static int
5658890ab77SEd Maste mgb_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrxqs,
5668890ab77SEd Maste     int nrxqsets)
5678890ab77SEd Maste {
5688890ab77SEd Maste 	struct mgb_softc *sc;
5698890ab77SEd Maste 	struct mgb_ring_data *rdata;
5708890ab77SEd Maste 	int q;
5718890ab77SEd Maste 
5728890ab77SEd Maste 	sc = iflib_get_softc(ctx);
5738890ab77SEd Maste 	KASSERT(nrxqsets == 1, ("nrxqsets = %d", nrxqsets));
5748890ab77SEd Maste 	rdata = &sc->rx_ring_data;
5758890ab77SEd Maste 	for (q = 0; q < nrxqsets; q++) {
5768890ab77SEd Maste 		KASSERT(nrxqs == 2, ("nrxqs = %d", nrxqs));
5778890ab77SEd Maste 		/* Ring */
5788890ab77SEd Maste 		rdata->ring = (struct mgb_ring_desc *) vaddrs[q * nrxqs + 0];
5798890ab77SEd Maste 		rdata->ring_bus_addr = paddrs[q * nrxqs + 0];
5808890ab77SEd Maste 
5818890ab77SEd Maste 		/* Head WB */
5828890ab77SEd Maste 		rdata->head_wb = (uint32_t *) vaddrs[q * nrxqs + 1];
5838890ab77SEd Maste 		rdata->head_wb_bus_addr = paddrs[q * nrxqs + 1];
5848890ab77SEd Maste 	}
5858890ab77SEd Maste 	return 0;
5868890ab77SEd Maste }
5878890ab77SEd Maste 
5888890ab77SEd Maste static void
5898890ab77SEd Maste mgb_queues_free(if_ctx_t ctx)
5908890ab77SEd Maste {
5918890ab77SEd Maste 	struct mgb_softc *sc;
5928890ab77SEd Maste 
5938890ab77SEd Maste 	sc = iflib_get_softc(ctx);
5948890ab77SEd Maste 
5958890ab77SEd Maste 	memset(&sc->rx_ring_data, 0, sizeof(struct mgb_ring_data));
5968890ab77SEd Maste 	memset(&sc->tx_ring_data, 0, sizeof(struct mgb_ring_data));
5978890ab77SEd Maste }
5988890ab77SEd Maste 
5998890ab77SEd Maste static void
6008890ab77SEd Maste mgb_init(if_ctx_t ctx)
6018890ab77SEd Maste {
6028890ab77SEd Maste 	struct mgb_softc *sc;
6038890ab77SEd Maste 	struct mii_data *miid;
6048890ab77SEd Maste 	int error;
6058890ab77SEd Maste 
6068890ab77SEd Maste 	sc = iflib_get_softc(ctx);
6078890ab77SEd Maste 	miid = device_get_softc(sc->miibus);
6088890ab77SEd Maste 	device_printf(sc->dev, "running init ...\n");
6098890ab77SEd Maste 
6108890ab77SEd Maste 	mgb_dma_init(sc);
6118890ab77SEd Maste 
6128890ab77SEd Maste 	/* XXX: Turn off perfect filtering, turn on (broad|multi|uni)cast rx */
6138890ab77SEd Maste 	CSR_CLEAR_REG(sc, MGB_RFE_CTL, MGB_RFE_ALLOW_PERFECT_FILTER);
6148890ab77SEd Maste 	CSR_UPDATE_REG(sc, MGB_RFE_CTL,
6158890ab77SEd Maste 	    MGB_RFE_ALLOW_BROADCAST |
6168890ab77SEd Maste 	    MGB_RFE_ALLOW_UNICAST |
6178890ab77SEd Maste 	    MGB_RFE_ALLOW_UNICAST);
6188890ab77SEd Maste 
6198890ab77SEd Maste 	error = mii_mediachg(miid);
6208890ab77SEd Maste 	KASSERT(!error, ("mii_mediachg returned: %d", error));
6218890ab77SEd Maste }
6228890ab77SEd Maste 
6238890ab77SEd Maste #ifdef DEBUG
6248890ab77SEd Maste static void
6258890ab77SEd Maste mgb_dump_some_stats(struct mgb_softc *sc)
6268890ab77SEd Maste {
6278890ab77SEd Maste 	int i;
6288890ab77SEd Maste 	int first_stat = 0x1200;
6298890ab77SEd Maste 	int last_stat = 0x12FC;
6308890ab77SEd Maste 
6318890ab77SEd Maste 	for (i = first_stat; i <= last_stat; i += 4)
6328890ab77SEd Maste 		if (CSR_READ_REG(sc, i) != 0)
6338890ab77SEd Maste 			device_printf(sc->dev, "0x%04x: 0x%08x\n", i,
6348890ab77SEd Maste 			    CSR_READ_REG(sc, i));
6358890ab77SEd Maste 	char *stat_names[] = {
6368890ab77SEd Maste 		"MAC_ERR_STS ",
6378890ab77SEd Maste 		"FCT_INT_STS ",
6388890ab77SEd Maste 		"DMAC_CFG ",
6398890ab77SEd Maste 		"DMAC_CMD ",
6408890ab77SEd Maste 		"DMAC_INT_STS ",
6418890ab77SEd Maste 		"DMAC_INT_EN ",
6428890ab77SEd Maste 		"DMAC_RX_ERR_STS0 ",
6438890ab77SEd Maste 		"DMAC_RX_ERR_STS1 ",
6448890ab77SEd Maste 		"DMAC_RX_ERR_STS2 ",
6458890ab77SEd Maste 		"DMAC_RX_ERR_STS3 ",
6468890ab77SEd Maste 		"INT_STS ",
6478890ab77SEd Maste 		"INT_EN ",
6488890ab77SEd Maste 		"INT_VEC_EN ",
6498890ab77SEd Maste 		"INT_VEC_MAP0 ",
6508890ab77SEd Maste 		"INT_VEC_MAP1 ",
6518890ab77SEd Maste 		"INT_VEC_MAP2 ",
6528890ab77SEd Maste 		"TX_HEAD0",
6538890ab77SEd Maste 		"TX_TAIL0",
6548890ab77SEd Maste 		"DMAC_TX_ERR_STS0 ",
6558890ab77SEd Maste 		NULL
6568890ab77SEd Maste 	};
6578890ab77SEd Maste 	int stats[] = {
6588890ab77SEd Maste 		0x114,
6598890ab77SEd Maste 		0xA0,
6608890ab77SEd Maste 		0xC00,
6618890ab77SEd Maste 		0xC0C,
6628890ab77SEd Maste 		0xC10,
6638890ab77SEd Maste 		0xC14,
6648890ab77SEd Maste 		0xC60,
6658890ab77SEd Maste 		0xCA0,
6668890ab77SEd Maste 		0xCE0,
6678890ab77SEd Maste 		0xD20,
6688890ab77SEd Maste 		0x780,
6698890ab77SEd Maste 		0x788,
6708890ab77SEd Maste 		0x794,
6718890ab77SEd Maste 		0x7A0,
6728890ab77SEd Maste 		0x7A4,
6738890ab77SEd Maste 		0x780,
6748890ab77SEd Maste 		0xD58,
6758890ab77SEd Maste 		0xD5C,
6768890ab77SEd Maste 		0xD60,
6778890ab77SEd Maste 		0x0
6788890ab77SEd Maste 	};
6798890ab77SEd Maste 	i = 0;
6808890ab77SEd Maste 	printf("==============================\n");
6818890ab77SEd Maste 	while (stats[i++])
6828890ab77SEd Maste 		device_printf(sc->dev, "%s at offset 0x%04x = 0x%08x\n",
6838890ab77SEd Maste 		    stat_names[i - 1], stats[i - 1],
6848890ab77SEd Maste 		    CSR_READ_REG(sc, stats[i - 1]));
6858890ab77SEd Maste 	printf("==== TX RING DESCS ====\n");
6868890ab77SEd Maste 	for (i = 0; i < MGB_DMA_RING_SIZE; i++)
6878890ab77SEd Maste 		device_printf(sc->dev, "ring[%d].data0=0x%08x\n"
6888890ab77SEd Maste 		    "ring[%d].data1=0x%08x\n"
6898890ab77SEd Maste 		    "ring[%d].data2=0x%08x\n"
6908890ab77SEd Maste 		    "ring[%d].data3=0x%08x\n",
6918890ab77SEd Maste 		    i, sc->tx_ring_data.ring[i].ctl,
6928890ab77SEd Maste 		    i, sc->tx_ring_data.ring[i].addr.low,
6938890ab77SEd Maste 		    i, sc->tx_ring_data.ring[i].addr.high,
6948890ab77SEd Maste 		    i, sc->tx_ring_data.ring[i].sts);
6958890ab77SEd Maste 	device_printf(sc->dev, "==== DUMP_TX_DMA_RAM ====\n");
6968890ab77SEd Maste 	int i;
6978890ab77SEd Maste 	CSR_WRITE_REG(sc, 0x24, 0xF); // DP_SEL & TX_RAM_0
6988890ab77SEd Maste 	for (i = 0; i < 128; i++) {
6998890ab77SEd Maste 		CSR_WRITE_REG(sc, 0x2C, i); // DP_ADDR
7008890ab77SEd Maste 
7018890ab77SEd Maste 		CSR_WRITE_REG(sc, 0x28, 0); // DP_CMD
7028890ab77SEd Maste 
7038890ab77SEd Maste 		while ((CSR_READ_REG(sc, 0x24) & 0x80000000) == 0) // DP_SEL & READY
7048890ab77SEd Maste 			DELAY(1000);
7058890ab77SEd Maste 
7068890ab77SEd Maste 		device_printf(sc->dev, "DMAC_TX_RAM_0[%u]=%08x\n", i,
7078890ab77SEd Maste 		    CSR_READ_REG(sc, 0x30)); // DP_DATA
7088890ab77SEd Maste 	}
7098890ab77SEd Maste }
7108890ab77SEd Maste #endif
7118890ab77SEd Maste 
7128890ab77SEd Maste static void
7138890ab77SEd Maste mgb_stop(if_ctx_t ctx)
7148890ab77SEd Maste {
7158890ab77SEd Maste 	struct mgb_softc *sc ;
7168890ab77SEd Maste 	if_softc_ctx_t scctx;
7178890ab77SEd Maste 	int i;
7188890ab77SEd Maste 
7198890ab77SEd Maste 	sc = iflib_get_softc(ctx);
7208890ab77SEd Maste 	scctx = iflib_get_softc_ctx(ctx);
7218890ab77SEd Maste 
7228890ab77SEd Maste 	/* XXX: Could potentially timeout */
7238890ab77SEd Maste 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
7248890ab77SEd Maste 		mgb_dmac_control(sc, MGB_DMAC_RX_START, 0, DMAC_STOP);
7258890ab77SEd Maste 		mgb_fct_control(sc, MGB_FCT_RX_CTL, 0, FCT_DISABLE);
7268890ab77SEd Maste 	}
7278890ab77SEd Maste 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
7288890ab77SEd Maste 		mgb_dmac_control(sc, MGB_DMAC_TX_START, 0, DMAC_STOP);
7298890ab77SEd Maste 		mgb_fct_control(sc, MGB_FCT_TX_CTL, 0, FCT_DISABLE);
7308890ab77SEd Maste 	}
7318890ab77SEd Maste }
7328890ab77SEd Maste 
7338890ab77SEd Maste static int
7348890ab77SEd Maste mgb_legacy_intr(void *xsc)
7358890ab77SEd Maste {
7368890ab77SEd Maste 	struct mgb_softc *sc;
7378890ab77SEd Maste 
7388890ab77SEd Maste 	sc = xsc;
7398890ab77SEd Maste 	iflib_admin_intr_deferred(sc->ctx);
7408890ab77SEd Maste 	return (FILTER_HANDLED);
7418890ab77SEd Maste }
7428890ab77SEd Maste 
7438890ab77SEd Maste static int
7448890ab77SEd Maste mgb_rxq_intr(void *xsc)
7458890ab77SEd Maste {
7468890ab77SEd Maste 	struct mgb_softc *sc;
7478890ab77SEd Maste 	if_softc_ctx_t scctx;
7488890ab77SEd Maste 	uint32_t intr_sts, intr_en;
7498890ab77SEd Maste 	int qidx;
7508890ab77SEd Maste 
7518890ab77SEd Maste 	sc = xsc;
7528890ab77SEd Maste 	scctx = iflib_get_softc_ctx(sc->ctx);
7538890ab77SEd Maste 
7548890ab77SEd Maste 	intr_sts = CSR_READ_REG(sc, MGB_INTR_STS);
7558890ab77SEd Maste 	intr_en = CSR_READ_REG(sc, MGB_INTR_ENBL_SET);
7568890ab77SEd Maste 	intr_sts &= intr_en;
7578890ab77SEd Maste 
7588890ab77SEd Maste 	for (qidx = 0; qidx < scctx->isc_nrxqsets; qidx++) {
7598890ab77SEd Maste 		if ((intr_sts & MGB_INTR_STS_RX(qidx))){
7608890ab77SEd Maste 			CSR_WRITE_REG(sc, MGB_INTR_ENBL_CLR,
7618890ab77SEd Maste 			    MGB_INTR_STS_RX(qidx));
7628890ab77SEd Maste 			CSR_WRITE_REG(sc, MGB_INTR_STS, MGB_INTR_STS_RX(qidx));
7638890ab77SEd Maste 		}
7648890ab77SEd Maste 	}
7658890ab77SEd Maste 	return (FILTER_SCHEDULE_THREAD);
7668890ab77SEd Maste }
7678890ab77SEd Maste 
7688890ab77SEd Maste static int
7698890ab77SEd Maste mgb_admin_intr(void *xsc)
7708890ab77SEd Maste {
7718890ab77SEd Maste 	struct mgb_softc *sc;
7728890ab77SEd Maste 	if_softc_ctx_t scctx;
7738890ab77SEd Maste 	uint32_t intr_sts, intr_en;
7748890ab77SEd Maste 	int qidx;
7758890ab77SEd Maste 
7768890ab77SEd Maste 	sc = xsc;
7778890ab77SEd Maste 	scctx = iflib_get_softc_ctx(sc->ctx);
7788890ab77SEd Maste 
7798890ab77SEd Maste 	intr_sts = CSR_READ_REG(sc, MGB_INTR_STS);
7808890ab77SEd Maste 	intr_en = CSR_READ_REG(sc, MGB_INTR_ENBL_SET);
7818890ab77SEd Maste 	intr_sts &= intr_en;
7828890ab77SEd Maste 
7838890ab77SEd Maste 	/*
7848890ab77SEd Maste 	 * NOTE: Debugging printfs here
7858890ab77SEd Maste 	 * will likely cause interrupt test failure.
7868890ab77SEd Maste 	 */
7878890ab77SEd Maste 
7888890ab77SEd Maste 	/* TODO: shouldn't continue if suspended */
7898890ab77SEd Maste 	if ((intr_sts & MGB_INTR_STS_ANY) == 0)
7908890ab77SEd Maste 	{
7918890ab77SEd Maste 		device_printf(sc->dev, "non-mgb interrupt triggered.\n");
7928890ab77SEd Maste 		return (FILTER_SCHEDULE_THREAD);
7938890ab77SEd Maste 	}
7948890ab77SEd Maste 	if ((intr_sts &  MGB_INTR_STS_TEST) != 0)
7958890ab77SEd Maste 	{
7968890ab77SEd Maste 		sc->isr_test_flag = true;
7978890ab77SEd Maste 		CSR_WRITE_REG(sc, MGB_INTR_STS, MGB_INTR_STS_TEST);
7988890ab77SEd Maste 		return (FILTER_HANDLED);
7998890ab77SEd Maste 	}
8008890ab77SEd Maste 	if ((intr_sts & MGB_INTR_STS_RX_ANY) != 0)
8018890ab77SEd Maste 	{
8028890ab77SEd Maste 		for (qidx = 0; qidx < scctx->isc_nrxqsets; qidx++) {
8038890ab77SEd Maste 			if ((intr_sts & MGB_INTR_STS_RX(qidx))){
8048890ab77SEd Maste 				iflib_rx_intr_deferred(sc->ctx, qidx);
8058890ab77SEd Maste 			}
8068890ab77SEd Maste 		}
8078890ab77SEd Maste 		return (FILTER_HANDLED);
8088890ab77SEd Maste 	}
8098890ab77SEd Maste 	/* XXX: TX interrupts should not occur */
8108890ab77SEd Maste 	if ((intr_sts & MGB_INTR_STS_TX_ANY) != 0)
8118890ab77SEd Maste 	{
8128890ab77SEd Maste 		for (qidx = 0; qidx < scctx->isc_ntxqsets; qidx++) {
8138890ab77SEd Maste 			if ((intr_sts & MGB_INTR_STS_RX(qidx))) {
8148890ab77SEd Maste 				/* clear the interrupt sts and run handler */
8158890ab77SEd Maste 				CSR_WRITE_REG(sc, MGB_INTR_ENBL_CLR,
8168890ab77SEd Maste 				    MGB_INTR_STS_TX(qidx));
8178890ab77SEd Maste 				CSR_WRITE_REG(sc, MGB_INTR_STS,
8188890ab77SEd Maste 				    MGB_INTR_STS_TX(qidx));
8198890ab77SEd Maste 				iflib_tx_intr_deferred(sc->ctx, qidx);
8208890ab77SEd Maste 			}
8218890ab77SEd Maste 		}
8228890ab77SEd Maste 		return (FILTER_HANDLED);
8238890ab77SEd Maste 	}
8248890ab77SEd Maste 
8258890ab77SEd Maste 	return (FILTER_SCHEDULE_THREAD);
8268890ab77SEd Maste }
8278890ab77SEd Maste 
8288890ab77SEd Maste static int
8298890ab77SEd Maste mgb_msix_intr_assign(if_ctx_t ctx, int msix)
8308890ab77SEd Maste {
8318890ab77SEd Maste 	struct mgb_softc *sc;
8328890ab77SEd Maste 	if_softc_ctx_t scctx;
8338890ab77SEd Maste 	int error, i, vectorid;
8348890ab77SEd Maste 	char irq_name[16];
8358890ab77SEd Maste 
8368890ab77SEd Maste 	sc = iflib_get_softc(ctx);
8378890ab77SEd Maste 	scctx = iflib_get_softc_ctx(ctx);
8388890ab77SEd Maste 
8398890ab77SEd Maste 	KASSERT(scctx->isc_nrxqsets == 1 && scctx->isc_ntxqsets == 1,
8408890ab77SEd Maste 	    ("num rxqsets/txqsets != 1 "));
8418890ab77SEd Maste 
8428890ab77SEd Maste 	/*
8438890ab77SEd Maste 	 * First vector should be admin interrupts, others vectors are TX/RX
8448890ab77SEd Maste 	 *
8458890ab77SEd Maste 	 * RIDs start at 1, and vector ids start at 0.
8468890ab77SEd Maste 	 */
8478890ab77SEd Maste 	vectorid = 0;
8488890ab77SEd Maste 	error = iflib_irq_alloc_generic(ctx, &sc->admin_irq, vectorid + 1,
8498890ab77SEd Maste 	    IFLIB_INTR_ADMIN, mgb_admin_intr, sc, 0, "admin");
8508890ab77SEd Maste 	if (error) {
8518890ab77SEd Maste 		device_printf(sc->dev,
8528890ab77SEd Maste 		    "Failed to register admin interrupt handler\n");
8538890ab77SEd Maste 		return (error);
8548890ab77SEd Maste 	}
8558890ab77SEd Maste 
8568890ab77SEd Maste 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
8578890ab77SEd Maste 		vectorid++;
8588890ab77SEd Maste 		snprintf(irq_name, sizeof(irq_name), "rxq%d", i);
8598890ab77SEd Maste 		error = iflib_irq_alloc_generic(ctx, &sc->rx_irq, vectorid + 1,
8608890ab77SEd Maste 		    IFLIB_INTR_RX, mgb_rxq_intr, sc, i, irq_name);
8618890ab77SEd Maste 		if (error) {
8628890ab77SEd Maste 			device_printf(sc->dev,
8638890ab77SEd Maste 			    "Failed to register rxq %d interrupt handler\n", i);
8648890ab77SEd Maste 			return (error);
8658890ab77SEd Maste 		}
8668890ab77SEd Maste 		CSR_UPDATE_REG(sc, MGB_INTR_VEC_RX_MAP,
8678890ab77SEd Maste 		    MGB_INTR_VEC_MAP(vectorid, i));
8688890ab77SEd Maste 	}
8698890ab77SEd Maste 
8708890ab77SEd Maste 	/* Not actually mapping hw TX interrupts ... */
8718890ab77SEd Maste 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
8728890ab77SEd Maste 		snprintf(irq_name, sizeof(irq_name), "txq%d", i);
8738890ab77SEd Maste 		iflib_softirq_alloc_generic(ctx, NULL, IFLIB_INTR_TX, NULL, i,
8748890ab77SEd Maste 		    irq_name);
8758890ab77SEd Maste 	}
8768890ab77SEd Maste 
8778890ab77SEd Maste 	return (0);
8788890ab77SEd Maste }
8798890ab77SEd Maste 
8808890ab77SEd Maste static void
8818890ab77SEd Maste mgb_intr_enable_all(if_ctx_t ctx)
8828890ab77SEd Maste {
8838890ab77SEd Maste 	struct mgb_softc *sc;
8848890ab77SEd Maste 	if_softc_ctx_t scctx;
8858890ab77SEd Maste 	int i, dmac_enable = 0, intr_sts = 0, vec_en = 0;
8868890ab77SEd Maste 
8878890ab77SEd Maste 	sc = iflib_get_softc(ctx);
8888890ab77SEd Maste 	scctx = iflib_get_softc_ctx(ctx);
8898890ab77SEd Maste 	intr_sts |= MGB_INTR_STS_ANY;
8908890ab77SEd Maste 	vec_en |= MGB_INTR_STS_ANY;
8918890ab77SEd Maste 
8928890ab77SEd Maste 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
8938890ab77SEd Maste 		intr_sts |= MGB_INTR_STS_RX(i);
8948890ab77SEd Maste 		dmac_enable |= MGB_DMAC_RX_INTR_ENBL(i);
8958890ab77SEd Maste 		vec_en |= MGB_INTR_RX_VEC_STS(i);
8968890ab77SEd Maste 	}
8978890ab77SEd Maste 
8988890ab77SEd Maste 	/* TX interrupts aren't needed ... */
8998890ab77SEd Maste 
9008890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_ENBL_SET, intr_sts);
9018890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_VEC_ENBL_SET, vec_en);
9028890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMAC_INTR_STS, dmac_enable);
9038890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMAC_INTR_ENBL_SET, dmac_enable);
9048890ab77SEd Maste }
9058890ab77SEd Maste 
9068890ab77SEd Maste static void
9078890ab77SEd Maste mgb_intr_disable_all(if_ctx_t ctx)
9088890ab77SEd Maste {
9098890ab77SEd Maste 	struct mgb_softc *sc;
9108890ab77SEd Maste 
9118890ab77SEd Maste 	sc = iflib_get_softc(ctx);
9128890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_ENBL_CLR, UINT32_MAX);
9138890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_VEC_ENBL_CLR, UINT32_MAX);
9148890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_STS, UINT32_MAX);
9158890ab77SEd Maste 
9168890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMAC_INTR_ENBL_CLR, UINT32_MAX);
9178890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMAC_INTR_STS, UINT32_MAX);
9188890ab77SEd Maste }
9198890ab77SEd Maste 
9208890ab77SEd Maste static int
9218890ab77SEd Maste mgb_rx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
9228890ab77SEd Maste {
9238890ab77SEd Maste 	/* called after successful rx isr */
9248890ab77SEd Maste 	struct mgb_softc *sc;
9258890ab77SEd Maste 
9268890ab77SEd Maste 	sc = iflib_get_softc(ctx);
9278890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_VEC_ENBL_SET, MGB_INTR_RX_VEC_STS(qid));
9288890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_ENBL_SET, MGB_INTR_STS_RX(qid));
9298890ab77SEd Maste 
9308890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMAC_INTR_STS, MGB_DMAC_RX_INTR_ENBL(qid));
9318890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMAC_INTR_ENBL_SET, MGB_DMAC_RX_INTR_ENBL(qid));
9328890ab77SEd Maste 	return (0);
9338890ab77SEd Maste }
9348890ab77SEd Maste 
9358890ab77SEd Maste static int
9368890ab77SEd Maste mgb_tx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
9378890ab77SEd Maste {
9388890ab77SEd Maste 	/* XXX: not called (since tx interrupts not used) */
9398890ab77SEd Maste 	struct mgb_softc *sc;
9408890ab77SEd Maste 
9418890ab77SEd Maste 	sc = iflib_get_softc(ctx);
9428890ab77SEd Maste 
9438890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_ENBL_SET, MGB_INTR_STS_TX(qid));
9448890ab77SEd Maste 
9458890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMAC_INTR_STS, MGB_DMAC_TX_INTR_ENBL(qid));
9468890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMAC_INTR_ENBL_SET, MGB_DMAC_TX_INTR_ENBL(qid));
9478890ab77SEd Maste 	return (0);
9488890ab77SEd Maste }
9498890ab77SEd Maste 
9508890ab77SEd Maste static bool
9518890ab77SEd Maste mgb_intr_test(struct mgb_softc *sc)
9528890ab77SEd Maste {
9538890ab77SEd Maste 	int i;
9548890ab77SEd Maste 
9558890ab77SEd Maste 	sc->isr_test_flag = false;
9568890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_STS, MGB_INTR_STS_TEST);
9578890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_VEC_ENBL_SET, MGB_INTR_STS_ANY);
9588890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_ENBL_SET,
9598890ab77SEd Maste 	    MGB_INTR_STS_ANY | MGB_INTR_STS_TEST);
9608890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_SET, MGB_INTR_STS_TEST);
9618890ab77SEd Maste 	if (sc->isr_test_flag)
9628890ab77SEd Maste 		return true;
9638890ab77SEd Maste 	for (i = 0; i < MGB_TIMEOUT; i++) {
9648890ab77SEd Maste 		DELAY(10);
9658890ab77SEd Maste 		if (sc->isr_test_flag)
9668890ab77SEd Maste 			break;
9678890ab77SEd Maste 	}
9688890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_ENBL_CLR, MGB_INTR_STS_TEST);
9698890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_INTR_STS, MGB_INTR_STS_TEST);
9708890ab77SEd Maste 	return sc->isr_test_flag;
9718890ab77SEd Maste }
9728890ab77SEd Maste 
9738890ab77SEd Maste static int
9748890ab77SEd Maste mgb_isc_txd_encap(void *xsc , if_pkt_info_t ipi)
9758890ab77SEd Maste {
9768890ab77SEd Maste 	struct mgb_softc *sc;
9778890ab77SEd Maste 	if_softc_ctx_t scctx;
9788890ab77SEd Maste 	struct mgb_ring_data *rdata;
9798890ab77SEd Maste 	struct mgb_ring_desc *txd;
9808890ab77SEd Maste 	bus_dma_segment_t *segs;
9818890ab77SEd Maste 	qidx_t pidx, nsegs;
9828890ab77SEd Maste 	int i;
9838890ab77SEd Maste 
9848890ab77SEd Maste 	KASSERT(ipi->ipi_qsidx == 0,
9858890ab77SEd Maste 	    ("tried to refill TX Channel %d.\n", ipi->ipi_qsidx));
9868890ab77SEd Maste 	sc = xsc;
9878890ab77SEd Maste 	scctx = iflib_get_softc_ctx(sc->ctx);
9888890ab77SEd Maste 	rdata = &sc->tx_ring_data;
9898890ab77SEd Maste 
9908890ab77SEd Maste 	pidx = ipi->ipi_pidx;
9918890ab77SEd Maste 	segs = ipi->ipi_segs;
9928890ab77SEd Maste 	nsegs = ipi->ipi_nsegs;
9938890ab77SEd Maste 
9948890ab77SEd Maste 	/* For each seg, create a descriptor */
9958890ab77SEd Maste 	for (i = 0; i < nsegs; ++i) {
9968890ab77SEd Maste 		KASSERT(nsegs == 1, ("Multisegment packet !!!!!\n"));
9978890ab77SEd Maste 		txd = &rdata->ring[pidx];
9988890ab77SEd Maste 		txd->ctl = htole32(
9998890ab77SEd Maste 		    (segs[i].ds_len & MGB_DESC_CTL_BUFLEN_MASK ) |
10008890ab77SEd Maste 		    /*
10018890ab77SEd Maste 		     * XXX: This will be wrong in the multipacket case
10028890ab77SEd Maste 		     * I suspect FS should be for the first packet and
10038890ab77SEd Maste 		     * LS should be for the last packet
10048890ab77SEd Maste 		     */
10058890ab77SEd Maste 		    MGB_TX_DESC_CTL_FS | MGB_TX_DESC_CTL_LS |
10068890ab77SEd Maste 		    MGB_DESC_CTL_FCS);
10078890ab77SEd Maste 		txd->addr.low = htole32(CSR_TRANSLATE_ADDR_LOW32(
10088890ab77SEd Maste 		    segs[i].ds_addr));
10098890ab77SEd Maste 		txd->addr.high = htole32(CSR_TRANSLATE_ADDR_HIGH32(
10108890ab77SEd Maste 		    segs[i].ds_addr));
10118890ab77SEd Maste 		txd->sts = htole32(
10128890ab77SEd Maste 		    (segs[i].ds_len << 16) & MGB_DESC_FRAME_LEN_MASK);
10138890ab77SEd Maste 		pidx = MGB_NEXT_RING_IDX(pidx);
10148890ab77SEd Maste 	}
10158890ab77SEd Maste 	ipi->ipi_new_pidx = pidx;
10168890ab77SEd Maste 	return (0);
10178890ab77SEd Maste }
10188890ab77SEd Maste 
10198890ab77SEd Maste static void
10208890ab77SEd Maste mgb_isc_txd_flush(void *xsc, uint16_t txqid, qidx_t pidx)
10218890ab77SEd Maste {
10228890ab77SEd Maste 	struct mgb_softc *sc;
10238890ab77SEd Maste 	struct mgb_ring_data *rdata;
10248890ab77SEd Maste 
10258890ab77SEd Maste 	KASSERT(txqid == 0, ("tried to flush TX Channel %d.\n", txqid));
10268890ab77SEd Maste 	sc = xsc;
10278890ab77SEd Maste 	rdata = &sc->tx_ring_data;
10288890ab77SEd Maste 
10298890ab77SEd Maste 	if (rdata->last_tail != pidx) {
10308890ab77SEd Maste 		rdata->last_tail = pidx;
10318890ab77SEd Maste 		CSR_WRITE_REG(sc, MGB_DMA_TX_TAIL(txqid), rdata->last_tail);
10328890ab77SEd Maste 	}
10338890ab77SEd Maste }
10348890ab77SEd Maste 
10358890ab77SEd Maste static int
10368890ab77SEd Maste mgb_isc_txd_credits_update(void *xsc, uint16_t txqid, bool clear)
10378890ab77SEd Maste {
10388890ab77SEd Maste 	struct mgb_softc *sc;
10398890ab77SEd Maste 	struct mgb_ring_desc *txd;
10408890ab77SEd Maste 	struct mgb_ring_data *rdata;
10418890ab77SEd Maste 	int processed = 0;
10428890ab77SEd Maste 
10438890ab77SEd Maste 	/*
10448890ab77SEd Maste 	 * > If clear is true, we need to report the number of TX command ring
10458890ab77SEd Maste 	 * > descriptors that have been processed by the device.  If clear is
10468890ab77SEd Maste 	 * > false, we just need to report whether or not at least one TX
10478890ab77SEd Maste 	 * > command ring descriptor has been processed by the device.
10488890ab77SEd Maste 	 * - vmx driver
10498890ab77SEd Maste 	 */
10508890ab77SEd Maste 	KASSERT(txqid == 0, ("tried to credits_update TX Channel %d.\n",
10518890ab77SEd Maste 	    txqid));
10528890ab77SEd Maste 	sc = xsc;
10538890ab77SEd Maste 	rdata = &sc->tx_ring_data;
10548890ab77SEd Maste 
10558890ab77SEd Maste 	while (*(rdata->head_wb) != rdata->last_head) {
10568890ab77SEd Maste 		if (!clear)
10578890ab77SEd Maste 			return 1;
10588890ab77SEd Maste 
10598890ab77SEd Maste 		txd = &rdata->ring[rdata->last_head];
10608890ab77SEd Maste 		memset(txd, 0, sizeof(struct mgb_ring_desc));
10618890ab77SEd Maste 		rdata->last_head = MGB_NEXT_RING_IDX(rdata->last_head);
10628890ab77SEd Maste 		processed++;
10638890ab77SEd Maste 	}
10648890ab77SEd Maste 
10658890ab77SEd Maste 	return (processed);
10668890ab77SEd Maste }
10678890ab77SEd Maste 
10688890ab77SEd Maste static int
10698890ab77SEd Maste mgb_isc_rxd_available(void *xsc, uint16_t rxqid, qidx_t idx, qidx_t budget)
10708890ab77SEd Maste {
10718890ab77SEd Maste 	struct mgb_softc *sc;
10728890ab77SEd Maste 	if_softc_ctx_t scctx;
10738890ab77SEd Maste 	struct mgb_ring_data *rdata;
10748890ab77SEd Maste 	int avail = 0;
10758890ab77SEd Maste 
10768890ab77SEd Maste 	sc = xsc;
10778890ab77SEd Maste 	KASSERT(rxqid == 0, ("tried to check availability in RX Channel %d.\n",
10788890ab77SEd Maste 	    rxqid));
10798890ab77SEd Maste 
10808890ab77SEd Maste 	rdata = &sc->rx_ring_data;
10818890ab77SEd Maste 	scctx = iflib_get_softc_ctx(sc->ctx);
10828890ab77SEd Maste 	for (; idx != *(rdata->head_wb);
10838890ab77SEd Maste 	    idx = MGB_NEXT_RING_IDX(idx)) {
10848890ab77SEd Maste 		avail++;
10858890ab77SEd Maste 		/* XXX: Could verify desc is device owned here */
10868890ab77SEd Maste 		if (avail == budget)
10878890ab77SEd Maste 			break;
10888890ab77SEd Maste 	}
10898890ab77SEd Maste 	return (avail);
10908890ab77SEd Maste }
10918890ab77SEd Maste 
10928890ab77SEd Maste static int
10938890ab77SEd Maste mgb_isc_rxd_pkt_get(void *xsc, if_rxd_info_t ri)
10948890ab77SEd Maste {
10958890ab77SEd Maste 	struct mgb_softc *sc;
10968890ab77SEd Maste 	struct mgb_ring_data *rdata;
10978890ab77SEd Maste 	struct mgb_ring_desc rxd;
10988890ab77SEd Maste 	int total_len;
10998890ab77SEd Maste 
11008890ab77SEd Maste 	KASSERT(ri->iri_qsidx == 0,
11018890ab77SEd Maste 	    ("tried to check availability in RX Channel %d\n", ri->iri_qsidx));
11028890ab77SEd Maste 	sc = xsc;
11038890ab77SEd Maste 	total_len = 0;
11048890ab77SEd Maste 	rdata = &sc->rx_ring_data;
11058890ab77SEd Maste 
11068890ab77SEd Maste 	while (*(rdata->head_wb) != rdata->last_head) {
11078890ab77SEd Maste 		/* copy ring desc and do swapping */
11088890ab77SEd Maste 		rxd = rdata->ring[rdata->last_head];
11098890ab77SEd Maste 		rxd.ctl = le32toh(rxd.ctl);
11108890ab77SEd Maste 		rxd.addr.low = le32toh(rxd.ctl);
11118890ab77SEd Maste 		rxd.addr.high = le32toh(rxd.ctl);
11128890ab77SEd Maste 		rxd.sts = le32toh(rxd.ctl);
11138890ab77SEd Maste 
11148890ab77SEd Maste 		if ((rxd.ctl & MGB_DESC_CTL_OWN) != 0) {
11158890ab77SEd Maste 			device_printf(sc->dev,
11168890ab77SEd Maste 			    "Tried to read descriptor ... "
11178890ab77SEd Maste 			    "found that it's owned by the driver\n");
11188890ab77SEd Maste 			return EINVAL;
11198890ab77SEd Maste 		}
11208890ab77SEd Maste 		if ((rxd.ctl & MGB_RX_DESC_CTL_FS) == 0) {
11218890ab77SEd Maste 			device_printf(sc->dev,
11228890ab77SEd Maste 			    "Tried to read descriptor ... "
11238890ab77SEd Maste 			    "found that FS is not set.\n");
11248890ab77SEd Maste 			device_printf(sc->dev, "Tried to read descriptor ... that it FS is not set.\n");
11258890ab77SEd Maste 			return EINVAL;
11268890ab77SEd Maste 		}
11278890ab77SEd Maste 		/* XXX: Multi-packet support */
11288890ab77SEd Maste 		if ((rxd.ctl & MGB_RX_DESC_CTL_LS) == 0) {
11298890ab77SEd Maste 			device_printf(sc->dev,
11308890ab77SEd Maste 			    "Tried to read descriptor ... "
11318890ab77SEd Maste 			    "found that LS is not set. (Multi-buffer packets not yet supported)\n");
11328890ab77SEd Maste 			return EINVAL;
11338890ab77SEd Maste 		}
11348890ab77SEd Maste 		ri->iri_frags[0].irf_flid = 0;
11358890ab77SEd Maste 		ri->iri_frags[0].irf_idx = rdata->last_head;
11368890ab77SEd Maste 		ri->iri_frags[0].irf_len = MGB_DESC_GET_FRAME_LEN(&rxd);
11378890ab77SEd Maste 		total_len += ri->iri_frags[0].irf_len;
11388890ab77SEd Maste 
11398890ab77SEd Maste 		rdata->last_head = MGB_NEXT_RING_IDX(rdata->last_head);
11408890ab77SEd Maste 		break;
11418890ab77SEd Maste 	}
11428890ab77SEd Maste 	ri->iri_nfrags = 1;
11438890ab77SEd Maste 	ri->iri_len = total_len;
11448890ab77SEd Maste 
11458890ab77SEd Maste 	return (0);
11468890ab77SEd Maste }
11478890ab77SEd Maste 
11488890ab77SEd Maste static void
11498890ab77SEd Maste mgb_isc_rxd_refill(void *xsc, if_rxd_update_t iru)
11508890ab77SEd Maste {
11518890ab77SEd Maste 	if_softc_ctx_t scctx;
11528890ab77SEd Maste 	struct mgb_softc *sc;
11538890ab77SEd Maste 	struct mgb_ring_data *rdata;
11548890ab77SEd Maste 	struct mgb_ring_desc *rxd;
11558890ab77SEd Maste 	uint64_t *paddrs;
11568890ab77SEd Maste 	qidx_t *idxs;
11578890ab77SEd Maste 	qidx_t idx;
11588890ab77SEd Maste 	int count, len;
11598890ab77SEd Maste 
11608890ab77SEd Maste 	count = iru->iru_count;
11618890ab77SEd Maste 	len = iru->iru_buf_size;
11628890ab77SEd Maste 	idxs = iru->iru_idxs;
11638890ab77SEd Maste 	paddrs = iru->iru_paddrs;
11648890ab77SEd Maste 	KASSERT(iru->iru_qsidx == 0,
11658890ab77SEd Maste 	    ("tried to refill RX Channel %d.\n", iru->iru_qsidx));
11668890ab77SEd Maste 
11678890ab77SEd Maste 	sc = xsc;
11688890ab77SEd Maste 	scctx = iflib_get_softc_ctx(sc->ctx);
11698890ab77SEd Maste 	rdata = &sc->rx_ring_data;
11708890ab77SEd Maste 
11718890ab77SEd Maste 	while (count > 0) {
11728890ab77SEd Maste 		idx = idxs[--count];
11738890ab77SEd Maste 		rxd = &rdata->ring[idx];
11748890ab77SEd Maste 
11758890ab77SEd Maste 		rxd->sts = 0;
11768890ab77SEd Maste 		rxd->addr.low =
11778890ab77SEd Maste 		    htole32(CSR_TRANSLATE_ADDR_LOW32(paddrs[count]));
11788890ab77SEd Maste 		rxd->addr.high =
11798890ab77SEd Maste 		    htole32(CSR_TRANSLATE_ADDR_HIGH32(paddrs[count]));
11808890ab77SEd Maste 		rxd->ctl = htole32(MGB_DESC_CTL_OWN |
11818890ab77SEd Maste 		    (len & MGB_DESC_CTL_BUFLEN_MASK));
11828890ab77SEd Maste 	}
11838890ab77SEd Maste 	return;
11848890ab77SEd Maste }
11858890ab77SEd Maste 
11868890ab77SEd Maste static void
11878890ab77SEd Maste mgb_isc_rxd_flush(void *xsc, uint16_t rxqid, uint8_t flid, qidx_t pidx)
11888890ab77SEd Maste {
11898890ab77SEd Maste 	struct mgb_softc *sc;
11908890ab77SEd Maste 
11918890ab77SEd Maste 	sc = xsc;
11928890ab77SEd Maste 
11938890ab77SEd Maste 	KASSERT(rxqid == 0, ("tried to flush RX Channel %d.\n", rxqid));
11948890ab77SEd Maste 	sc->rx_ring_data.last_tail = pidx;
11958890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_RX_TAIL(rxqid), sc->rx_ring_data.last_tail);
11968890ab77SEd Maste 	return;
11978890ab77SEd Maste }
11988890ab77SEd Maste 
11998890ab77SEd Maste static int
12008890ab77SEd Maste mgb_test_bar(struct mgb_softc *sc)
12018890ab77SEd Maste {
12028890ab77SEd Maste 	uint32_t id_rev, dev_id, rev;
12038890ab77SEd Maste 
12048890ab77SEd Maste 	id_rev = CSR_READ_REG(sc, 0);
12058890ab77SEd Maste 	dev_id = id_rev >> 16;
12068890ab77SEd Maste 	rev = id_rev & 0xFFFF;
12078890ab77SEd Maste 	if (dev_id == MGB_LAN7430_DEVICE_ID ||
12088890ab77SEd Maste 	    dev_id == MGB_LAN7431_DEVICE_ID) {
12098890ab77SEd Maste 		return 0;
12108890ab77SEd Maste 	} else {
12118890ab77SEd Maste 		device_printf(sc->dev, "ID check failed.\n");
12128890ab77SEd Maste 		return ENXIO;
12138890ab77SEd Maste 	}
12148890ab77SEd Maste }
12158890ab77SEd Maste 
12168890ab77SEd Maste static int
12178890ab77SEd Maste mgb_alloc_regs(struct mgb_softc *sc)
12188890ab77SEd Maste {
12198890ab77SEd Maste 	int rid;
12208890ab77SEd Maste 
12218890ab77SEd Maste 	rid = PCIR_BAR(MGB_BAR);
12228890ab77SEd Maste 	pci_enable_busmaster(sc->dev);
12238890ab77SEd Maste 	sc->regs = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
12248890ab77SEd Maste 	    &rid, RF_ACTIVE);
12258890ab77SEd Maste 	if (sc->regs == NULL)
12268890ab77SEd Maste 		 return ENXIO;
12278890ab77SEd Maste 
12288890ab77SEd Maste 	return (0);
12298890ab77SEd Maste }
12308890ab77SEd Maste 
12318890ab77SEd Maste static int
12328890ab77SEd Maste mgb_release_regs(struct mgb_softc *sc)
12338890ab77SEd Maste {
12348890ab77SEd Maste 	int error = 0;
12358890ab77SEd Maste 
12368890ab77SEd Maste 	if (sc->regs != NULL)
12378890ab77SEd Maste 		error = bus_release_resource(sc->dev, SYS_RES_MEMORY,
12388890ab77SEd Maste 		    rman_get_rid(sc->regs), sc->regs);
12398890ab77SEd Maste 	sc->regs = NULL;
12408890ab77SEd Maste 	pci_disable_busmaster(sc->dev);
12418890ab77SEd Maste 	return error;
12428890ab77SEd Maste }
12438890ab77SEd Maste 
12448890ab77SEd Maste static int
12458890ab77SEd Maste mgb_dma_init(struct mgb_softc *sc)
12468890ab77SEd Maste {
12478890ab77SEd Maste 	if_softc_ctx_t scctx;
12488890ab77SEd Maste 	int ch, error = 0;
12498890ab77SEd Maste 
12508890ab77SEd Maste 	scctx = iflib_get_softc_ctx(sc->ctx);
12518890ab77SEd Maste 
12528890ab77SEd Maste 	for (ch = 0; ch < scctx->isc_nrxqsets; ch++)
12538890ab77SEd Maste 		if ((error = mgb_dma_rx_ring_init(sc, ch)))
12548890ab77SEd Maste 			goto fail;
12558890ab77SEd Maste 
12568890ab77SEd Maste 	for (ch = 0; ch < scctx->isc_nrxqsets; ch++)
12578890ab77SEd Maste 		if ((error = mgb_dma_tx_ring_init(sc, ch)))
12588890ab77SEd Maste 			goto fail;
12598890ab77SEd Maste 
12608890ab77SEd Maste fail:
12618890ab77SEd Maste 	return error;
12628890ab77SEd Maste }
12638890ab77SEd Maste 
12648890ab77SEd Maste static int
12658890ab77SEd Maste mgb_dma_rx_ring_init(struct mgb_softc *sc, int channel)
12668890ab77SEd Maste {
12678890ab77SEd Maste 	struct mgb_ring_data *rdata;
12688890ab77SEd Maste 	int ring_config, error = 0;
12698890ab77SEd Maste 
12708890ab77SEd Maste 	rdata = &sc->rx_ring_data;
12718890ab77SEd Maste 	mgb_dmac_control(sc, MGB_DMAC_RX_START, 0, DMAC_RESET);
12728890ab77SEd Maste 	KASSERT(MGB_DMAC_STATE_IS_INITIAL(sc, MGB_DMAC_RX_START, channel),
12738890ab77SEd Maste 	    ("Trying to init channels when not in init state\n"));
12748890ab77SEd Maste 
12758890ab77SEd Maste 	/* write ring address */
12768890ab77SEd Maste 	if (rdata->ring_bus_addr == 0) {
12778890ab77SEd Maste 		device_printf(sc->dev, "Invalid ring bus addr.\n");
12788890ab77SEd Maste 		goto fail;
12798890ab77SEd Maste 	}
12808890ab77SEd Maste 
12818890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_RX_BASE_H(channel),
12828890ab77SEd Maste 	    CSR_TRANSLATE_ADDR_HIGH32(rdata->ring_bus_addr));
12838890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_RX_BASE_L(channel),
12848890ab77SEd Maste 	    CSR_TRANSLATE_ADDR_LOW32(rdata->ring_bus_addr));
12858890ab77SEd Maste 
12868890ab77SEd Maste 	/* write head pointer writeback address */
12878890ab77SEd Maste 	if (rdata->head_wb_bus_addr == 0) {
12888890ab77SEd Maste 		device_printf(sc->dev, "Invalid head wb bus addr.\n");
12898890ab77SEd Maste 		goto fail;
12908890ab77SEd Maste 	}
12918890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_RX_HEAD_WB_H(channel),
12928890ab77SEd Maste 	    CSR_TRANSLATE_ADDR_HIGH32(rdata->head_wb_bus_addr));
12938890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_RX_HEAD_WB_L(channel),
12948890ab77SEd Maste 	    CSR_TRANSLATE_ADDR_LOW32(rdata->head_wb_bus_addr));
12958890ab77SEd Maste 
12968890ab77SEd Maste 	/* Enable head pointer writeback */
12978890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_RX_CONFIG0(channel), MGB_DMA_HEAD_WB_ENBL);
12988890ab77SEd Maste 
12998890ab77SEd Maste 	ring_config = CSR_READ_REG(sc, MGB_DMA_RX_CONFIG1(channel));
13008890ab77SEd Maste 	/*  ring size */
13018890ab77SEd Maste 	ring_config &= ~MGB_DMA_RING_LEN_MASK;
13028890ab77SEd Maste 	ring_config |= (MGB_DMA_RING_SIZE & MGB_DMA_RING_LEN_MASK);
13038890ab77SEd Maste 	/* packet padding  (PAD_2 is better for IP header alignment ...) */
13048890ab77SEd Maste 	ring_config &= ~MGB_DMA_RING_PAD_MASK;
13058890ab77SEd Maste 	ring_config |= (MGB_DMA_RING_PAD_0 & MGB_DMA_RING_PAD_MASK);
13068890ab77SEd Maste 
13078890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_RX_CONFIG1(channel), ring_config);
13088890ab77SEd Maste 
13098890ab77SEd Maste 	rdata->last_head = CSR_READ_REG(sc, MGB_DMA_RX_HEAD(channel));
13108890ab77SEd Maste 
13118890ab77SEd Maste 	mgb_fct_control(sc, MGB_FCT_RX_CTL, channel, FCT_RESET);
13128890ab77SEd Maste 	if (error != 0) {
13138890ab77SEd Maste 		device_printf(sc->dev, "Failed to reset RX FCT.\n");
13148890ab77SEd Maste 		goto fail;
13158890ab77SEd Maste 	}
13168890ab77SEd Maste 	mgb_fct_control(sc, MGB_FCT_RX_CTL, channel, FCT_ENABLE);
13178890ab77SEd Maste 	if (error != 0) {
13188890ab77SEd Maste 		device_printf(sc->dev, "Failed to enable RX FCT.\n");
13198890ab77SEd Maste 		goto fail;
13208890ab77SEd Maste 	}
13218890ab77SEd Maste 	mgb_dmac_control(sc, MGB_DMAC_RX_START, channel, DMAC_START);
13228890ab77SEd Maste 	if (error != 0)
13238890ab77SEd Maste 		device_printf(sc->dev, "Failed to start RX DMAC.\n");
13248890ab77SEd Maste fail:
13258890ab77SEd Maste 	return (error);
13268890ab77SEd Maste }
13278890ab77SEd Maste 
13288890ab77SEd Maste static int
13298890ab77SEd Maste mgb_dma_tx_ring_init(struct mgb_softc *sc, int channel)
13308890ab77SEd Maste {
13318890ab77SEd Maste 	struct mgb_ring_data *rdata;
13328890ab77SEd Maste 	int ring_config, error = 0;
13338890ab77SEd Maste 
13348890ab77SEd Maste 	rdata = &sc->tx_ring_data;
13358890ab77SEd Maste 	if ((error = mgb_fct_control(sc, MGB_FCT_TX_CTL, channel, FCT_RESET))) {
13368890ab77SEd Maste 		device_printf(sc->dev, "Failed to reset TX FCT.\n");
13378890ab77SEd Maste 		goto fail;
13388890ab77SEd Maste 	}
13398890ab77SEd Maste 	if ((error = mgb_fct_control(sc, MGB_FCT_TX_CTL, channel,
13408890ab77SEd Maste 	    FCT_ENABLE))) {
13418890ab77SEd Maste 		device_printf(sc->dev, "Failed to enable TX FCT.\n");
13428890ab77SEd Maste 		goto fail;
13438890ab77SEd Maste 	}
13448890ab77SEd Maste 	if ((error = mgb_dmac_control(sc, MGB_DMAC_TX_START, channel,
13458890ab77SEd Maste 	    DMAC_RESET))) {
13468890ab77SEd Maste 		device_printf(sc->dev, "Failed to reset TX DMAC.\n");
13478890ab77SEd Maste 		goto fail;
13488890ab77SEd Maste 	}
13498890ab77SEd Maste 	KASSERT(MGB_DMAC_STATE_IS_INITIAL(sc, MGB_DMAC_TX_START, channel),
13508890ab77SEd Maste 	    ("Trying to init channels in not init state\n"));
13518890ab77SEd Maste 
13528890ab77SEd Maste 	/* write ring address */
13538890ab77SEd Maste 	if (rdata->ring_bus_addr == 0) {
13548890ab77SEd Maste 		device_printf(sc->dev, "Invalid ring bus addr.\n");
13558890ab77SEd Maste 		goto fail;
13568890ab77SEd Maste 	}
13578890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_TX_BASE_H(channel),
13588890ab77SEd Maste 	    CSR_TRANSLATE_ADDR_HIGH32(rdata->ring_bus_addr));
13598890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_TX_BASE_L(channel),
13608890ab77SEd Maste 	    CSR_TRANSLATE_ADDR_LOW32(rdata->ring_bus_addr));
13618890ab77SEd Maste 
13628890ab77SEd Maste 	/* write ring size */
13638890ab77SEd Maste 	ring_config = CSR_READ_REG(sc, MGB_DMA_TX_CONFIG1(channel));
13648890ab77SEd Maste 	ring_config &= ~MGB_DMA_RING_LEN_MASK;
13658890ab77SEd Maste 	ring_config |= (MGB_DMA_RING_SIZE & MGB_DMA_RING_LEN_MASK);
13668890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_TX_CONFIG1(channel), ring_config);
13678890ab77SEd Maste 
13688890ab77SEd Maste 	/* Enable interrupt on completion and head pointer writeback */
13698890ab77SEd Maste 	ring_config = (MGB_DMA_HEAD_WB_LS_ENBL | MGB_DMA_HEAD_WB_ENBL);
13708890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_TX_CONFIG0(channel), ring_config);
13718890ab77SEd Maste 
13728890ab77SEd Maste 	/* write head pointer writeback address */
13738890ab77SEd Maste 	if (rdata->head_wb_bus_addr == 0) {
13748890ab77SEd Maste 		device_printf(sc->dev, "Invalid head wb bus addr.\n");
13758890ab77SEd Maste 		goto fail;
13768890ab77SEd Maste 	}
13778890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_TX_HEAD_WB_H(channel),
13788890ab77SEd Maste 	    CSR_TRANSLATE_ADDR_HIGH32(rdata->head_wb_bus_addr));
13798890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_TX_HEAD_WB_L(channel),
13808890ab77SEd Maste 	    CSR_TRANSLATE_ADDR_LOW32(rdata->head_wb_bus_addr));
13818890ab77SEd Maste 
13828890ab77SEd Maste 	rdata->last_head = CSR_READ_REG(sc, MGB_DMA_TX_HEAD(channel));
13838890ab77SEd Maste 	KASSERT(rdata->last_head == 0, ("MGB_DMA_TX_HEAD was not reset.\n"));
13848890ab77SEd Maste 	rdata->last_tail = 0;
13858890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMA_TX_TAIL(channel), rdata->last_tail);
13868890ab77SEd Maste 
13878890ab77SEd Maste 	if ((error = mgb_dmac_control(sc, MGB_DMAC_TX_START, channel,
13888890ab77SEd Maste 	    DMAC_START)))
13898890ab77SEd Maste 		device_printf(sc->dev, "Failed to start TX DMAC.\n");
13908890ab77SEd Maste fail:
13918890ab77SEd Maste 	return error;
13928890ab77SEd Maste }
13938890ab77SEd Maste 
13948890ab77SEd Maste static int
13958890ab77SEd Maste mgb_dmac_control(struct mgb_softc *sc, int start, int channel,
13968890ab77SEd Maste     enum mgb_dmac_cmd cmd)
13978890ab77SEd Maste {
13988890ab77SEd Maste 	int error = 0;
13998890ab77SEd Maste 
14008890ab77SEd Maste 	switch (cmd) {
14018890ab77SEd Maste 	case DMAC_RESET:
14028890ab77SEd Maste 		CSR_WRITE_REG(sc, MGB_DMAC_CMD,
14038890ab77SEd Maste 		    MGB_DMAC_CMD_RESET(start, channel));
14048890ab77SEd Maste 		error = mgb_wait_for_bits(sc, MGB_DMAC_CMD, 0,
14058890ab77SEd Maste 		    MGB_DMAC_CMD_RESET(start, channel));
14068890ab77SEd Maste 		break;
14078890ab77SEd Maste 
14088890ab77SEd Maste 	case DMAC_START:
14098890ab77SEd Maste 		/*
14108890ab77SEd Maste 		 * NOTE: this simplifies the logic, since it will never
14118890ab77SEd Maste 		 * try to start in STOP_PENDING, but it also increases work.
14128890ab77SEd Maste 		 */
14138890ab77SEd Maste 		error = mgb_dmac_control(sc, start, channel, DMAC_STOP);
14148890ab77SEd Maste 		if (error != 0)
14158890ab77SEd Maste 			return error;
14168890ab77SEd Maste 		CSR_WRITE_REG(sc, MGB_DMAC_CMD,
14178890ab77SEd Maste 		    MGB_DMAC_CMD_START(start, channel));
14188890ab77SEd Maste 		break;
14198890ab77SEd Maste 
14208890ab77SEd Maste 	case DMAC_STOP:
14218890ab77SEd Maste 		CSR_WRITE_REG(sc, MGB_DMAC_CMD,
14228890ab77SEd Maste 		    MGB_DMAC_CMD_STOP(start, channel));
14238890ab77SEd Maste 		error = mgb_wait_for_bits(sc, MGB_DMAC_CMD,
14248890ab77SEd Maste 		    MGB_DMAC_CMD_STOP(start, channel),
14258890ab77SEd Maste 		    MGB_DMAC_CMD_START(start, channel));
14268890ab77SEd Maste 		break;
14278890ab77SEd Maste 	}
14288890ab77SEd Maste 	return error;
14298890ab77SEd Maste }
14308890ab77SEd Maste 
14318890ab77SEd Maste static int
14328890ab77SEd Maste mgb_fct_control(struct mgb_softc *sc, int reg, int channel,
14338890ab77SEd Maste     enum mgb_fct_cmd cmd)
14348890ab77SEd Maste {
14358890ab77SEd Maste 
14368890ab77SEd Maste 	switch (cmd) {
14378890ab77SEd Maste 	case FCT_RESET:
14388890ab77SEd Maste 		CSR_WRITE_REG(sc, reg, MGB_FCT_RESET(channel));
14398890ab77SEd Maste 		return mgb_wait_for_bits(sc, reg, 0, MGB_FCT_RESET(channel));
14408890ab77SEd Maste 	case FCT_ENABLE:
14418890ab77SEd Maste 		CSR_WRITE_REG(sc, reg, MGB_FCT_ENBL(channel));
14428890ab77SEd Maste 		return (0);
14438890ab77SEd Maste 	case FCT_DISABLE:
14448890ab77SEd Maste 		CSR_WRITE_REG(sc, reg, MGB_FCT_DSBL(channel));
14458890ab77SEd Maste 		return mgb_wait_for_bits(sc, reg, 0, MGB_FCT_ENBL(channel));
14468890ab77SEd Maste 	}
14478890ab77SEd Maste }
14488890ab77SEd Maste 
14498890ab77SEd Maste static int
14508890ab77SEd Maste mgb_hw_teardown(struct mgb_softc *sc)
14518890ab77SEd Maste {
14528890ab77SEd Maste 	int err = 0;
14538890ab77SEd Maste 
14548890ab77SEd Maste 	/* Stop MAC */
14558890ab77SEd Maste 	CSR_CLEAR_REG(sc, MGB_MAC_RX, MGB_MAC_ENBL);
14568890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_MAC_TX, MGB_MAC_ENBL);
14578890ab77SEd Maste 	if ((err = mgb_wait_for_bits(sc, MGB_MAC_RX, MGB_MAC_DSBL, 0)))
14588890ab77SEd Maste 		return (err);
14598890ab77SEd Maste 	if ((err = mgb_wait_for_bits(sc, MGB_MAC_TX, MGB_MAC_DSBL, 0)))
14608890ab77SEd Maste 		return (err);
14618890ab77SEd Maste 	return (err);
14628890ab77SEd Maste }
14638890ab77SEd Maste 
14648890ab77SEd Maste static int
14658890ab77SEd Maste mgb_hw_init(struct mgb_softc *sc)
14668890ab77SEd Maste {
14678890ab77SEd Maste 	int error = 0;
14688890ab77SEd Maste 
14698890ab77SEd Maste 	error = mgb_hw_reset(sc);
14708890ab77SEd Maste 	if (error != 0)
14718890ab77SEd Maste 		goto fail;
14728890ab77SEd Maste 
14738890ab77SEd Maste 	mgb_mac_init(sc);
14748890ab77SEd Maste 
14758890ab77SEd Maste 	error = mgb_phy_reset(sc);
14768890ab77SEd Maste 	if (error != 0)
14778890ab77SEd Maste 		goto fail;
14788890ab77SEd Maste 
14798890ab77SEd Maste 	error = mgb_dmac_reset(sc);
14808890ab77SEd Maste 	if (error != 0)
14818890ab77SEd Maste 		goto fail;
14828890ab77SEd Maste 
14838890ab77SEd Maste fail:
14848890ab77SEd Maste 	return error;
14858890ab77SEd Maste }
14868890ab77SEd Maste 
14878890ab77SEd Maste static int
14888890ab77SEd Maste mgb_hw_reset(struct mgb_softc *sc)
14898890ab77SEd Maste {
14908890ab77SEd Maste 
14918890ab77SEd Maste 	CSR_UPDATE_REG(sc, MGB_HW_CFG, MGB_LITE_RESET);
14928890ab77SEd Maste 	return (mgb_wait_for_bits(sc, MGB_HW_CFG, 0, MGB_LITE_RESET));
14938890ab77SEd Maste }
14948890ab77SEd Maste 
14958890ab77SEd Maste static int
14968890ab77SEd Maste mgb_mac_init(struct mgb_softc *sc)
14978890ab77SEd Maste {
14988890ab77SEd Maste 
14998890ab77SEd Maste 	/**
15008890ab77SEd Maste 	 * enable automatic duplex detection and
15018890ab77SEd Maste 	 * automatic speed detection
15028890ab77SEd Maste 	 */
15038890ab77SEd Maste 	CSR_UPDATE_REG(sc, MGB_MAC_CR, MGB_MAC_ADD_ENBL | MGB_MAC_ASD_ENBL);
15048890ab77SEd Maste 	CSR_UPDATE_REG(sc, MGB_MAC_TX, MGB_MAC_ENBL);
15058890ab77SEd Maste 	CSR_UPDATE_REG(sc, MGB_MAC_RX, MGB_MAC_ENBL);
15068890ab77SEd Maste 
15078890ab77SEd Maste 	return MGB_STS_OK;
15088890ab77SEd Maste }
15098890ab77SEd Maste 
15108890ab77SEd Maste static int
15118890ab77SEd Maste mgb_phy_reset(struct mgb_softc *sc)
15128890ab77SEd Maste {
15138890ab77SEd Maste 
15148890ab77SEd Maste 	CSR_UPDATE_BYTE(sc, MGB_PMT_CTL, MGB_PHY_RESET);
15158890ab77SEd Maste 	if (mgb_wait_for_bits(sc, MGB_PMT_CTL, 0, MGB_PHY_RESET) ==
15168890ab77SEd Maste 	    MGB_STS_TIMEOUT)
15178890ab77SEd Maste 		return MGB_STS_TIMEOUT;
15188890ab77SEd Maste 	return (mgb_wait_for_bits(sc, MGB_PMT_CTL, MGB_PHY_READY, 0));
15198890ab77SEd Maste }
15208890ab77SEd Maste 
15218890ab77SEd Maste static int
15228890ab77SEd Maste mgb_dmac_reset(struct mgb_softc *sc)
15238890ab77SEd Maste {
15248890ab77SEd Maste 
15258890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_DMAC_CMD, MGB_DMAC_RESET);
15268890ab77SEd Maste 	return (mgb_wait_for_bits(sc, MGB_DMAC_CMD, 0, MGB_DMAC_RESET));
15278890ab77SEd Maste }
15288890ab77SEd Maste 
15298890ab77SEd Maste static int
15308890ab77SEd Maste mgb_wait_for_bits(struct mgb_softc *sc, int reg, int set_bits, int clear_bits)
15318890ab77SEd Maste {
15328890ab77SEd Maste 	int i, val;
15338890ab77SEd Maste 
15348890ab77SEd Maste 	i = 0;
15358890ab77SEd Maste 	do {
15368890ab77SEd Maste 		/*
15378890ab77SEd Maste 		 * XXX: Datasheets states delay should be > 5 microseconds
15388890ab77SEd Maste 		 * for device reset.
15398890ab77SEd Maste 		 */
15408890ab77SEd Maste 		DELAY(100);
15418890ab77SEd Maste 		val = CSR_READ_REG(sc, reg);
15428890ab77SEd Maste 		if ((val & set_bits) == set_bits &&
15438890ab77SEd Maste 		    (val & clear_bits) == 0)
15448890ab77SEd Maste 			return MGB_STS_OK;
15458890ab77SEd Maste 	} while (i++ < MGB_TIMEOUT);
15468890ab77SEd Maste 
15478890ab77SEd Maste 	return MGB_STS_TIMEOUT;
15488890ab77SEd Maste }
15498890ab77SEd Maste 
15508890ab77SEd Maste static void
15518890ab77SEd Maste mgb_get_ethaddr(struct mgb_softc *sc, struct ether_addr *dest)
15528890ab77SEd Maste {
15538890ab77SEd Maste 
15548890ab77SEd Maste 	CSR_READ_REG_BYTES(sc, MGB_MAC_ADDR_BASE_L, &dest->octet[0], 4);
15558890ab77SEd Maste 	CSR_READ_REG_BYTES(sc, MGB_MAC_ADDR_BASE_H, &dest->octet[4], 2);
15568890ab77SEd Maste }
15578890ab77SEd Maste 
15588890ab77SEd Maste static int
15598890ab77SEd Maste mgb_miibus_readreg(device_t dev, int phy, int reg)
15608890ab77SEd Maste {
15618890ab77SEd Maste 	struct mgb_softc *sc;
15628890ab77SEd Maste 	int mii_access;
15638890ab77SEd Maste 
15648890ab77SEd Maste 	sc = iflib_get_softc(device_get_softc(dev));
15658890ab77SEd Maste 
15668890ab77SEd Maste 	if (mgb_wait_for_bits(sc, MGB_MII_ACCESS, 0, MGB_MII_BUSY) ==
15678890ab77SEd Maste 	    MGB_STS_TIMEOUT)
15688890ab77SEd Maste 		return EIO;
15698890ab77SEd Maste 	mii_access = (phy & MGB_MII_PHY_ADDR_MASK) << MGB_MII_PHY_ADDR_SHIFT;
15708890ab77SEd Maste 	mii_access |= (reg & MGB_MII_REG_ADDR_MASK) << MGB_MII_REG_ADDR_SHIFT;
15718890ab77SEd Maste 	mii_access |= MGB_MII_BUSY | MGB_MII_READ;
15728890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_MII_ACCESS, mii_access);
15738890ab77SEd Maste 	if (mgb_wait_for_bits(sc, MGB_MII_ACCESS, 0, MGB_MII_BUSY) ==
15748890ab77SEd Maste 	    MGB_STS_TIMEOUT)
15758890ab77SEd Maste 		return EIO;
15768890ab77SEd Maste 	return (CSR_READ_2_BYTES(sc, MGB_MII_DATA));
15778890ab77SEd Maste }
15788890ab77SEd Maste 
15798890ab77SEd Maste static int
15808890ab77SEd Maste mgb_miibus_writereg(device_t dev, int phy, int reg, int data)
15818890ab77SEd Maste {
15828890ab77SEd Maste 	struct mgb_softc *sc;
15838890ab77SEd Maste 	int mii_access;
15848890ab77SEd Maste 
15858890ab77SEd Maste 	sc = iflib_get_softc(device_get_softc(dev));
15868890ab77SEd Maste 
15878890ab77SEd Maste 	if (mgb_wait_for_bits(sc, MGB_MII_ACCESS,
15888890ab77SEd Maste 	    0, MGB_MII_BUSY) == MGB_STS_TIMEOUT)
15898890ab77SEd Maste 		return EIO;
15908890ab77SEd Maste 	mii_access = (phy & MGB_MII_PHY_ADDR_MASK) << MGB_MII_PHY_ADDR_SHIFT;
15918890ab77SEd Maste 	mii_access |= (reg & MGB_MII_REG_ADDR_MASK) << MGB_MII_REG_ADDR_SHIFT;
15928890ab77SEd Maste 	mii_access |= MGB_MII_BUSY | MGB_MII_WRITE;
15938890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_MII_DATA, data);
15948890ab77SEd Maste 	CSR_WRITE_REG(sc, MGB_MII_ACCESS, mii_access);
15958890ab77SEd Maste 	if (mgb_wait_for_bits(sc, MGB_MII_ACCESS, 0, MGB_MII_BUSY) ==
15968890ab77SEd Maste 	    MGB_STS_TIMEOUT)
15978890ab77SEd Maste 		return EIO;
15988890ab77SEd Maste 	return 0;
15998890ab77SEd Maste }
16008890ab77SEd Maste 
16018890ab77SEd Maste /* XXX: May need to lock these up */
16028890ab77SEd Maste static void
16038890ab77SEd Maste mgb_miibus_statchg(device_t dev)
16048890ab77SEd Maste {
16058890ab77SEd Maste 	struct mgb_softc *sc;
16068890ab77SEd Maste 	struct mii_data *miid;
16078890ab77SEd Maste 
16088890ab77SEd Maste 	sc = iflib_get_softc(device_get_softc(dev));
16098890ab77SEd Maste 	miid = device_get_softc(sc->miibus);
16108890ab77SEd Maste 	/* Update baudrate in iflib */
16118890ab77SEd Maste 	sc->baudrate = ifmedia_baudrate(miid->mii_media_active);
16128890ab77SEd Maste 	iflib_link_state_change(sc->ctx, sc->link_state, sc->baudrate);
16138890ab77SEd Maste }
16148890ab77SEd Maste 
16158890ab77SEd Maste static void
16168890ab77SEd Maste mgb_miibus_linkchg(device_t dev)
16178890ab77SEd Maste {
16188890ab77SEd Maste 	struct mgb_softc *sc;
16198890ab77SEd Maste 	struct mii_data *miid;
16208890ab77SEd Maste 	int link_state;
16218890ab77SEd Maste 
16228890ab77SEd Maste 	sc = iflib_get_softc(device_get_softc(dev));
16238890ab77SEd Maste 	miid = device_get_softc(sc->miibus);
16248890ab77SEd Maste 	/* XXX: copied from miibus_linkchg **/
16258890ab77SEd Maste 	if (miid->mii_media_status & IFM_AVALID) {
16268890ab77SEd Maste 		if (miid->mii_media_status & IFM_ACTIVE)
16278890ab77SEd Maste 			link_state = LINK_STATE_UP;
16288890ab77SEd Maste 		else
16298890ab77SEd Maste 			link_state = LINK_STATE_DOWN;
16308890ab77SEd Maste 	} else
16318890ab77SEd Maste 		link_state = LINK_STATE_UNKNOWN;
16328890ab77SEd Maste 	sc->link_state = link_state;
16338890ab77SEd Maste 	iflib_link_state_change(sc->ctx, sc->link_state, sc->baudrate);
16348890ab77SEd Maste }
1635