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