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