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