xref: /freebsd-src/sys/dev/mge/if_mge.c (revision 18250ec6c089c0c50cbd9fd87d78e03ff89916df)
19f55f5f5SRafal Jaworowski /*-
27282444bSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
37282444bSPedro F. Giffuni  *
49f55f5f5SRafal Jaworowski  * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
53c71b84fSZbigniew Bodek  * Copyright (C) 2009-2015 Semihalf
63c71b84fSZbigniew Bodek  * Copyright (C) 2015 Stormshield
79f55f5f5SRafal Jaworowski  * All rights reserved.
89f55f5f5SRafal Jaworowski  *
99f55f5f5SRafal Jaworowski  * Developed by Semihalf.
109f55f5f5SRafal Jaworowski  *
119f55f5f5SRafal Jaworowski  * Redistribution and use in source and binary forms, with or without
129f55f5f5SRafal Jaworowski  * modification, are permitted provided that the following conditions
139f55f5f5SRafal Jaworowski  * are met:
149f55f5f5SRafal Jaworowski  * 1. Redistributions of source code must retain the above copyright
159f55f5f5SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer.
169f55f5f5SRafal Jaworowski  * 2. Redistributions in binary form must reproduce the above copyright
179f55f5f5SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer in the
189f55f5f5SRafal Jaworowski  *    documentation and/or other materials provided with the distribution.
199f55f5f5SRafal Jaworowski  * 3. Neither the name of MARVELL nor the names of contributors
209f55f5f5SRafal Jaworowski  *    may be used to endorse or promote products derived from this software
219f55f5f5SRafal Jaworowski  *    without specific prior written permission.
229f55f5f5SRafal Jaworowski  *
239f55f5f5SRafal Jaworowski  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
249f55f5f5SRafal Jaworowski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
259f55f5f5SRafal Jaworowski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
269f55f5f5SRafal Jaworowski  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
279f55f5f5SRafal Jaworowski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
289f55f5f5SRafal Jaworowski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
299f55f5f5SRafal Jaworowski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
309f55f5f5SRafal Jaworowski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
319f55f5f5SRafal Jaworowski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
329f55f5f5SRafal Jaworowski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
339f55f5f5SRafal Jaworowski  * SUCH DAMAGE.
349f55f5f5SRafal Jaworowski  */
359f55f5f5SRafal Jaworowski 
369f55f5f5SRafal Jaworowski #ifdef HAVE_KERNEL_OPTION_HEADERS
379f55f5f5SRafal Jaworowski #include "opt_device_polling.h"
389f55f5f5SRafal Jaworowski #endif
399f55f5f5SRafal Jaworowski 
409f55f5f5SRafal Jaworowski #include <sys/param.h>
419f55f5f5SRafal Jaworowski #include <sys/systm.h>
429f55f5f5SRafal Jaworowski #include <sys/endian.h>
439f55f5f5SRafal Jaworowski #include <sys/mbuf.h>
449f55f5f5SRafal Jaworowski #include <sys/lock.h>
459f55f5f5SRafal Jaworowski #include <sys/mutex.h>
469f55f5f5SRafal Jaworowski #include <sys/kernel.h>
479f55f5f5SRafal Jaworowski #include <sys/module.h>
489f55f5f5SRafal Jaworowski #include <sys/socket.h>
499f55f5f5SRafal Jaworowski #include <sys/sysctl.h>
509f55f5f5SRafal Jaworowski 
519f55f5f5SRafal Jaworowski #include <net/ethernet.h>
529f55f5f5SRafal Jaworowski #include <net/bpf.h>
539f55f5f5SRafal Jaworowski #include <net/if.h>
549f55f5f5SRafal Jaworowski #include <net/if_arp.h>
559f55f5f5SRafal Jaworowski #include <net/if_dl.h>
569f55f5f5SRafal Jaworowski #include <net/if_media.h>
579f55f5f5SRafal Jaworowski #include <net/if_types.h>
589f55f5f5SRafal Jaworowski #include <net/if_vlan_var.h>
599f55f5f5SRafal Jaworowski 
609f55f5f5SRafal Jaworowski #include <netinet/in_systm.h>
619f55f5f5SRafal Jaworowski #include <netinet/in.h>
629f55f5f5SRafal Jaworowski #include <netinet/ip.h>
639f55f5f5SRafal Jaworowski 
649f55f5f5SRafal Jaworowski #include <sys/sockio.h>
659f55f5f5SRafal Jaworowski #include <sys/bus.h>
669f55f5f5SRafal Jaworowski #include <machine/bus.h>
679f55f5f5SRafal Jaworowski #include <sys/rman.h>
689f55f5f5SRafal Jaworowski #include <machine/resource.h>
699f55f5f5SRafal Jaworowski 
709f55f5f5SRafal Jaworowski #include <dev/mii/mii.h>
719f55f5f5SRafal Jaworowski #include <dev/mii/miivar.h>
729f55f5f5SRafal Jaworowski 
73db5ef4fcSRafal Jaworowski #include <dev/fdt/fdt_common.h>
74db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus.h>
75db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h>
7671e8eac4SAdrian Chadd #include <dev/mdio/mdio.h>
779f55f5f5SRafal Jaworowski 
789f55f5f5SRafal Jaworowski #include <dev/mge/if_mgevar.h>
799f55f5f5SRafal Jaworowski #include <arm/mv/mvreg.h>
808e1dc58eSRafal Jaworowski #include <arm/mv/mvvar.h>
819f55f5f5SRafal Jaworowski 
829f55f5f5SRafal Jaworowski #include "miibus_if.h"
833c71b84fSZbigniew Bodek #include "mdio_if.h"
843c71b84fSZbigniew Bodek 
853c71b84fSZbigniew Bodek #define	MGE_DELAY(x)	pause("SMI access sleep", (x) / tick_sbt)
869f55f5f5SRafal Jaworowski 
879f55f5f5SRafal Jaworowski static int mge_probe(device_t dev);
889f55f5f5SRafal Jaworowski static int mge_attach(device_t dev);
899f55f5f5SRafal Jaworowski static int mge_detach(device_t dev);
909f55f5f5SRafal Jaworowski static int mge_shutdown(device_t dev);
919f55f5f5SRafal Jaworowski static int mge_suspend(device_t dev);
929f55f5f5SRafal Jaworowski static int mge_resume(device_t dev);
939f55f5f5SRafal Jaworowski 
949f55f5f5SRafal Jaworowski static int mge_miibus_readreg(device_t dev, int phy, int reg);
958e45f0b7SAndriy Gapon static int mge_miibus_writereg(device_t dev, int phy, int reg, int value);
969f55f5f5SRafal Jaworowski 
973c71b84fSZbigniew Bodek static int mge_mdio_readreg(device_t dev, int phy, int reg);
983c71b84fSZbigniew Bodek static int mge_mdio_writereg(device_t dev, int phy, int reg, int value);
993c71b84fSZbigniew Bodek 
10098fe10c8SJustin Hibbits static int mge_ifmedia_upd(if_t ifp);
10198fe10c8SJustin Hibbits static void mge_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr);
1029f55f5f5SRafal Jaworowski 
1039f55f5f5SRafal Jaworowski static void mge_init(void *arg);
1049f55f5f5SRafal Jaworowski static void mge_init_locked(void *arg);
10598fe10c8SJustin Hibbits static void mge_start(if_t ifp);
10698fe10c8SJustin Hibbits static void mge_start_locked(if_t ifp);
1079f55f5f5SRafal Jaworowski static void mge_watchdog(struct mge_softc *sc);
10898fe10c8SJustin Hibbits static int mge_ioctl(if_t ifp, u_long command, caddr_t data);
1099f55f5f5SRafal Jaworowski 
1108e1dc58eSRafal Jaworowski static uint32_t mge_tfut_ipg(uint32_t val, int ver);
1118e1dc58eSRafal Jaworowski static uint32_t mge_rx_ipg(uint32_t val, int ver);
1128e1dc58eSRafal Jaworowski static void mge_ver_params(struct mge_softc *sc);
1138e1dc58eSRafal Jaworowski 
1149f55f5f5SRafal Jaworowski static void mge_intrs_ctrl(struct mge_softc *sc, int enable);
11575f1438bSOleksandr Tymoshenko static void mge_intr_rxtx(void *arg);
1169f55f5f5SRafal Jaworowski static void mge_intr_rx(void *arg);
11775f1438bSOleksandr Tymoshenko static void mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause,
11875f1438bSOleksandr Tymoshenko     uint32_t int_cause_ext);
1191abcdbd1SAttilio Rao static int mge_intr_rx_locked(struct mge_softc *sc, int count);
1209f55f5f5SRafal Jaworowski static void mge_intr_tx(void *arg);
1219f55f5f5SRafal Jaworowski static void mge_intr_tx_locked(struct mge_softc *sc);
1229f55f5f5SRafal Jaworowski static void mge_intr_misc(void *arg);
1239f55f5f5SRafal Jaworowski static void mge_intr_sum(void *arg);
1249f55f5f5SRafal Jaworowski static void mge_intr_err(void *arg);
1259f55f5f5SRafal Jaworowski static void mge_stop(struct mge_softc *sc);
1269f55f5f5SRafal Jaworowski static void mge_tick(void *msc);
1279f55f5f5SRafal Jaworowski static uint32_t mge_set_port_serial_control(uint32_t media);
1289f55f5f5SRafal Jaworowski static void mge_get_mac_address(struct mge_softc *sc, uint8_t *addr);
1299f55f5f5SRafal Jaworowski static void mge_set_mac_address(struct mge_softc *sc);
1309f55f5f5SRafal Jaworowski static void mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte,
1319f55f5f5SRafal Jaworowski     uint8_t queue);
1329f55f5f5SRafal Jaworowski static void mge_set_prom_mode(struct mge_softc *sc, uint8_t queue);
1339f55f5f5SRafal Jaworowski static int mge_allocate_dma(struct mge_softc *sc);
1349f55f5f5SRafal Jaworowski static int mge_alloc_desc_dma(struct mge_softc *sc,
1354ac30cc1SZbigniew Bodek     struct mge_desc_wrapper* desc_tab, uint32_t size,
1364ac30cc1SZbigniew Bodek     bus_dma_tag_t *buffer_tag);
1379f55f5f5SRafal Jaworowski static int mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map,
1389f55f5f5SRafal Jaworowski     struct mbuf **mbufp, bus_addr_t *paddr);
1394ac30cc1SZbigniew Bodek static void mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg,
1404ac30cc1SZbigniew Bodek     int error);
1419f55f5f5SRafal Jaworowski static void mge_free_dma(struct mge_softc *sc);
1424ac30cc1SZbigniew Bodek static void mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab,
1434ac30cc1SZbigniew Bodek     uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs);
14498fe10c8SJustin Hibbits static void mge_offload_process_frame(if_t ifp, struct mbuf *frame,
1459f55f5f5SRafal Jaworowski     uint32_t status, uint16_t bufsize);
1469f55f5f5SRafal Jaworowski static void mge_offload_setup_descriptor(struct mge_softc *sc,
1479f55f5f5SRafal Jaworowski     struct mge_desc_wrapper *dw);
1489f55f5f5SRafal Jaworowski static uint8_t mge_crc8(uint8_t *data, int size);
1499f55f5f5SRafal Jaworowski static void mge_setup_multicast(struct mge_softc *sc);
1509f55f5f5SRafal Jaworowski static void mge_set_rxic(struct mge_softc *sc);
1519f55f5f5SRafal Jaworowski static void mge_set_txic(struct mge_softc *sc);
1529f55f5f5SRafal Jaworowski static void mge_add_sysctls(struct mge_softc *sc);
1539f55f5f5SRafal Jaworowski static int mge_sysctl_ic(SYSCTL_HANDLER_ARGS);
1549f55f5f5SRafal Jaworowski 
1559f55f5f5SRafal Jaworowski static device_method_t mge_methods[] = {
1569f55f5f5SRafal Jaworowski 	/* Device interface */
1579f55f5f5SRafal Jaworowski 	DEVMETHOD(device_probe,		mge_probe),
1589f55f5f5SRafal Jaworowski 	DEVMETHOD(device_attach,	mge_attach),
1599f55f5f5SRafal Jaworowski 	DEVMETHOD(device_detach,	mge_detach),
1609f55f5f5SRafal Jaworowski 	DEVMETHOD(device_shutdown,	mge_shutdown),
1619f55f5f5SRafal Jaworowski 	DEVMETHOD(device_suspend,	mge_suspend),
1629f55f5f5SRafal Jaworowski 	DEVMETHOD(device_resume,	mge_resume),
1639f55f5f5SRafal Jaworowski 	/* MII interface */
1649f55f5f5SRafal Jaworowski 	DEVMETHOD(miibus_readreg,	mge_miibus_readreg),
1659f55f5f5SRafal Jaworowski 	DEVMETHOD(miibus_writereg,	mge_miibus_writereg),
1663c71b84fSZbigniew Bodek 	/* MDIO interface */
1673c71b84fSZbigniew Bodek 	DEVMETHOD(mdio_readreg,		mge_mdio_readreg),
1683c71b84fSZbigniew Bodek 	DEVMETHOD(mdio_writereg,	mge_mdio_writereg),
1699f55f5f5SRafal Jaworowski 	{ 0, 0 }
1709f55f5f5SRafal Jaworowski };
1719f55f5f5SRafal Jaworowski 
1723c71b84fSZbigniew Bodek DEFINE_CLASS_0(mge, mge_driver, mge_methods, sizeof(struct mge_softc));
1739f55f5f5SRafal Jaworowski 
1743c71b84fSZbigniew Bodek static int switch_attached = 0;
1759f55f5f5SRafal Jaworowski 
1768059bf7bSJohn Baldwin DRIVER_MODULE(mge, simplebus, mge_driver, 0, 0);
1773e38757dSJohn Baldwin DRIVER_MODULE(miibus, mge, miibus_driver, 0, 0);
1788933f7d6SJohn Baldwin DRIVER_MODULE(mdio, mge, mdio_driver, 0, 0);
1799f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, ether, 1, 1, 1);
1809f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, miibus, 1, 1, 1);
1813c71b84fSZbigniew Bodek MODULE_DEPEND(mge, mdio, 1, 1, 1);
1829f55f5f5SRafal Jaworowski 
1839f55f5f5SRafal Jaworowski static struct resource_spec res_spec[] = {
1849f55f5f5SRafal Jaworowski 	{ SYS_RES_MEMORY, 0, RF_ACTIVE },
1859f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
1869f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE },
1879f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE },
1889f55f5f5SRafal Jaworowski 	{ -1, 0 }
1899f55f5f5SRafal Jaworowski };
1909f55f5f5SRafal Jaworowski 
1919f55f5f5SRafal Jaworowski static struct {
1929f55f5f5SRafal Jaworowski 	driver_intr_t *handler;
1939f55f5f5SRafal Jaworowski 	char * description;
19475f1438bSOleksandr Tymoshenko } mge_intrs[MGE_INTR_COUNT + 1] = {
19575f1438bSOleksandr Tymoshenko 	{ mge_intr_rxtx,"GbE aggregated interrupt" },
1969f55f5f5SRafal Jaworowski 	{ mge_intr_rx,	"GbE receive interrupt" },
1979f55f5f5SRafal Jaworowski 	{ mge_intr_tx,	"GbE transmit interrupt" },
1989f55f5f5SRafal Jaworowski 	{ mge_intr_misc,"GbE misc interrupt" },
1999f55f5f5SRafal Jaworowski 	{ mge_intr_sum,	"GbE summary interrupt" },
2009f55f5f5SRafal Jaworowski 	{ mge_intr_err,	"GbE error interrupt" },
2019f55f5f5SRafal Jaworowski };
2029f55f5f5SRafal Jaworowski 
2033c71b84fSZbigniew Bodek /* SMI access interlock */
2043c71b84fSZbigniew Bodek static struct sx sx_smi;
2053c71b84fSZbigniew Bodek 
2063c71b84fSZbigniew Bodek static uint32_t
2073c71b84fSZbigniew Bodek mv_read_ge_smi(device_t dev, int phy, int reg)
2083c71b84fSZbigniew Bodek {
2093c71b84fSZbigniew Bodek 	uint32_t timeout;
2103c71b84fSZbigniew Bodek 	uint32_t ret;
2113c71b84fSZbigniew Bodek 	struct mge_softc *sc;
2123c71b84fSZbigniew Bodek 
2133c71b84fSZbigniew Bodek 	sc = device_get_softc(dev);
2143c71b84fSZbigniew Bodek 	KASSERT(sc != NULL, ("NULL softc ptr!"));
2153c71b84fSZbigniew Bodek 	timeout = MGE_SMI_WRITE_RETRIES;
2163c71b84fSZbigniew Bodek 
2173c71b84fSZbigniew Bodek 	MGE_SMI_LOCK();
2183c71b84fSZbigniew Bodek 	while (--timeout &&
2193c71b84fSZbigniew Bodek 	    (MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_BUSY))
2203c71b84fSZbigniew Bodek 		MGE_DELAY(MGE_SMI_WRITE_DELAY);
2213c71b84fSZbigniew Bodek 
2223c71b84fSZbigniew Bodek 	if (timeout == 0) {
2233c71b84fSZbigniew Bodek 		device_printf(dev, "SMI write timeout.\n");
2243c71b84fSZbigniew Bodek 		ret = ~0U;
2253c71b84fSZbigniew Bodek 		goto out;
2263c71b84fSZbigniew Bodek 	}
2273c71b84fSZbigniew Bodek 
2283c71b84fSZbigniew Bodek 	MGE_WRITE(sc, MGE_REG_SMI, MGE_SMI_MASK &
2293c71b84fSZbigniew Bodek 	    (MGE_SMI_READ | (reg << 21) | (phy << 16)));
2303c71b84fSZbigniew Bodek 
2313c71b84fSZbigniew Bodek 	/* Wait till finished. */
2323c71b84fSZbigniew Bodek 	timeout = MGE_SMI_WRITE_RETRIES;
2333c71b84fSZbigniew Bodek 	while (--timeout &&
2343c71b84fSZbigniew Bodek 	    !((MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_READVALID)))
2353c71b84fSZbigniew Bodek 		MGE_DELAY(MGE_SMI_WRITE_DELAY);
2363c71b84fSZbigniew Bodek 
2373c71b84fSZbigniew Bodek 	if (timeout == 0) {
2383c71b84fSZbigniew Bodek 		device_printf(dev, "SMI write validation timeout.\n");
2393c71b84fSZbigniew Bodek 		ret = ~0U;
2403c71b84fSZbigniew Bodek 		goto out;
2413c71b84fSZbigniew Bodek 	}
2423c71b84fSZbigniew Bodek 
2433c71b84fSZbigniew Bodek 	/* Wait for the data to update in the SMI register */
2443c71b84fSZbigniew Bodek 	MGE_DELAY(MGE_SMI_DELAY);
2453c71b84fSZbigniew Bodek 	ret = MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_DATA_MASK;
2463c71b84fSZbigniew Bodek 
2473c71b84fSZbigniew Bodek out:
2483c71b84fSZbigniew Bodek 	MGE_SMI_UNLOCK();
2493c71b84fSZbigniew Bodek 	return (ret);
2503c71b84fSZbigniew Bodek 
2513c71b84fSZbigniew Bodek }
2523c71b84fSZbigniew Bodek 
2533c71b84fSZbigniew Bodek static void
2543c71b84fSZbigniew Bodek mv_write_ge_smi(device_t dev, int phy, int reg, uint32_t value)
2553c71b84fSZbigniew Bodek {
2563c71b84fSZbigniew Bodek 	uint32_t timeout;
2573c71b84fSZbigniew Bodek 	struct mge_softc *sc;
2583c71b84fSZbigniew Bodek 
2593c71b84fSZbigniew Bodek 	sc = device_get_softc(dev);
2603c71b84fSZbigniew Bodek 	KASSERT(sc != NULL, ("NULL softc ptr!"));
2613c71b84fSZbigniew Bodek 
2623c71b84fSZbigniew Bodek 	MGE_SMI_LOCK();
2633c71b84fSZbigniew Bodek 	timeout = MGE_SMI_READ_RETRIES;
2643c71b84fSZbigniew Bodek 	while (--timeout &&
2653c71b84fSZbigniew Bodek 	    (MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_BUSY))
2663c71b84fSZbigniew Bodek 		MGE_DELAY(MGE_SMI_READ_DELAY);
2673c71b84fSZbigniew Bodek 
2683c71b84fSZbigniew Bodek 	if (timeout == 0) {
2693c71b84fSZbigniew Bodek 		device_printf(dev, "SMI read timeout.\n");
2703c71b84fSZbigniew Bodek 		goto out;
2713c71b84fSZbigniew Bodek 	}
2723c71b84fSZbigniew Bodek 
2733c71b84fSZbigniew Bodek 	MGE_WRITE(sc, MGE_REG_SMI, MGE_SMI_MASK &
2743c71b84fSZbigniew Bodek 	    (MGE_SMI_WRITE | (reg << 21) | (phy << 16) |
2753c71b84fSZbigniew Bodek 	    (value & MGE_SMI_DATA_MASK)));
2763c71b84fSZbigniew Bodek 
2773c71b84fSZbigniew Bodek out:
2783c71b84fSZbigniew Bodek 	MGE_SMI_UNLOCK();
2793c71b84fSZbigniew Bodek }
2803c71b84fSZbigniew Bodek 
2813c71b84fSZbigniew Bodek static int
2823c71b84fSZbigniew Bodek mv_read_ext_phy(device_t dev, int phy, int reg)
2833c71b84fSZbigniew Bodek {
2843c71b84fSZbigniew Bodek 	uint32_t retries;
2853c71b84fSZbigniew Bodek 	struct mge_softc *sc;
2863c71b84fSZbigniew Bodek 	uint32_t ret;
2873c71b84fSZbigniew Bodek 
2883c71b84fSZbigniew Bodek 	sc = device_get_softc(dev);
2893c71b84fSZbigniew Bodek 
2903c71b84fSZbigniew Bodek 	MGE_SMI_LOCK();
2913c71b84fSZbigniew Bodek 	MGE_WRITE(sc->phy_sc, MGE_REG_SMI, MGE_SMI_MASK &
2923c71b84fSZbigniew Bodek 	    (MGE_SMI_READ | (reg << 21) | (phy << 16)));
2933c71b84fSZbigniew Bodek 
2943c71b84fSZbigniew Bodek 	retries = MGE_SMI_READ_RETRIES;
2953c71b84fSZbigniew Bodek 	while (--retries &&
2963c71b84fSZbigniew Bodek 	    !(MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_READVALID))
2973c71b84fSZbigniew Bodek 		DELAY(MGE_SMI_READ_DELAY);
2983c71b84fSZbigniew Bodek 
2993c71b84fSZbigniew Bodek 	if (retries == 0)
3003c71b84fSZbigniew Bodek 		device_printf(dev, "Timeout while reading from PHY\n");
3013c71b84fSZbigniew Bodek 
3023c71b84fSZbigniew Bodek 	ret = MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_DATA_MASK;
3033c71b84fSZbigniew Bodek 	MGE_SMI_UNLOCK();
3043c71b84fSZbigniew Bodek 
3053c71b84fSZbigniew Bodek 	return (ret);
3063c71b84fSZbigniew Bodek }
3073c71b84fSZbigniew Bodek 
3083c71b84fSZbigniew Bodek static void
3093c71b84fSZbigniew Bodek mv_write_ext_phy(device_t dev, int phy, int reg, int value)
3103c71b84fSZbigniew Bodek {
3113c71b84fSZbigniew Bodek 	uint32_t retries;
3123c71b84fSZbigniew Bodek 	struct mge_softc *sc;
3133c71b84fSZbigniew Bodek 
3143c71b84fSZbigniew Bodek 	sc = device_get_softc(dev);
3153c71b84fSZbigniew Bodek 
3163c71b84fSZbigniew Bodek 	MGE_SMI_LOCK();
3173c71b84fSZbigniew Bodek 	MGE_WRITE(sc->phy_sc, MGE_REG_SMI, MGE_SMI_MASK &
3183c71b84fSZbigniew Bodek 	    (MGE_SMI_WRITE | (reg << 21) | (phy << 16) |
3193c71b84fSZbigniew Bodek 	    (value & MGE_SMI_DATA_MASK)));
3203c71b84fSZbigniew Bodek 
3213c71b84fSZbigniew Bodek 	retries = MGE_SMI_WRITE_RETRIES;
3223c71b84fSZbigniew Bodek 	while (--retries && MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_BUSY)
3233c71b84fSZbigniew Bodek 		DELAY(MGE_SMI_WRITE_DELAY);
3243c71b84fSZbigniew Bodek 
3253c71b84fSZbigniew Bodek 	if (retries == 0)
3263c71b84fSZbigniew Bodek 		device_printf(dev, "Timeout while writing to PHY\n");
3273c71b84fSZbigniew Bodek 	MGE_SMI_UNLOCK();
3283c71b84fSZbigniew Bodek }
3293c71b84fSZbigniew Bodek 
3309f55f5f5SRafal Jaworowski static void
3319f55f5f5SRafal Jaworowski mge_get_mac_address(struct mge_softc *sc, uint8_t *addr)
3329f55f5f5SRafal Jaworowski {
3339f55f5f5SRafal Jaworowski 	uint32_t mac_l, mac_h;
334db5ef4fcSRafal Jaworowski 	uint8_t lmac[6];
335db5ef4fcSRafal Jaworowski 	int i, valid;
3369f55f5f5SRafal Jaworowski 
337db5ef4fcSRafal Jaworowski 	/*
338db5ef4fcSRafal Jaworowski 	 * Retrieve hw address from the device tree.
339db5ef4fcSRafal Jaworowski 	 */
340db5ef4fcSRafal Jaworowski 	i = OF_getprop(sc->node, "local-mac-address", (void *)lmac, 6);
341db5ef4fcSRafal Jaworowski 	if (i == 6) {
342db5ef4fcSRafal Jaworowski 		valid = 0;
343db5ef4fcSRafal Jaworowski 		for (i = 0; i < 6; i++)
344db5ef4fcSRafal Jaworowski 			if (lmac[i] != 0) {
345db5ef4fcSRafal Jaworowski 				valid = 1;
346db5ef4fcSRafal Jaworowski 				break;
347db5ef4fcSRafal Jaworowski 			}
3489f55f5f5SRafal Jaworowski 
349db5ef4fcSRafal Jaworowski 		if (valid) {
350db5ef4fcSRafal Jaworowski 			bcopy(lmac, addr, 6);
351db5ef4fcSRafal Jaworowski 			return;
352db5ef4fcSRafal Jaworowski 		}
353db5ef4fcSRafal Jaworowski 	}
354db5ef4fcSRafal Jaworowski 
355db5ef4fcSRafal Jaworowski 	/*
356db5ef4fcSRafal Jaworowski 	 * Fall back -- use the currently programmed address.
357db5ef4fcSRafal Jaworowski 	 */
3589f55f5f5SRafal Jaworowski 	mac_l = MGE_READ(sc, MGE_MAC_ADDR_L);
3599f55f5f5SRafal Jaworowski 	mac_h = MGE_READ(sc, MGE_MAC_ADDR_H);
3609f55f5f5SRafal Jaworowski 
3619f55f5f5SRafal Jaworowski 	addr[0] = (mac_h & 0xff000000) >> 24;
3629f55f5f5SRafal Jaworowski 	addr[1] = (mac_h & 0x00ff0000) >> 16;
3639f55f5f5SRafal Jaworowski 	addr[2] = (mac_h & 0x0000ff00) >> 8;
3649f55f5f5SRafal Jaworowski 	addr[3] = (mac_h & 0x000000ff);
3659f55f5f5SRafal Jaworowski 	addr[4] = (mac_l & 0x0000ff00) >> 8;
3669f55f5f5SRafal Jaworowski 	addr[5] = (mac_l & 0x000000ff);
3679f55f5f5SRafal Jaworowski }
3689f55f5f5SRafal Jaworowski 
3698e1dc58eSRafal Jaworowski static uint32_t
3708e1dc58eSRafal Jaworowski mge_tfut_ipg(uint32_t val, int ver)
3718e1dc58eSRafal Jaworowski {
3728e1dc58eSRafal Jaworowski 
3738e1dc58eSRafal Jaworowski 	switch (ver) {
3748e1dc58eSRafal Jaworowski 	case 1:
3758e1dc58eSRafal Jaworowski 		return ((val & 0x3fff) << 4);
3768e1dc58eSRafal Jaworowski 	case 2:
3778e1dc58eSRafal Jaworowski 	default:
3788e1dc58eSRafal Jaworowski 		return ((val & 0xffff) << 4);
3798e1dc58eSRafal Jaworowski 	}
3808e1dc58eSRafal Jaworowski }
3818e1dc58eSRafal Jaworowski 
3828e1dc58eSRafal Jaworowski static uint32_t
3838e1dc58eSRafal Jaworowski mge_rx_ipg(uint32_t val, int ver)
3848e1dc58eSRafal Jaworowski {
3858e1dc58eSRafal Jaworowski 
3868e1dc58eSRafal Jaworowski 	switch (ver) {
3878e1dc58eSRafal Jaworowski 	case 1:
3888e1dc58eSRafal Jaworowski 		return ((val & 0x3fff) << 8);
3898e1dc58eSRafal Jaworowski 	case 2:
3908e1dc58eSRafal Jaworowski 	default:
3918e1dc58eSRafal Jaworowski 		return (((val & 0x8000) << 10) | ((val & 0x7fff) << 7));
3928e1dc58eSRafal Jaworowski 	}
3938e1dc58eSRafal Jaworowski }
3948e1dc58eSRafal Jaworowski 
3958e1dc58eSRafal Jaworowski static void
3968e1dc58eSRafal Jaworowski mge_ver_params(struct mge_softc *sc)
3978e1dc58eSRafal Jaworowski {
3988e1dc58eSRafal Jaworowski 	uint32_t d, r;
3998e1dc58eSRafal Jaworowski 
4008e1dc58eSRafal Jaworowski 	soc_id(&d, &r);
40175f1438bSOleksandr Tymoshenko 	if (d == MV_DEV_88F6281 || d == MV_DEV_88F6781 ||
402c8953e12SHiroki Sato 	    d == MV_DEV_88F6282 ||
403c8953e12SHiroki Sato 	    d == MV_DEV_MV78100 ||
40475f1438bSOleksandr Tymoshenko 	    d == MV_DEV_MV78100_Z0 ||
40575f1438bSOleksandr Tymoshenko 	    (d & MV_DEV_FAMILY_MASK) == MV_DEV_DISCOVERY) {
4068e1dc58eSRafal Jaworowski 		sc->mge_ver = 2;
4078e1dc58eSRafal Jaworowski 		sc->mge_mtu = 0x4e8;
4088e1dc58eSRafal Jaworowski 		sc->mge_tfut_ipg_max = 0xFFFF;
4098e1dc58eSRafal Jaworowski 		sc->mge_rx_ipg_max = 0xFFFF;
4108e1dc58eSRafal Jaworowski 		sc->mge_tx_arb_cfg = 0xFC0000FF;
4118e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cfg = 0xFFFF7FFF;
4128e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cnt = 0x3FFFFFFF;
4138e1dc58eSRafal Jaworowski 	} else {
4148e1dc58eSRafal Jaworowski 		sc->mge_ver = 1;
4158e1dc58eSRafal Jaworowski 		sc->mge_mtu = 0x458;
4168e1dc58eSRafal Jaworowski 		sc->mge_tfut_ipg_max = 0x3FFF;
4178e1dc58eSRafal Jaworowski 		sc->mge_rx_ipg_max = 0x3FFF;
4188e1dc58eSRafal Jaworowski 		sc->mge_tx_arb_cfg = 0x000000FF;
4198e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cfg = 0x3FFFFFFF;
4208e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cnt = 0x3FFFFFFF;
4218e1dc58eSRafal Jaworowski 	}
42275f1438bSOleksandr Tymoshenko 	if (d == MV_DEV_88RC8180)
42375f1438bSOleksandr Tymoshenko 		sc->mge_intr_cnt = 1;
42475f1438bSOleksandr Tymoshenko 	else
42575f1438bSOleksandr Tymoshenko 		sc->mge_intr_cnt = 2;
42675f1438bSOleksandr Tymoshenko 
42775f1438bSOleksandr Tymoshenko 	if (d == MV_DEV_MV78160 || d == MV_DEV_MV78260 || d == MV_DEV_MV78460)
42875f1438bSOleksandr Tymoshenko 		sc->mge_hw_csum = 0;
42975f1438bSOleksandr Tymoshenko 	else
43075f1438bSOleksandr Tymoshenko 		sc->mge_hw_csum = 1;
4318e1dc58eSRafal Jaworowski }
4328e1dc58eSRafal Jaworowski 
4339f55f5f5SRafal Jaworowski static void
4349f55f5f5SRafal Jaworowski mge_set_mac_address(struct mge_softc *sc)
4359f55f5f5SRafal Jaworowski {
4369f55f5f5SRafal Jaworowski 	char *if_mac;
4379f55f5f5SRafal Jaworowski 	uint32_t mac_l, mac_h;
4389f55f5f5SRafal Jaworowski 
4399f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK_ASSERT(sc);
4409f55f5f5SRafal Jaworowski 
44198fe10c8SJustin Hibbits 	if_mac = (char *)if_getlladdr(sc->ifp);
4429f55f5f5SRafal Jaworowski 
4439f55f5f5SRafal Jaworowski 	mac_l = (if_mac[4] << 8) | (if_mac[5]);
4449f55f5f5SRafal Jaworowski 	mac_h = (if_mac[0] << 24)| (if_mac[1] << 16) |
4459f55f5f5SRafal Jaworowski 	    (if_mac[2] << 8) | (if_mac[3] << 0);
4469f55f5f5SRafal Jaworowski 
4479f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_MAC_ADDR_L, mac_l);
4489f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_MAC_ADDR_H, mac_h);
4499f55f5f5SRafal Jaworowski 
4509f55f5f5SRafal Jaworowski 	mge_set_ucast_address(sc, if_mac[5], MGE_RX_DEFAULT_QUEUE);
4519f55f5f5SRafal Jaworowski }
4529f55f5f5SRafal Jaworowski 
4539f55f5f5SRafal Jaworowski static void
4549f55f5f5SRafal Jaworowski mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte, uint8_t queue)
4559f55f5f5SRafal Jaworowski {
4569f55f5f5SRafal Jaworowski 	uint32_t reg_idx, reg_off, reg_val, i;
4579f55f5f5SRafal Jaworowski 
4589f55f5f5SRafal Jaworowski 	last_byte &= 0xf;
4599f55f5f5SRafal Jaworowski 	reg_idx = last_byte / MGE_UCAST_REG_NUMBER;
4609f55f5f5SRafal Jaworowski 	reg_off = (last_byte % MGE_UCAST_REG_NUMBER) * 8;
4619f55f5f5SRafal Jaworowski 	reg_val = (1 | (queue << 1)) << reg_off;
4629f55f5f5SRafal Jaworowski 
4639f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_UCAST_REG_NUMBER; i++) {
4649f55f5f5SRafal Jaworowski 		if ( i == reg_idx)
4659f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val);
4669f55f5f5SRafal Jaworowski 		else
4679f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), 0);
4689f55f5f5SRafal Jaworowski 	}
4699f55f5f5SRafal Jaworowski }
4709f55f5f5SRafal Jaworowski 
4719f55f5f5SRafal Jaworowski static void
4729f55f5f5SRafal Jaworowski mge_set_prom_mode(struct mge_softc *sc, uint8_t queue)
4739f55f5f5SRafal Jaworowski {
4749f55f5f5SRafal Jaworowski 	uint32_t port_config;
4759f55f5f5SRafal Jaworowski 	uint32_t reg_val, i;
4769f55f5f5SRafal Jaworowski 
4779f55f5f5SRafal Jaworowski 	/* Enable or disable promiscuous mode as needed */
47896ab5e71SJustin Hibbits 	if (if_getflags(sc->ifp) & IFF_PROMISC) {
4799f55f5f5SRafal Jaworowski 		port_config = MGE_READ(sc, MGE_PORT_CONFIG);
4809f55f5f5SRafal Jaworowski 		port_config |= PORT_CONFIG_UPM;
4819f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_CONFIG, port_config);
4829f55f5f5SRafal Jaworowski 
4839f55f5f5SRafal Jaworowski 		reg_val = ((1 | (queue << 1)) | (1 | (queue << 1)) << 8 |
4849f55f5f5SRafal Jaworowski 		   (1 | (queue << 1)) << 16 | (1 | (queue << 1)) << 24);
4859f55f5f5SRafal Jaworowski 
4869f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
4879f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), reg_val);
4889f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), reg_val);
4899f55f5f5SRafal Jaworowski 		}
4909f55f5f5SRafal Jaworowski 
4919f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_UCAST_REG_NUMBER; i++)
4929f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val);
4939f55f5f5SRafal Jaworowski 
4949f55f5f5SRafal Jaworowski 	} else {
4959f55f5f5SRafal Jaworowski 		port_config = MGE_READ(sc, MGE_PORT_CONFIG);
4969f55f5f5SRafal Jaworowski 		port_config &= ~PORT_CONFIG_UPM;
4979f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_CONFIG, port_config);
4989f55f5f5SRafal Jaworowski 
4999f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
5009f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), 0);
5019f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), 0);
5029f55f5f5SRafal Jaworowski 		}
5039f55f5f5SRafal Jaworowski 
5049f55f5f5SRafal Jaworowski 		mge_set_mac_address(sc);
5059f55f5f5SRafal Jaworowski 	}
5069f55f5f5SRafal Jaworowski }
5079f55f5f5SRafal Jaworowski 
5089f55f5f5SRafal Jaworowski static void
5099f55f5f5SRafal Jaworowski mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
5109f55f5f5SRafal Jaworowski {
5119f55f5f5SRafal Jaworowski 	u_int32_t *paddr;
5129f55f5f5SRafal Jaworowski 
5139f55f5f5SRafal Jaworowski 	KASSERT(nseg == 1, ("wrong number of segments, should be 1"));
5149f55f5f5SRafal Jaworowski 	paddr = arg;
5159f55f5f5SRafal Jaworowski 
5169f55f5f5SRafal Jaworowski 	*paddr = segs->ds_addr;
5179f55f5f5SRafal Jaworowski }
5189f55f5f5SRafal Jaworowski 
5199f55f5f5SRafal Jaworowski static int
5209f55f5f5SRafal Jaworowski mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf **mbufp,
5219f55f5f5SRafal Jaworowski     bus_addr_t *paddr)
5229f55f5f5SRafal Jaworowski {
5239f55f5f5SRafal Jaworowski 	struct mbuf *new_mbuf;
5249f55f5f5SRafal Jaworowski 	bus_dma_segment_t seg[1];
5259f55f5f5SRafal Jaworowski 	int error;
5269f55f5f5SRafal Jaworowski 	int nsegs;
5279f55f5f5SRafal Jaworowski 
5289f55f5f5SRafal Jaworowski 	KASSERT(mbufp != NULL, ("NULL mbuf pointer!"));
5299f55f5f5SRafal Jaworowski 
530c6499eccSGleb Smirnoff 	new_mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
5319f55f5f5SRafal Jaworowski 	if (new_mbuf == NULL)
5329f55f5f5SRafal Jaworowski 		return (ENOBUFS);
5339f55f5f5SRafal Jaworowski 	new_mbuf->m_len = new_mbuf->m_pkthdr.len = new_mbuf->m_ext.ext_size;
5349f55f5f5SRafal Jaworowski 
5359f55f5f5SRafal Jaworowski 	if (*mbufp) {
5369f55f5f5SRafal Jaworowski 		bus_dmamap_sync(tag, map, BUS_DMASYNC_POSTREAD);
5379f55f5f5SRafal Jaworowski 		bus_dmamap_unload(tag, map);
5389f55f5f5SRafal Jaworowski 	}
5399f55f5f5SRafal Jaworowski 
5409f55f5f5SRafal Jaworowski 	error = bus_dmamap_load_mbuf_sg(tag, map, new_mbuf, seg, &nsegs,
5419f55f5f5SRafal Jaworowski 	    BUS_DMA_NOWAIT);
5429f55f5f5SRafal Jaworowski 	KASSERT(nsegs == 1, ("Too many segments returned!"));
5439f55f5f5SRafal Jaworowski 	if (nsegs != 1 || error)
5449f55f5f5SRafal Jaworowski 		panic("mge_new_rxbuf(): nsegs(%d), error(%d)", nsegs, error);
5459f55f5f5SRafal Jaworowski 
5469f55f5f5SRafal Jaworowski 	bus_dmamap_sync(tag, map, BUS_DMASYNC_PREREAD);
5479f55f5f5SRafal Jaworowski 
5489f55f5f5SRafal Jaworowski 	(*mbufp) = new_mbuf;
5499f55f5f5SRafal Jaworowski 	(*paddr) = seg->ds_addr;
5509f55f5f5SRafal Jaworowski 	return (0);
5519f55f5f5SRafal Jaworowski }
5529f55f5f5SRafal Jaworowski 
5539f55f5f5SRafal Jaworowski static int
5549f55f5f5SRafal Jaworowski mge_alloc_desc_dma(struct mge_softc *sc, struct mge_desc_wrapper* tab,
5559f55f5f5SRafal Jaworowski     uint32_t size, bus_dma_tag_t *buffer_tag)
5569f55f5f5SRafal Jaworowski {
5579f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
5589f55f5f5SRafal Jaworowski 	bus_addr_t desc_paddr;
5599f55f5f5SRafal Jaworowski 	int i, error;
5609f55f5f5SRafal Jaworowski 
5619f55f5f5SRafal Jaworowski 	desc_paddr = 0;
5629f55f5f5SRafal Jaworowski 	for (i = size - 1; i >= 0; i--) {
5639f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
5649f55f5f5SRafal Jaworowski 		error = bus_dmamem_alloc(sc->mge_desc_dtag,
5659f55f5f5SRafal Jaworowski 		    (void**)&(dw->mge_desc),
5669f55f5f5SRafal Jaworowski 		    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
5679f55f5f5SRafal Jaworowski 		    &(dw->desc_dmap));
5689f55f5f5SRafal Jaworowski 
5699f55f5f5SRafal Jaworowski 		if (error) {
5709f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "failed to allocate DMA memory\n");
5719f55f5f5SRafal Jaworowski 			dw->mge_desc = NULL;
5729f55f5f5SRafal Jaworowski 			return (ENXIO);
5739f55f5f5SRafal Jaworowski 		}
5749f55f5f5SRafal Jaworowski 
5759f55f5f5SRafal Jaworowski 		error = bus_dmamap_load(sc->mge_desc_dtag, dw->desc_dmap,
5769f55f5f5SRafal Jaworowski 		    dw->mge_desc, sizeof(struct mge_desc), mge_get_dma_addr,
5779f55f5f5SRafal Jaworowski 		    &(dw->mge_desc_paddr), BUS_DMA_NOWAIT);
5789f55f5f5SRafal Jaworowski 
5799f55f5f5SRafal Jaworowski 		if (error) {
5809f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "can't load descriptor\n");
5819f55f5f5SRafal Jaworowski 			bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc,
5829f55f5f5SRafal Jaworowski 			    dw->desc_dmap);
5839f55f5f5SRafal Jaworowski 			dw->mge_desc = NULL;
5849f55f5f5SRafal Jaworowski 			return (ENXIO);
5859f55f5f5SRafal Jaworowski 		}
5869f55f5f5SRafal Jaworowski 
5879f55f5f5SRafal Jaworowski 		/* Chain descriptors */
5889f55f5f5SRafal Jaworowski 		dw->mge_desc->next_desc = desc_paddr;
5899f55f5f5SRafal Jaworowski 		desc_paddr = dw->mge_desc_paddr;
5909f55f5f5SRafal Jaworowski 	}
5919f55f5f5SRafal Jaworowski 	tab[size - 1].mge_desc->next_desc = desc_paddr;
5929f55f5f5SRafal Jaworowski 
5939f55f5f5SRafal Jaworowski 	/* Allocate a busdma tag for mbufs. */
59462ce43ccSScott Long 	error = bus_dma_tag_create(bus_get_dma_tag(sc->dev),	/* parent */
59575f1438bSOleksandr Tymoshenko 	    1, 0,				/* alignment, boundary */
5969f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
5979f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR,			/* highaddr */
5989f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* filtfunc, filtfuncarg */
5999f55f5f5SRafal Jaworowski 	    MCLBYTES, 1,			/* maxsize, nsegments */
6009f55f5f5SRafal Jaworowski 	    MCLBYTES, 0,			/* maxsegsz, flags */
6019f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* lockfunc, lockfuncarg */
6029f55f5f5SRafal Jaworowski 	    buffer_tag);			/* dmat */
6039f55f5f5SRafal Jaworowski 	if (error) {
6049f55f5f5SRafal Jaworowski 		if_printf(sc->ifp, "failed to create busdma tag for mbufs\n");
6059f55f5f5SRafal Jaworowski 		return (ENXIO);
6069f55f5f5SRafal Jaworowski 	}
6079f55f5f5SRafal Jaworowski 
6089f55f5f5SRafal Jaworowski 	/* Create TX busdma maps */
6099f55f5f5SRafal Jaworowski 	for (i = 0; i < size; i++) {
6109f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
6119f55f5f5SRafal Jaworowski 		error = bus_dmamap_create(*buffer_tag, 0, &dw->buffer_dmap);
6129f55f5f5SRafal Jaworowski 		if (error) {
6139f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "failed to create map for mbuf\n");
6149f55f5f5SRafal Jaworowski 			return (ENXIO);
6159f55f5f5SRafal Jaworowski 		}
6169f55f5f5SRafal Jaworowski 
6179f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
6189f55f5f5SRafal Jaworowski 		dw->mge_desc->buffer = (bus_addr_t)NULL;
6199f55f5f5SRafal Jaworowski 	}
6209f55f5f5SRafal Jaworowski 
6219f55f5f5SRafal Jaworowski 	return (0);
6229f55f5f5SRafal Jaworowski }
6239f55f5f5SRafal Jaworowski 
6249f55f5f5SRafal Jaworowski static int
6259f55f5f5SRafal Jaworowski mge_allocate_dma(struct mge_softc *sc)
6269f55f5f5SRafal Jaworowski {
6279f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
628d6bdd318SRafal Jaworowski 	int i;
6299f55f5f5SRafal Jaworowski 
6309f55f5f5SRafal Jaworowski 	/* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
631f8967810SWarner Losh 	bus_dma_tag_create(bus_get_dma_tag(sc->dev),	/* parent */
6329f55f5f5SRafal Jaworowski 	    16, 0,				/* alignment, boundary */
6339f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
6349f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR,			/* highaddr */
6359f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* filtfunc, filtfuncarg */
6369f55f5f5SRafal Jaworowski 	    sizeof(struct mge_desc), 1,		/* maxsize, nsegments */
6379f55f5f5SRafal Jaworowski 	    sizeof(struct mge_desc), 0,		/* maxsegsz, flags */
6389f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* lockfunc, lockfuncarg */
6399f55f5f5SRafal Jaworowski 	    &sc->mge_desc_dtag);		/* dmat */
6409f55f5f5SRafal Jaworowski 
6419f55f5f5SRafal Jaworowski 
6429f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM,
6439f55f5f5SRafal Jaworowski 	    &sc->mge_tx_dtag);
6449f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM,
6459f55f5f5SRafal Jaworowski 	    &sc->mge_rx_dtag);
6469f55f5f5SRafal Jaworowski 
6479f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
6489f55f5f5SRafal Jaworowski 		dw = &(sc->mge_rx_desc[i]);
6499f55f5f5SRafal Jaworowski 		mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer,
6509f55f5f5SRafal Jaworowski 		    &dw->mge_desc->buffer);
6519f55f5f5SRafal Jaworowski 	}
6529f55f5f5SRafal Jaworowski 
6539f55f5f5SRafal Jaworowski 	sc->tx_desc_start = sc->mge_tx_desc[0].mge_desc_paddr;
6549f55f5f5SRafal Jaworowski 	sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr;
6559f55f5f5SRafal Jaworowski 
6569f55f5f5SRafal Jaworowski 	return (0);
6579f55f5f5SRafal Jaworowski }
6589f55f5f5SRafal Jaworowski 
6599f55f5f5SRafal Jaworowski static void
6609f55f5f5SRafal Jaworowski mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab,
6619f55f5f5SRafal Jaworowski     uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs)
6629f55f5f5SRafal Jaworowski {
6639f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
6649f55f5f5SRafal Jaworowski 	int i;
6659f55f5f5SRafal Jaworowski 
6669f55f5f5SRafal Jaworowski 	for (i = 0; i < size; i++) {
6679f55f5f5SRafal Jaworowski 		/* Free RX mbuf */
6689f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
6699f55f5f5SRafal Jaworowski 
6709f55f5f5SRafal Jaworowski 		if (dw->buffer_dmap) {
6719f55f5f5SRafal Jaworowski 			if (free_mbufs) {
6729f55f5f5SRafal Jaworowski 				bus_dmamap_sync(buffer_tag, dw->buffer_dmap,
6739f55f5f5SRafal Jaworowski 				    BUS_DMASYNC_POSTREAD);
6749f55f5f5SRafal Jaworowski 				bus_dmamap_unload(buffer_tag, dw->buffer_dmap);
6759f55f5f5SRafal Jaworowski 			}
6769f55f5f5SRafal Jaworowski 			bus_dmamap_destroy(buffer_tag, dw->buffer_dmap);
6779f55f5f5SRafal Jaworowski 			if (free_mbufs)
6789f55f5f5SRafal Jaworowski 				m_freem(dw->buffer);
6799f55f5f5SRafal Jaworowski 		}
6809f55f5f5SRafal Jaworowski 		/* Free RX descriptors */
6819f55f5f5SRafal Jaworowski 		if (dw->desc_dmap) {
6829f55f5f5SRafal Jaworowski 			bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
6839f55f5f5SRafal Jaworowski 			    BUS_DMASYNC_POSTREAD);
6849f55f5f5SRafal Jaworowski 			bus_dmamap_unload(sc->mge_desc_dtag, dw->desc_dmap);
6859f55f5f5SRafal Jaworowski 			bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc,
6869f55f5f5SRafal Jaworowski 			    dw->desc_dmap);
6879f55f5f5SRafal Jaworowski 		}
6889f55f5f5SRafal Jaworowski 	}
6899f55f5f5SRafal Jaworowski }
6909f55f5f5SRafal Jaworowski 
6919f55f5f5SRafal Jaworowski static void
6929f55f5f5SRafal Jaworowski mge_free_dma(struct mge_softc *sc)
6939f55f5f5SRafal Jaworowski {
6944ac30cc1SZbigniew Bodek 
695b1603638SGordon Bergling 	/* Free descriptors and mbufs */
6969f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1);
6979f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM, sc->mge_tx_dtag, 0);
6989f55f5f5SRafal Jaworowski 
6999f55f5f5SRafal Jaworowski 	/* Destroy mbuf dma tag */
7009f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_tx_dtag);
7019f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_rx_dtag);
7029f55f5f5SRafal Jaworowski 	/* Destroy descriptors tag */
7039f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_desc_dtag);
7049f55f5f5SRafal Jaworowski }
7059f55f5f5SRafal Jaworowski 
7069f55f5f5SRafal Jaworowski static void
7079f55f5f5SRafal Jaworowski mge_reinit_rx(struct mge_softc *sc)
7089f55f5f5SRafal Jaworowski {
7099f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
7109f55f5f5SRafal Jaworowski 	int i;
7119f55f5f5SRafal Jaworowski 
712d6bdd318SRafal Jaworowski 	MGE_RECEIVE_LOCK_ASSERT(sc);
7139f55f5f5SRafal Jaworowski 
7149f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1);
7159f55f5f5SRafal Jaworowski 
7169f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM,
7179f55f5f5SRafal Jaworowski 	    &sc->mge_rx_dtag);
7189f55f5f5SRafal Jaworowski 
7199f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
7209f55f5f5SRafal Jaworowski 		dw = &(sc->mge_rx_desc[i]);
7219f55f5f5SRafal Jaworowski 		mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer,
7229f55f5f5SRafal Jaworowski 		&dw->mge_desc->buffer);
7239f55f5f5SRafal Jaworowski 	}
7249f55f5f5SRafal Jaworowski 
7259f55f5f5SRafal Jaworowski 	sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr;
7269f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
7279f55f5f5SRafal Jaworowski 
7289f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE),
7299f55f5f5SRafal Jaworowski 	    sc->rx_desc_start);
7309f55f5f5SRafal Jaworowski 
7319f55f5f5SRafal Jaworowski 	/* Enable RX queue */
7329f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE));
7339f55f5f5SRafal Jaworowski }
7349f55f5f5SRafal Jaworowski 
7359f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
7369f55f5f5SRafal Jaworowski static poll_handler_t mge_poll;
7379f55f5f5SRafal Jaworowski 
7381abcdbd1SAttilio Rao static int
73998fe10c8SJustin Hibbits mge_poll(if_t ifp, enum poll_cmd cmd, int count)
7409f55f5f5SRafal Jaworowski {
74198fe10c8SJustin Hibbits 	struct mge_softc *sc = if_getsoftc(ifp);
7429f55f5f5SRafal Jaworowski 	uint32_t int_cause, int_cause_ext;
7431abcdbd1SAttilio Rao 	int rx_npkts = 0;
7449f55f5f5SRafal Jaworowski 
7453c71b84fSZbigniew Bodek 	MGE_RECEIVE_LOCK(sc);
7469f55f5f5SRafal Jaworowski 
74798fe10c8SJustin Hibbits 	if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
7483c71b84fSZbigniew Bodek 		MGE_RECEIVE_UNLOCK(sc);
7491abcdbd1SAttilio Rao 		return (rx_npkts);
7509f55f5f5SRafal Jaworowski 	}
7519f55f5f5SRafal Jaworowski 
7529f55f5f5SRafal Jaworowski 	if (cmd == POLL_AND_CHECK_STATUS) {
7539f55f5f5SRafal Jaworowski 		int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
7549f55f5f5SRafal Jaworowski 		int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
7559f55f5f5SRafal Jaworowski 
7569f55f5f5SRafal Jaworowski 		/* Check for resource error */
7579f55f5f5SRafal Jaworowski 		if (int_cause & MGE_PORT_INT_RXERRQ0)
7589f55f5f5SRafal Jaworowski 			mge_reinit_rx(sc);
7599f55f5f5SRafal Jaworowski 
7609f55f5f5SRafal Jaworowski 		if (int_cause || int_cause_ext) {
7619f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause);
7629f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext);
7639f55f5f5SRafal Jaworowski 		}
7649f55f5f5SRafal Jaworowski 	}
7659f55f5f5SRafal Jaworowski 
7663c71b84fSZbigniew Bodek 
7671abcdbd1SAttilio Rao 	rx_npkts = mge_intr_rx_locked(sc, count);
7689f55f5f5SRafal Jaworowski 
7693c71b84fSZbigniew Bodek 	MGE_RECEIVE_UNLOCK(sc);
7703c71b84fSZbigniew Bodek 	MGE_TRANSMIT_LOCK(sc);
7713c71b84fSZbigniew Bodek 	mge_intr_tx_locked(sc);
7723c71b84fSZbigniew Bodek 	MGE_TRANSMIT_UNLOCK(sc);
7731abcdbd1SAttilio Rao 	return (rx_npkts);
7749f55f5f5SRafal Jaworowski }
7759f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */
7769f55f5f5SRafal Jaworowski 
7779f55f5f5SRafal Jaworowski static int
7789f55f5f5SRafal Jaworowski mge_attach(device_t dev)
7799f55f5f5SRafal Jaworowski {
7809f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
781a6eb469dSPhilip Paeps 	struct mii_softc *miisc;
78298fe10c8SJustin Hibbits 	if_t ifp;
7839f55f5f5SRafal Jaworowski 	uint8_t hwaddr[ETHER_ADDR_LEN];
7848e5d93dbSMarius Strobl 	int i, error, phy;
7859f55f5f5SRafal Jaworowski 
7869f55f5f5SRafal Jaworowski 	sc = device_get_softc(dev);
7879f55f5f5SRafal Jaworowski 	sc->dev = dev;
788db5ef4fcSRafal Jaworowski 	sc->node = ofw_bus_get_node(dev);
7893c71b84fSZbigniew Bodek 	phy = 0;
7903c71b84fSZbigniew Bodek 
7913c71b84fSZbigniew Bodek 	if (fdt_get_phyaddr(sc->node, sc->dev, &phy, (void **)&sc->phy_sc) == 0) {
7923c71b84fSZbigniew Bodek 		device_printf(dev, "PHY%i attached, phy_sc points to %s\n", phy,
7933c71b84fSZbigniew Bodek 		    device_get_nameunit(sc->phy_sc->dev));
7943c71b84fSZbigniew Bodek 		sc->phy_attached = 1;
7953c71b84fSZbigniew Bodek 	} else {
7963c71b84fSZbigniew Bodek 		device_printf(dev, "PHY not attached.\n");
7973c71b84fSZbigniew Bodek 		sc->phy_attached = 0;
7983c71b84fSZbigniew Bodek 		sc->phy_sc = sc;
7993c71b84fSZbigniew Bodek 	}
8003c71b84fSZbigniew Bodek 
8013c71b84fSZbigniew Bodek 	if (fdt_find_compatible(sc->node, "mrvl,sw", 1) != 0) {
8023c71b84fSZbigniew Bodek 		device_printf(dev, "Switch attached.\n");
8033c71b84fSZbigniew Bodek 		sc->switch_attached = 1;
8043c71b84fSZbigniew Bodek 		/* additional variable available across instances */
8053c71b84fSZbigniew Bodek 		switch_attached = 1;
8063c71b84fSZbigniew Bodek 	} else {
8073c71b84fSZbigniew Bodek 		sc->switch_attached = 0;
8083c71b84fSZbigniew Bodek 	}
8093c71b84fSZbigniew Bodek 
8103c71b84fSZbigniew Bodek 	if (device_get_unit(dev) == 0) {
8113c71b84fSZbigniew Bodek 		sx_init(&sx_smi, "mge_tick() SMI access threads interlock");
8123c71b84fSZbigniew Bodek 	}
8139f55f5f5SRafal Jaworowski 
8148e1dc58eSRafal Jaworowski 	/* Set chip version-dependent parameters */
8158e1dc58eSRafal Jaworowski 	mge_ver_params(sc);
8168e1dc58eSRafal Jaworowski 
8179f55f5f5SRafal Jaworowski 	/* Initialize mutexes */
8184ac30cc1SZbigniew Bodek 	mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "mge TX lock",
8194ac30cc1SZbigniew Bodek 	    MTX_DEF);
8204ac30cc1SZbigniew Bodek 	mtx_init(&sc->receive_lock, device_get_nameunit(dev), "mge RX lock",
8214ac30cc1SZbigniew Bodek 	    MTX_DEF);
8229f55f5f5SRafal Jaworowski 
8239f55f5f5SRafal Jaworowski 	/* Allocate IO and IRQ resources */
8249f55f5f5SRafal Jaworowski 	error = bus_alloc_resources(dev, res_spec, sc->res);
8259f55f5f5SRafal Jaworowski 	if (error) {
8269f55f5f5SRafal Jaworowski 		device_printf(dev, "could not allocate resources\n");
8279f55f5f5SRafal Jaworowski 		mge_detach(dev);
8289f55f5f5SRafal Jaworowski 		return (ENXIO);
8299f55f5f5SRafal Jaworowski 	}
8309f55f5f5SRafal Jaworowski 
8319f55f5f5SRafal Jaworowski 	/* Allocate DMA, buffers, buffer descriptors */
8329f55f5f5SRafal Jaworowski 	error = mge_allocate_dma(sc);
8339f55f5f5SRafal Jaworowski 	if (error) {
8349f55f5f5SRafal Jaworowski 		mge_detach(dev);
8359f55f5f5SRafal Jaworowski 		return (ENXIO);
8369f55f5f5SRafal Jaworowski 	}
8379f55f5f5SRafal Jaworowski 
8389f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = 0;
8399f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
8409f55f5f5SRafal Jaworowski 	sc->tx_desc_used_idx = 0;
8415817716fSRafal Jaworowski 	sc->tx_desc_used_count = 0;
8429f55f5f5SRafal Jaworowski 
8439f55f5f5SRafal Jaworowski 	/* Configure defaults for interrupts coalescing */
8449f55f5f5SRafal Jaworowski 	sc->rx_ic_time = 768;
8459f55f5f5SRafal Jaworowski 	sc->tx_ic_time = 768;
8469f55f5f5SRafal Jaworowski 	mge_add_sysctls(sc);
8479f55f5f5SRafal Jaworowski 
8489f55f5f5SRafal Jaworowski 	/* Allocate network interface */
8499f55f5f5SRafal Jaworowski 	ifp = sc->ifp = if_alloc(IFT_ETHER);
8509f55f5f5SRafal Jaworowski 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
85198fe10c8SJustin Hibbits 	if_setsoftc(ifp, sc);
85298fe10c8SJustin Hibbits 	if_setflags(ifp, IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST);
85398fe10c8SJustin Hibbits 	if_setcapabilities(ifp, IFCAP_VLAN_MTU);
85475f1438bSOleksandr Tymoshenko 	if (sc->mge_hw_csum) {
85598fe10c8SJustin Hibbits 		if_setcapabilitiesbit(ifp, IFCAP_HWCSUM, 0);
85698fe10c8SJustin Hibbits 		if_sethwassist(ifp, MGE_CHECKSUM_FEATURES);
85775f1438bSOleksandr Tymoshenko 	}
85898fe10c8SJustin Hibbits 	if_setcapenable(ifp, if_getcapabilities(ifp));
8599f55f5f5SRafal Jaworowski 
8609f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
8619f55f5f5SRafal Jaworowski 	/* Advertise that polling is supported */
86298fe10c8SJustin Hibbits 	if_setcapabilitiesbit(ifp, IFCAP_POLLING, 0);
8639f55f5f5SRafal Jaworowski #endif
8649f55f5f5SRafal Jaworowski 
86598fe10c8SJustin Hibbits 	if_setinitfn(ifp, mge_init);
86698fe10c8SJustin Hibbits 	if_setstartfn(ifp, mge_start);
86798fe10c8SJustin Hibbits 	if_setioctlfn(ifp, mge_ioctl);
8689f55f5f5SRafal Jaworowski 
86998fe10c8SJustin Hibbits 	if_setsendqlen(ifp, MGE_TX_DESC_NUM - 1);
87098fe10c8SJustin Hibbits 	if_setsendqready(ifp);
8719f55f5f5SRafal Jaworowski 
8729f55f5f5SRafal Jaworowski 	mge_get_mac_address(sc, hwaddr);
8739f55f5f5SRafal Jaworowski 	ether_ifattach(ifp, hwaddr);
8746b2ff27cSAlexander Motin 	callout_init(&sc->wd_callout, 1);
8759f55f5f5SRafal Jaworowski 
8768e5d93dbSMarius Strobl 	/* Attach PHY(s) */
8773c71b84fSZbigniew Bodek 	if (sc->phy_attached) {
8788e5d93dbSMarius Strobl 		error = mii_attach(dev, &sc->miibus, ifp, mge_ifmedia_upd,
8798e5d93dbSMarius Strobl 		    mge_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
8809f55f5f5SRafal Jaworowski 		if (error) {
8813c71b84fSZbigniew Bodek 			device_printf(dev, "MII failed to find PHY\n");
8823c71b84fSZbigniew Bodek 			if_free(ifp);
8833c71b84fSZbigniew Bodek 			sc->ifp = NULL;
8849f55f5f5SRafal Jaworowski 			mge_detach(dev);
8859f55f5f5SRafal Jaworowski 			return (error);
8869f55f5f5SRafal Jaworowski 		}
8879f55f5f5SRafal Jaworowski 		sc->mii = device_get_softc(sc->miibus);
8889f55f5f5SRafal Jaworowski 
889a6eb469dSPhilip Paeps 		/* Tell the MAC where to find the PHY so autoneg works */
890a6eb469dSPhilip Paeps 		miisc = LIST_FIRST(&sc->mii->mii_phys);
891a6eb469dSPhilip Paeps 		MGE_WRITE(sc, MGE_REG_PHYDEV, miisc->mii_phy);
8923c71b84fSZbigniew Bodek 	} else {
8933c71b84fSZbigniew Bodek 		/* no PHY, so use hard-coded values */
8943c71b84fSZbigniew Bodek 		ifmedia_init(&sc->mge_ifmedia, 0,
8953c71b84fSZbigniew Bodek 		    mge_ifmedia_upd,
8963c71b84fSZbigniew Bodek 		    mge_ifmedia_sts);
8973c71b84fSZbigniew Bodek 		ifmedia_add(&sc->mge_ifmedia,
8983c71b84fSZbigniew Bodek 		    IFM_ETHER | IFM_1000_T | IFM_FDX,
8993c71b84fSZbigniew Bodek 		    0, NULL);
9003c71b84fSZbigniew Bodek 		ifmedia_set(&sc->mge_ifmedia,
9013c71b84fSZbigniew Bodek 		    IFM_ETHER | IFM_1000_T | IFM_FDX);
9023c71b84fSZbigniew Bodek 	}
903a6eb469dSPhilip Paeps 
9049f55f5f5SRafal Jaworowski 	/* Attach interrupt handlers */
90575f1438bSOleksandr Tymoshenko 	/* TODO: review flags, in part. mark RX as INTR_ENTROPY ? */
90675f1438bSOleksandr Tymoshenko 	for (i = 1; i <= sc->mge_intr_cnt; ++i) {
90775f1438bSOleksandr Tymoshenko 		error = bus_setup_intr(dev, sc->res[i],
90875f1438bSOleksandr Tymoshenko 		    INTR_TYPE_NET | INTR_MPSAFE,
90975f1438bSOleksandr Tymoshenko 		    NULL, *mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].handler,
91075f1438bSOleksandr Tymoshenko 		    sc, &sc->ih_cookie[i - 1]);
9119f55f5f5SRafal Jaworowski 		if (error) {
9129f55f5f5SRafal Jaworowski 			device_printf(dev, "could not setup %s\n",
91375f1438bSOleksandr Tymoshenko 			    mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].description);
914a6eb469dSPhilip Paeps 			mge_detach(dev);
9159f55f5f5SRafal Jaworowski 			return (error);
9169f55f5f5SRafal Jaworowski 		}
9179f55f5f5SRafal Jaworowski 	}
9189f55f5f5SRafal Jaworowski 
9193c71b84fSZbigniew Bodek 	if (sc->switch_attached) {
9203c71b84fSZbigniew Bodek 		MGE_WRITE(sc, MGE_REG_PHYDEV, MGE_SWITCH_PHYDEV);
9215b56413dSWarner Losh 		device_add_child(dev, "mdio", DEVICE_UNIT_ANY);
922*18250ec6SJohn Baldwin 		bus_attach_children(dev);
9233c71b84fSZbigniew Bodek 	}
9243c71b84fSZbigniew Bodek 
9259f55f5f5SRafal Jaworowski 	return (0);
9269f55f5f5SRafal Jaworowski }
9279f55f5f5SRafal Jaworowski 
9289f55f5f5SRafal Jaworowski static int
9299f55f5f5SRafal Jaworowski mge_detach(device_t dev)
9309f55f5f5SRafal Jaworowski {
9319f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
9329f55f5f5SRafal Jaworowski 	int error,i;
9339f55f5f5SRafal Jaworowski 
9349f55f5f5SRafal Jaworowski 	sc = device_get_softc(dev);
9359f55f5f5SRafal Jaworowski 
9369f55f5f5SRafal Jaworowski 	/* Stop controller and free TX queue */
9379f55f5f5SRafal Jaworowski 	if (sc->ifp)
9389f55f5f5SRafal Jaworowski 		mge_shutdown(dev);
9399f55f5f5SRafal Jaworowski 
9409f55f5f5SRafal Jaworowski 	/* Wait for stopping ticks */
9419f55f5f5SRafal Jaworowski         callout_drain(&sc->wd_callout);
9429f55f5f5SRafal Jaworowski 
9439f55f5f5SRafal Jaworowski 	/* Stop and release all interrupts */
94475f1438bSOleksandr Tymoshenko 	for (i = 0; i < sc->mge_intr_cnt; ++i) {
945a6eb469dSPhilip Paeps 		if (!sc->ih_cookie[i])
946a6eb469dSPhilip Paeps 			continue;
947a6eb469dSPhilip Paeps 
9484ac30cc1SZbigniew Bodek 		error = bus_teardown_intr(dev, sc->res[1 + i],
9494ac30cc1SZbigniew Bodek 		    sc->ih_cookie[i]);
9509f55f5f5SRafal Jaworowski 		if (error)
9519f55f5f5SRafal Jaworowski 			device_printf(dev, "could not release %s\n",
95275f1438bSOleksandr Tymoshenko 			    mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i + 1)].description);
9539f55f5f5SRafal Jaworowski 	}
9549f55f5f5SRafal Jaworowski 
9559f55f5f5SRafal Jaworowski 	/* Detach network interface */
9569f55f5f5SRafal Jaworowski 	if (sc->ifp) {
9579f55f5f5SRafal Jaworowski 		ether_ifdetach(sc->ifp);
9589f55f5f5SRafal Jaworowski 		if_free(sc->ifp);
9599f55f5f5SRafal Jaworowski 	}
9609f55f5f5SRafal Jaworowski 
9619f55f5f5SRafal Jaworowski 	/* Free DMA resources */
9629f55f5f5SRafal Jaworowski 	mge_free_dma(sc);
9639f55f5f5SRafal Jaworowski 
9649f55f5f5SRafal Jaworowski 	/* Free IO memory handler */
9659f55f5f5SRafal Jaworowski 	bus_release_resources(dev, res_spec, sc->res);
9669f55f5f5SRafal Jaworowski 
9679f55f5f5SRafal Jaworowski 	/* Destroy mutexes */
9689f55f5f5SRafal Jaworowski 	mtx_destroy(&sc->receive_lock);
9699f55f5f5SRafal Jaworowski 	mtx_destroy(&sc->transmit_lock);
9709f55f5f5SRafal Jaworowski 
9713c71b84fSZbigniew Bodek 	if (device_get_unit(dev) == 0)
9723c71b84fSZbigniew Bodek 		sx_destroy(&sx_smi);
9733c71b84fSZbigniew Bodek 
9749f55f5f5SRafal Jaworowski 	return (0);
9759f55f5f5SRafal Jaworowski }
9769f55f5f5SRafal Jaworowski 
9779f55f5f5SRafal Jaworowski static void
97898fe10c8SJustin Hibbits mge_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
9799f55f5f5SRafal Jaworowski {
9804ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
9819f55f5f5SRafal Jaworowski 	struct mii_data *mii;
9829f55f5f5SRafal Jaworowski 
98398fe10c8SJustin Hibbits 	sc = if_getsoftc(ifp);
9843c71b84fSZbigniew Bodek 	MGE_GLOBAL_LOCK(sc);
9853c71b84fSZbigniew Bodek 
9863c71b84fSZbigniew Bodek 	if (!sc->phy_attached) {
9873c71b84fSZbigniew Bodek 		ifmr->ifm_active = IFM_1000_T | IFM_FDX | IFM_ETHER;
9883c71b84fSZbigniew Bodek 		ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
9893c71b84fSZbigniew Bodek 		goto out_unlock;
9903c71b84fSZbigniew Bodek 	}
9919f55f5f5SRafal Jaworowski 
9929f55f5f5SRafal Jaworowski 	mii = sc->mii;
9939f55f5f5SRafal Jaworowski 	mii_pollstat(mii);
9949f55f5f5SRafal Jaworowski 
9959f55f5f5SRafal Jaworowski 	ifmr->ifm_active = mii->mii_media_active;
9969f55f5f5SRafal Jaworowski 	ifmr->ifm_status = mii->mii_media_status;
9979f55f5f5SRafal Jaworowski 
9983c71b84fSZbigniew Bodek out_unlock:
9993c71b84fSZbigniew Bodek 	MGE_GLOBAL_UNLOCK(sc);
10009f55f5f5SRafal Jaworowski }
10019f55f5f5SRafal Jaworowski 
10029f55f5f5SRafal Jaworowski static uint32_t
10039f55f5f5SRafal Jaworowski mge_set_port_serial_control(uint32_t media)
10049f55f5f5SRafal Jaworowski {
10059f55f5f5SRafal Jaworowski 	uint32_t port_config;
10069f55f5f5SRafal Jaworowski 
10079f55f5f5SRafal Jaworowski 	port_config = PORT_SERIAL_RES_BIT9 | PORT_SERIAL_FORCE_LINK_FAIL |
10089f55f5f5SRafal Jaworowski 	    PORT_SERIAL_MRU(PORT_SERIAL_MRU_1552);
10099f55f5f5SRafal Jaworowski 
10109f55f5f5SRafal Jaworowski 	if (IFM_TYPE(media) == IFM_ETHER) {
10119f55f5f5SRafal Jaworowski 		switch(IFM_SUBTYPE(media)) {
10129f55f5f5SRafal Jaworowski 			case IFM_AUTO:
10139f55f5f5SRafal Jaworowski 				break;
10149f55f5f5SRafal Jaworowski 			case IFM_1000_T:
10159f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_GMII_SPEED_1000 |
10163c71b84fSZbigniew Bodek 				    PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC
10173c71b84fSZbigniew Bodek 				    | PORT_SERIAL_SPEED_AUTONEG);
10189f55f5f5SRafal Jaworowski 				break;
10199f55f5f5SRafal Jaworowski 			case IFM_100_TX:
10209f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_MII_SPEED_100 |
10213c71b84fSZbigniew Bodek 				    PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC
10223c71b84fSZbigniew Bodek 				    | PORT_SERIAL_SPEED_AUTONEG);
10239f55f5f5SRafal Jaworowski 				break;
10249f55f5f5SRafal Jaworowski 			case IFM_10_T:
10259f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_AUTONEG |
10269f55f5f5SRafal Jaworowski 				    PORT_SERIAL_AUTONEG_FC |
10279f55f5f5SRafal Jaworowski 				    PORT_SERIAL_SPEED_AUTONEG);
10289f55f5f5SRafal Jaworowski 				break;
10299f55f5f5SRafal Jaworowski 		}
10309f55f5f5SRafal Jaworowski 		if (media & IFM_FDX)
10319f55f5f5SRafal Jaworowski 			port_config |= PORT_SERIAL_FULL_DUPLEX;
10329f55f5f5SRafal Jaworowski 	}
10339f55f5f5SRafal Jaworowski 	return (port_config);
10349f55f5f5SRafal Jaworowski }
10359f55f5f5SRafal Jaworowski 
10369f55f5f5SRafal Jaworowski static int
103798fe10c8SJustin Hibbits mge_ifmedia_upd(if_t ifp)
10389f55f5f5SRafal Jaworowski {
103998fe10c8SJustin Hibbits 	struct mge_softc *sc = if_getsoftc(ifp);
10409f55f5f5SRafal Jaworowski 
10413c71b84fSZbigniew Bodek 	/*
10423c71b84fSZbigniew Bodek 	 * Do not do anything for switch here, as updating media between
10433c71b84fSZbigniew Bodek 	 * MGE MAC and switch MAC is hardcoded in PCB. Changing it here would
10443c71b84fSZbigniew Bodek 	 * break the link.
10453c71b84fSZbigniew Bodek 	 */
10463c71b84fSZbigniew Bodek 	if (sc->phy_attached) {
10479f55f5f5SRafal Jaworowski 		MGE_GLOBAL_LOCK(sc);
104898fe10c8SJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
10499f55f5f5SRafal Jaworowski 			sc->mge_media_status = sc->mii->mii_media.ifm_media;
10509f55f5f5SRafal Jaworowski 			mii_mediachg(sc->mii);
10513c71b84fSZbigniew Bodek 
10523c71b84fSZbigniew Bodek 			/* MGE MAC needs to be reinitialized. */
10539f55f5f5SRafal Jaworowski 			mge_init_locked(sc);
10549f55f5f5SRafal Jaworowski 
10553c71b84fSZbigniew Bodek 		}
10569f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
10579f55f5f5SRafal Jaworowski 	}
10589f55f5f5SRafal Jaworowski 
10599f55f5f5SRafal Jaworowski 	return (0);
10609f55f5f5SRafal Jaworowski }
10619f55f5f5SRafal Jaworowski 
10629f55f5f5SRafal Jaworowski static void
10639f55f5f5SRafal Jaworowski mge_init(void *arg)
10649f55f5f5SRafal Jaworowski {
10654ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
10669f55f5f5SRafal Jaworowski 
10674ac30cc1SZbigniew Bodek 	sc = arg;
10689f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
10699f55f5f5SRafal Jaworowski 
10709f55f5f5SRafal Jaworowski 	mge_init_locked(arg);
10719f55f5f5SRafal Jaworowski 
10729f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
10739f55f5f5SRafal Jaworowski }
10749f55f5f5SRafal Jaworowski 
10759f55f5f5SRafal Jaworowski static void
10769f55f5f5SRafal Jaworowski mge_init_locked(void *arg)
10779f55f5f5SRafal Jaworowski {
10789f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
10799f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
10809f55f5f5SRafal Jaworowski 	volatile uint32_t reg_val;
10819f55f5f5SRafal Jaworowski 	int i, count;
10823c71b84fSZbigniew Bodek 	uint32_t media_status;
10839f55f5f5SRafal Jaworowski 
10849f55f5f5SRafal Jaworowski 
10859f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK_ASSERT(sc);
10869f55f5f5SRafal Jaworowski 
10879f55f5f5SRafal Jaworowski 	/* Stop interface */
10889f55f5f5SRafal Jaworowski 	mge_stop(sc);
10899f55f5f5SRafal Jaworowski 
10909f55f5f5SRafal Jaworowski 	/* Disable interrupts */
10919f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 0);
10929f55f5f5SRafal Jaworowski 
10939f55f5f5SRafal Jaworowski 	/* Set MAC address */
10949f55f5f5SRafal Jaworowski 	mge_set_mac_address(sc);
10959f55f5f5SRafal Jaworowski 
10969f55f5f5SRafal Jaworowski 	/* Setup multicast filters */
10979f55f5f5SRafal Jaworowski 	mge_setup_multicast(sc);
10989f55f5f5SRafal Jaworowski 
10998e1dc58eSRafal Jaworowski 	if (sc->mge_ver == 2) {
11009f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL1, MGE_RGMII_EN);
11019f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_FIXED_PRIO_CONF, MGE_FIXED_PRIO_EN(0));
11028e1dc58eSRafal Jaworowski 	}
11039f55f5f5SRafal Jaworowski 
11048e1dc58eSRafal Jaworowski 	/* Initialize TX queue configuration registers */
11058e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(0), sc->mge_tx_tok_cnt);
11068e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_TOKEN_CONF(0), sc->mge_tx_tok_cfg);
11078e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_ARBITER_CONF(0), sc->mge_tx_arb_cfg);
11088e1dc58eSRafal Jaworowski 
11098e1dc58eSRafal Jaworowski 	/* Clear TX queue configuration registers for unused queues */
11109f55f5f5SRafal Jaworowski 	for (i = 1; i < 7; i++) {
11118e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(i), 0);
11128e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_TOKEN_CONF(i), 0);
11138e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_ARBITER_CONF(i), 0);
11149f55f5f5SRafal Jaworowski 	}
11159f55f5f5SRafal Jaworowski 
11169f55f5f5SRafal Jaworowski 	/* Set default MTU */
11178e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, sc->mge_mtu, 0);
11189f55f5f5SRafal Jaworowski 
11199f55f5f5SRafal Jaworowski 	/* Port configuration */
11209f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_CONFIG,
11219f55f5f5SRafal Jaworowski 	    PORT_CONFIG_RXCS | PORT_CONFIG_DFLT_RXQ(0) |
11229f55f5f5SRafal Jaworowski 	    PORT_CONFIG_ARO_RXQ(0));
11239f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_EXT_CONFIG , 0x0);
11249f55f5f5SRafal Jaworowski 
11253c71b84fSZbigniew Bodek 	/* Configure promisc mode */
11263c71b84fSZbigniew Bodek 	mge_set_prom_mode(sc, MGE_RX_DEFAULT_QUEUE);
11273c71b84fSZbigniew Bodek 
11283c71b84fSZbigniew Bodek 	media_status = sc->mge_media_status;
11293c71b84fSZbigniew Bodek 	if (sc->switch_attached) {
11303c71b84fSZbigniew Bodek 		media_status &= ~IFM_TMASK;
11313c71b84fSZbigniew Bodek 		media_status |= IFM_1000_T;
11323c71b84fSZbigniew Bodek 	}
11333c71b84fSZbigniew Bodek 
11349f55f5f5SRafal Jaworowski 	/* Setup port configuration */
11353c71b84fSZbigniew Bodek 	reg_val = mge_set_port_serial_control(media_status);
11369f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
11379f55f5f5SRafal Jaworowski 
11389f55f5f5SRafal Jaworowski 	/* Setup SDMA configuration */
11399f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_SDMA_CONFIG , MGE_SDMA_RX_BYTE_SWAP |
11409f55f5f5SRafal Jaworowski 	    MGE_SDMA_TX_BYTE_SWAP |
11419f55f5f5SRafal Jaworowski 	    MGE_SDMA_RX_BURST_SIZE(MGE_SDMA_BURST_16_WORD) |
11429f55f5f5SRafal Jaworowski 	    MGE_SDMA_TX_BURST_SIZE(MGE_SDMA_BURST_16_WORD));
11439f55f5f5SRafal Jaworowski 
11449f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, 0x0);
11459f55f5f5SRafal Jaworowski 
11469f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_CUR_DESC_PTR, sc->tx_desc_start);
11479f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE),
11489f55f5f5SRafal Jaworowski 	    sc->rx_desc_start);
11499f55f5f5SRafal Jaworowski 
11509f55f5f5SRafal Jaworowski 	/* Reset descriptor indexes */
11519f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = 0;
11529f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
11539f55f5f5SRafal Jaworowski 	sc->tx_desc_used_idx = 0;
11545817716fSRafal Jaworowski 	sc->tx_desc_used_count = 0;
11559f55f5f5SRafal Jaworowski 
11569f55f5f5SRafal Jaworowski 	/* Enable RX descriptors */
11579f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
11589f55f5f5SRafal Jaworowski 		dw = &sc->mge_rx_desc[i];
11599f55f5f5SRafal Jaworowski 		dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
11609f55f5f5SRafal Jaworowski 		dw->mge_desc->buff_size = MCLBYTES;
11619f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
11629f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
11639f55f5f5SRafal Jaworowski 	}
11649f55f5f5SRafal Jaworowski 
11659f55f5f5SRafal Jaworowski 	/* Enable RX queue */
11669f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE));
11679f55f5f5SRafal Jaworowski 
11689f55f5f5SRafal Jaworowski 	/* Enable port */
11699f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL);
11709f55f5f5SRafal Jaworowski 	reg_val |= PORT_SERIAL_ENABLE;
11719f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
11729f55f5f5SRafal Jaworowski 	count = 0x100000;
11739f55f5f5SRafal Jaworowski 	for (;;) {
11749f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_PORT_STATUS);
11759f55f5f5SRafal Jaworowski 		if (reg_val & MGE_STATUS_LINKUP)
11769f55f5f5SRafal Jaworowski 			break;
11779f55f5f5SRafal Jaworowski 		DELAY(100);
11789f55f5f5SRafal Jaworowski 		if (--count == 0) {
11799f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "Timeout on link-up\n");
11809f55f5f5SRafal Jaworowski 			break;
11819f55f5f5SRafal Jaworowski 		}
11829f55f5f5SRafal Jaworowski 	}
11839f55f5f5SRafal Jaworowski 
11849f55f5f5SRafal Jaworowski 	/* Setup interrupts coalescing */
11859f55f5f5SRafal Jaworowski 	mge_set_rxic(sc);
11869f55f5f5SRafal Jaworowski 	mge_set_txic(sc);
11879f55f5f5SRafal Jaworowski 
11889f55f5f5SRafal Jaworowski 	/* Enable interrupts */
11899f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
11909f55f5f5SRafal Jaworowski         /*
11919f55f5f5SRafal Jaworowski 	 * * ...only if polling is not turned on. Disable interrupts explicitly
11929f55f5f5SRafal Jaworowski 	 * if polling is enabled.
11939f55f5f5SRafal Jaworowski 	 */
119496ab5e71SJustin Hibbits 	if (if_getcapenable(sc->ifp) & IFCAP_POLLING)
11959f55f5f5SRafal Jaworowski 		mge_intrs_ctrl(sc, 0);
11969f55f5f5SRafal Jaworowski 	else
11979f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */
11989f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 1);
11999f55f5f5SRafal Jaworowski 
12009f55f5f5SRafal Jaworowski 	/* Activate network interface */
120196ab5e71SJustin Hibbits 	if_setdrvflagbits(sc->ifp, IFF_DRV_RUNNING, 0);
120296ab5e71SJustin Hibbits 	if_setdrvflagbits(sc->ifp, 0, IFF_DRV_OACTIVE);
12039f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
12049f55f5f5SRafal Jaworowski 
12059f55f5f5SRafal Jaworowski 	/* Schedule watchdog timeout */
12063c71b84fSZbigniew Bodek 	if (sc->phy_attached)
12079f55f5f5SRafal Jaworowski 		callout_reset(&sc->wd_callout, hz, mge_tick, sc);
12089f55f5f5SRafal Jaworowski }
12099f55f5f5SRafal Jaworowski 
12109f55f5f5SRafal Jaworowski static void
121175f1438bSOleksandr Tymoshenko mge_intr_rxtx(void *arg)
121275f1438bSOleksandr Tymoshenko {
12134ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
121475f1438bSOleksandr Tymoshenko 	uint32_t int_cause, int_cause_ext;
121575f1438bSOleksandr Tymoshenko 
12164ac30cc1SZbigniew Bodek 	sc = arg;
121775f1438bSOleksandr Tymoshenko 	MGE_GLOBAL_LOCK(sc);
121875f1438bSOleksandr Tymoshenko 
121975f1438bSOleksandr Tymoshenko #ifdef DEVICE_POLLING
122096ab5e71SJustin Hibbits 	if (if_getcapenable(sc->ifp) & IFCAP_POLLING) {
122175f1438bSOleksandr Tymoshenko 		MGE_GLOBAL_UNLOCK(sc);
122275f1438bSOleksandr Tymoshenko 		return;
122375f1438bSOleksandr Tymoshenko 	}
122475f1438bSOleksandr Tymoshenko #endif
122575f1438bSOleksandr Tymoshenko 
122675f1438bSOleksandr Tymoshenko 	/* Get interrupt cause */
122775f1438bSOleksandr Tymoshenko 	int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
122875f1438bSOleksandr Tymoshenko 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
122975f1438bSOleksandr Tymoshenko 
123075f1438bSOleksandr Tymoshenko 	/* Check for Transmit interrupt */
123175f1438bSOleksandr Tymoshenko 	if (int_cause_ext & (MGE_PORT_INT_EXT_TXBUF0 |
123275f1438bSOleksandr Tymoshenko 	    MGE_PORT_INT_EXT_TXUR)) {
123375f1438bSOleksandr Tymoshenko 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext &
123475f1438bSOleksandr Tymoshenko 		    (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR)));
123575f1438bSOleksandr Tymoshenko 		mge_intr_tx_locked(sc);
123675f1438bSOleksandr Tymoshenko 	}
123775f1438bSOleksandr Tymoshenko 
123875f1438bSOleksandr Tymoshenko 	MGE_TRANSMIT_UNLOCK(sc);
123975f1438bSOleksandr Tymoshenko 
124075f1438bSOleksandr Tymoshenko 	/* Check for Receive interrupt */
124175f1438bSOleksandr Tymoshenko 	mge_intr_rx_check(sc, int_cause, int_cause_ext);
124275f1438bSOleksandr Tymoshenko 
124375f1438bSOleksandr Tymoshenko 	MGE_RECEIVE_UNLOCK(sc);
124475f1438bSOleksandr Tymoshenko }
124575f1438bSOleksandr Tymoshenko 
124675f1438bSOleksandr Tymoshenko static void
12479f55f5f5SRafal Jaworowski mge_intr_err(void *arg)
12489f55f5f5SRafal Jaworowski {
12494ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
125098fe10c8SJustin Hibbits 	if_t ifp;
12519f55f5f5SRafal Jaworowski 
12524ac30cc1SZbigniew Bodek 	sc = arg;
12539f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
12549f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
12559f55f5f5SRafal Jaworowski }
12569f55f5f5SRafal Jaworowski 
12579f55f5f5SRafal Jaworowski static void
12589f55f5f5SRafal Jaworowski mge_intr_misc(void *arg)
12599f55f5f5SRafal Jaworowski {
12604ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
126198fe10c8SJustin Hibbits 	if_t ifp;
12629f55f5f5SRafal Jaworowski 
12634ac30cc1SZbigniew Bodek 	sc = arg;
12649f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
12659f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
12669f55f5f5SRafal Jaworowski }
12679f55f5f5SRafal Jaworowski 
12689f55f5f5SRafal Jaworowski static void
12699f55f5f5SRafal Jaworowski mge_intr_rx(void *arg) {
12704ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
12719f55f5f5SRafal Jaworowski 	uint32_t int_cause, int_cause_ext;
12729f55f5f5SRafal Jaworowski 
12734ac30cc1SZbigniew Bodek 	sc = arg;
12749f55f5f5SRafal Jaworowski 	MGE_RECEIVE_LOCK(sc);
12759f55f5f5SRafal Jaworowski 
12769f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
127796ab5e71SJustin Hibbits 	if (if_getcapenable(sc->ifp) & IFCAP_POLLING) {
12789f55f5f5SRafal Jaworowski 		MGE_RECEIVE_UNLOCK(sc);
12799f55f5f5SRafal Jaworowski 		return;
12809f55f5f5SRafal Jaworowski 	}
12819f55f5f5SRafal Jaworowski #endif
12829f55f5f5SRafal Jaworowski 
12839f55f5f5SRafal Jaworowski 	/* Get interrupt cause */
12849f55f5f5SRafal Jaworowski 	int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
12859f55f5f5SRafal Jaworowski 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
12869f55f5f5SRafal Jaworowski 
128775f1438bSOleksandr Tymoshenko 	mge_intr_rx_check(sc, int_cause, int_cause_ext);
128875f1438bSOleksandr Tymoshenko 
128975f1438bSOleksandr Tymoshenko 	MGE_RECEIVE_UNLOCK(sc);
129075f1438bSOleksandr Tymoshenko }
129175f1438bSOleksandr Tymoshenko 
129275f1438bSOleksandr Tymoshenko static void
129375f1438bSOleksandr Tymoshenko mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause,
129475f1438bSOleksandr Tymoshenko     uint32_t int_cause_ext)
129575f1438bSOleksandr Tymoshenko {
12969f55f5f5SRafal Jaworowski 	/* Check for resource error */
12979f55f5f5SRafal Jaworowski 	if (int_cause & MGE_PORT_INT_RXERRQ0) {
12989f55f5f5SRafal Jaworowski 		mge_reinit_rx(sc);
12999f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE,
130075f1438bSOleksandr Tymoshenko 		    ~(int_cause & MGE_PORT_INT_RXERRQ0));
13019f55f5f5SRafal Jaworowski 	}
13029f55f5f5SRafal Jaworowski 
13039f55f5f5SRafal Jaworowski 	int_cause &= MGE_PORT_INT_RXQ0;
13049f55f5f5SRafal Jaworowski 	int_cause_ext &= MGE_PORT_INT_EXT_RXOR;
13059f55f5f5SRafal Jaworowski 
13069f55f5f5SRafal Jaworowski 	if (int_cause || int_cause_ext) {
13079f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause);
13089f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext);
13099f55f5f5SRafal Jaworowski 		mge_intr_rx_locked(sc, -1);
13109f55f5f5SRafal Jaworowski 	}
13119f55f5f5SRafal Jaworowski }
13129f55f5f5SRafal Jaworowski 
13131abcdbd1SAttilio Rao static int
13149f55f5f5SRafal Jaworowski mge_intr_rx_locked(struct mge_softc *sc, int count)
13159f55f5f5SRafal Jaworowski {
131698fe10c8SJustin Hibbits 	if_t ifp = sc->ifp;
13179f55f5f5SRafal Jaworowski 	uint32_t status;
13189f55f5f5SRafal Jaworowski 	uint16_t bufsize;
13199f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper* dw;
13209f55f5f5SRafal Jaworowski 	struct mbuf *mb;
13211abcdbd1SAttilio Rao 	int rx_npkts = 0;
13229f55f5f5SRafal Jaworowski 
13239f55f5f5SRafal Jaworowski 	MGE_RECEIVE_LOCK_ASSERT(sc);
13249f55f5f5SRafal Jaworowski 
13259f55f5f5SRafal Jaworowski 	while (count != 0) {
13269f55f5f5SRafal Jaworowski 		dw = &sc->mge_rx_desc[sc->rx_desc_curr];
13279f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
13289f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
13299f55f5f5SRafal Jaworowski 
13309f55f5f5SRafal Jaworowski 		/* Get status */
13319f55f5f5SRafal Jaworowski 		status = dw->mge_desc->cmd_status;
13329f55f5f5SRafal Jaworowski 		bufsize = dw->mge_desc->buff_size;
13339f55f5f5SRafal Jaworowski 		if ((status & MGE_DMA_OWNED) != 0)
13349f55f5f5SRafal Jaworowski 			break;
13359f55f5f5SRafal Jaworowski 
13369f55f5f5SRafal Jaworowski 		if (dw->mge_desc->byte_count &&
13379f55f5f5SRafal Jaworowski 		    ~(status & MGE_ERR_SUMMARY)) {
13389f55f5f5SRafal Jaworowski 
13399f55f5f5SRafal Jaworowski 			bus_dmamap_sync(sc->mge_rx_dtag, dw->buffer_dmap,
13409f55f5f5SRafal Jaworowski 			    BUS_DMASYNC_POSTREAD);
13419f55f5f5SRafal Jaworowski 
13429f55f5f5SRafal Jaworowski 			mb = m_devget(dw->buffer->m_data,
13439f55f5f5SRafal Jaworowski 			    dw->mge_desc->byte_count - ETHER_CRC_LEN,
13449f55f5f5SRafal Jaworowski 			    0, ifp, NULL);
13459f55f5f5SRafal Jaworowski 
13465817716fSRafal Jaworowski 			if (mb == NULL)
13475817716fSRafal Jaworowski 				/* Give up if no mbufs */
13485817716fSRafal Jaworowski 				break;
13495817716fSRafal Jaworowski 
13509f55f5f5SRafal Jaworowski 			mb->m_len -= 2;
13519f55f5f5SRafal Jaworowski 			mb->m_pkthdr.len -= 2;
13529f55f5f5SRafal Jaworowski 			mb->m_data += 2;
13539f55f5f5SRafal Jaworowski 
1354b8fad6c0SFabien Thomas 			mb->m_pkthdr.rcvif = ifp;
1355b8fad6c0SFabien Thomas 
13569f55f5f5SRafal Jaworowski 			mge_offload_process_frame(ifp, mb, status,
13579f55f5f5SRafal Jaworowski 			    bufsize);
13589f55f5f5SRafal Jaworowski 
13599f55f5f5SRafal Jaworowski 			MGE_RECEIVE_UNLOCK(sc);
136098fe10c8SJustin Hibbits 			if_input(ifp, mb);
13619f55f5f5SRafal Jaworowski 			MGE_RECEIVE_LOCK(sc);
13621abcdbd1SAttilio Rao 			rx_npkts++;
13639f55f5f5SRafal Jaworowski 		}
13649f55f5f5SRafal Jaworowski 
13659f55f5f5SRafal Jaworowski 		dw->mge_desc->byte_count = 0;
13669f55f5f5SRafal Jaworowski 		dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
13675817716fSRafal Jaworowski 		sc->rx_desc_curr = (++sc->rx_desc_curr % MGE_RX_DESC_NUM);
13689f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
13699f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
13709f55f5f5SRafal Jaworowski 
13719f55f5f5SRafal Jaworowski 		if (count > 0)
13729f55f5f5SRafal Jaworowski 			count -= 1;
13739f55f5f5SRafal Jaworowski 	}
13749f55f5f5SRafal Jaworowski 
1375c8dfaf38SGleb Smirnoff 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_npkts);
1376b8fad6c0SFabien Thomas 
13771abcdbd1SAttilio Rao 	return (rx_npkts);
13789f55f5f5SRafal Jaworowski }
13799f55f5f5SRafal Jaworowski 
13809f55f5f5SRafal Jaworowski static void
13819f55f5f5SRafal Jaworowski mge_intr_sum(void *arg)
13829f55f5f5SRafal Jaworowski {
13839f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
138498fe10c8SJustin Hibbits 	if_t ifp;
13859f55f5f5SRafal Jaworowski 
13869f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
13879f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
13889f55f5f5SRafal Jaworowski }
13899f55f5f5SRafal Jaworowski 
13909f55f5f5SRafal Jaworowski static void
13919f55f5f5SRafal Jaworowski mge_intr_tx(void *arg)
13929f55f5f5SRafal Jaworowski {
13939f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
13949f55f5f5SRafal Jaworowski 	uint32_t int_cause_ext;
13959f55f5f5SRafal Jaworowski 
13969f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK(sc);
13979f55f5f5SRafal Jaworowski 
13989f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
139996ab5e71SJustin Hibbits 	if (if_getcapenable(sc->ifp) & IFCAP_POLLING) {
14009f55f5f5SRafal Jaworowski 		MGE_TRANSMIT_UNLOCK(sc);
14019f55f5f5SRafal Jaworowski 		return;
14029f55f5f5SRafal Jaworowski 	}
14039f55f5f5SRafal Jaworowski #endif
14049f55f5f5SRafal Jaworowski 
14059f55f5f5SRafal Jaworowski 	/* Ack the interrupt */
14069f55f5f5SRafal Jaworowski 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
140775f1438bSOleksandr Tymoshenko 	MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext &
140875f1438bSOleksandr Tymoshenko 	    (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR)));
14099f55f5f5SRafal Jaworowski 
14109f55f5f5SRafal Jaworowski 	mge_intr_tx_locked(sc);
14119f55f5f5SRafal Jaworowski 
14129f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_UNLOCK(sc);
14139f55f5f5SRafal Jaworowski }
14149f55f5f5SRafal Jaworowski 
14159f55f5f5SRafal Jaworowski static void
14169f55f5f5SRafal Jaworowski mge_intr_tx_locked(struct mge_softc *sc)
14179f55f5f5SRafal Jaworowski {
141898fe10c8SJustin Hibbits 	if_t ifp = sc->ifp;
14199f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
14209f55f5f5SRafal Jaworowski 	struct mge_desc *desc;
14219f55f5f5SRafal Jaworowski 	uint32_t status;
14229f55f5f5SRafal Jaworowski 	int send = 0;
14239f55f5f5SRafal Jaworowski 
14249f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK_ASSERT(sc);
14259f55f5f5SRafal Jaworowski 
14269f55f5f5SRafal Jaworowski 	/* Disable watchdog */
14279f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
14289f55f5f5SRafal Jaworowski 
14299f55f5f5SRafal Jaworowski 	while (sc->tx_desc_used_count) {
14309f55f5f5SRafal Jaworowski 		/* Get the descriptor */
14319f55f5f5SRafal Jaworowski 		dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
14329f55f5f5SRafal Jaworowski 		desc = dw->mge_desc;
14339f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
14349f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
14359f55f5f5SRafal Jaworowski 
14369f55f5f5SRafal Jaworowski 		/* Get descriptor status */
14379f55f5f5SRafal Jaworowski 		status = desc->cmd_status;
14389f55f5f5SRafal Jaworowski 
14399f55f5f5SRafal Jaworowski 		if (status & MGE_DMA_OWNED)
14409f55f5f5SRafal Jaworowski 			break;
14419f55f5f5SRafal Jaworowski 
14429f55f5f5SRafal Jaworowski 		sc->tx_desc_used_idx =
1443c2ede4b3SMartin Blapp 			(++sc->tx_desc_used_idx) % MGE_TX_DESC_NUM;
14449f55f5f5SRafal Jaworowski 		sc->tx_desc_used_count--;
14459f55f5f5SRafal Jaworowski 
14469f55f5f5SRafal Jaworowski 		/* Update collision statistics */
14479f55f5f5SRafal Jaworowski 		if (status & MGE_ERR_SUMMARY) {
14489f55f5f5SRafal Jaworowski 			if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_LC)
1449c8dfaf38SGleb Smirnoff 				if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1);
14509f55f5f5SRafal Jaworowski 			if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_RL)
1451c8dfaf38SGleb Smirnoff 				if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 16);
14529f55f5f5SRafal Jaworowski 		}
14539f55f5f5SRafal Jaworowski 
14549f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
14559f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTWRITE);
14569f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap);
14579f55f5f5SRafal Jaworowski 		m_freem(dw->buffer);
14589f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
14599f55f5f5SRafal Jaworowski 		send++;
14609f55f5f5SRafal Jaworowski 
1461c8dfaf38SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
14629f55f5f5SRafal Jaworowski 	}
14639f55f5f5SRafal Jaworowski 
14649f55f5f5SRafal Jaworowski 	if (send) {
14659f55f5f5SRafal Jaworowski 		/* Now send anything that was pending */
146698fe10c8SJustin Hibbits 		if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
14679f55f5f5SRafal Jaworowski 		mge_start_locked(ifp);
14689f55f5f5SRafal Jaworowski 	}
14699f55f5f5SRafal Jaworowski }
14709f55f5f5SRafal Jaworowski static int
147198fe10c8SJustin Hibbits mge_ioctl(if_t ifp, u_long command, caddr_t data)
14729f55f5f5SRafal Jaworowski {
147398fe10c8SJustin Hibbits 	struct mge_softc *sc = if_getsoftc(ifp);
14749f55f5f5SRafal Jaworowski 	struct ifreq *ifr = (struct ifreq *)data;
14759f55f5f5SRafal Jaworowski 	int mask, error;
14769f55f5f5SRafal Jaworowski 	uint32_t flags;
14779f55f5f5SRafal Jaworowski 
14789f55f5f5SRafal Jaworowski 	error = 0;
14799f55f5f5SRafal Jaworowski 
14809f55f5f5SRafal Jaworowski 	switch (command) {
14819f55f5f5SRafal Jaworowski 	case SIOCSIFFLAGS:
14829f55f5f5SRafal Jaworowski 		MGE_GLOBAL_LOCK(sc);
14839f55f5f5SRafal Jaworowski 
148498fe10c8SJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
148598fe10c8SJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
148698fe10c8SJustin Hibbits 				flags = if_getflags(ifp) ^ sc->mge_if_flags;
14879f55f5f5SRafal Jaworowski 				if (flags & IFF_PROMISC)
14889f55f5f5SRafal Jaworowski 					mge_set_prom_mode(sc,
14899f55f5f5SRafal Jaworowski 					    MGE_RX_DEFAULT_QUEUE);
14909f55f5f5SRafal Jaworowski 
14919f55f5f5SRafal Jaworowski 				if (flags & IFF_ALLMULTI)
14929f55f5f5SRafal Jaworowski 					mge_setup_multicast(sc);
14939f55f5f5SRafal Jaworowski 			} else
14949f55f5f5SRafal Jaworowski 				mge_init_locked(sc);
14959f55f5f5SRafal Jaworowski 		}
149698fe10c8SJustin Hibbits 		else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
14979f55f5f5SRafal Jaworowski 			mge_stop(sc);
14989f55f5f5SRafal Jaworowski 
149998fe10c8SJustin Hibbits 		sc->mge_if_flags = if_getflags(ifp);
15009f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
15019f55f5f5SRafal Jaworowski 		break;
15029f55f5f5SRafal Jaworowski 	case SIOCADDMULTI:
15039f55f5f5SRafal Jaworowski 	case SIOCDELMULTI:
150498fe10c8SJustin Hibbits 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
15059f55f5f5SRafal Jaworowski 			MGE_GLOBAL_LOCK(sc);
15069f55f5f5SRafal Jaworowski 			mge_setup_multicast(sc);
15079f55f5f5SRafal Jaworowski 			MGE_GLOBAL_UNLOCK(sc);
15089f55f5f5SRafal Jaworowski 		}
15099f55f5f5SRafal Jaworowski 		break;
15109f55f5f5SRafal Jaworowski 	case SIOCSIFCAP:
151198fe10c8SJustin Hibbits 		mask = if_getcapenable(ifp) ^ ifr->ifr_reqcap;
15129f55f5f5SRafal Jaworowski 		if (mask & IFCAP_HWCSUM) {
151398fe10c8SJustin Hibbits 			if_setcapenablebit(ifp, 0, IFCAP_HWCSUM);
151498fe10c8SJustin Hibbits 			if_setcapenablebit(ifp, IFCAP_HWCSUM & ifr->ifr_reqcap, 0);
151598fe10c8SJustin Hibbits 			if (if_getcapenable(ifp) & IFCAP_TXCSUM)
151698fe10c8SJustin Hibbits 				if_sethwassist(ifp, MGE_CHECKSUM_FEATURES);
15179f55f5f5SRafal Jaworowski 			else
151898fe10c8SJustin Hibbits 				if_sethwassist(ifp, 0);
15199f55f5f5SRafal Jaworowski 		}
15209f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
15219f55f5f5SRafal Jaworowski 		if (mask & IFCAP_POLLING) {
15229f55f5f5SRafal Jaworowski 			if (ifr->ifr_reqcap & IFCAP_POLLING) {
15239f55f5f5SRafal Jaworowski 				error = ether_poll_register(mge_poll, ifp);
15249f55f5f5SRafal Jaworowski 				if (error)
15259f55f5f5SRafal Jaworowski 					return(error);
15269f55f5f5SRafal Jaworowski 
15279f55f5f5SRafal Jaworowski 				MGE_GLOBAL_LOCK(sc);
15289f55f5f5SRafal Jaworowski 				mge_intrs_ctrl(sc, 0);
152998fe10c8SJustin Hibbits 				if_setcapenablebit(ifp, IFCAP_POLLING, 0);
15309f55f5f5SRafal Jaworowski 				MGE_GLOBAL_UNLOCK(sc);
15319f55f5f5SRafal Jaworowski 			} else {
15329f55f5f5SRafal Jaworowski 				error = ether_poll_deregister(ifp);
15339f55f5f5SRafal Jaworowski 				MGE_GLOBAL_LOCK(sc);
15349f55f5f5SRafal Jaworowski 				mge_intrs_ctrl(sc, 1);
153598fe10c8SJustin Hibbits 				if_setcapenablebit(ifp, 0, IFCAP_POLLING);
15369f55f5f5SRafal Jaworowski 				MGE_GLOBAL_UNLOCK(sc);
15379f55f5f5SRafal Jaworowski 			}
15389f55f5f5SRafal Jaworowski 		}
15399f55f5f5SRafal Jaworowski #endif
15409f55f5f5SRafal Jaworowski 		break;
15419f55f5f5SRafal Jaworowski 	case SIOCGIFMEDIA: /* fall through */
15429f55f5f5SRafal Jaworowski 	case SIOCSIFMEDIA:
15433c71b84fSZbigniew Bodek 		/*
15443c71b84fSZbigniew Bodek 		 * Setting up media type via ioctls is *not* supported for MAC
15453c71b84fSZbigniew Bodek 		 * which is connected to switch. Use etherswitchcfg.
15463c71b84fSZbigniew Bodek 		 */
15473c71b84fSZbigniew Bodek 		if (!sc->phy_attached && (command == SIOCSIFMEDIA))
15483c71b84fSZbigniew Bodek 			return (0);
15493c71b84fSZbigniew Bodek 		else if (!sc->phy_attached) {
15503c71b84fSZbigniew Bodek 			error = ifmedia_ioctl(ifp, ifr, &sc->mge_ifmedia,
15513c71b84fSZbigniew Bodek 			    command);
15523c71b84fSZbigniew Bodek 			break;
15533c71b84fSZbigniew Bodek 		}
15543c71b84fSZbigniew Bodek 
15559f55f5f5SRafal Jaworowski 		if (IFM_SUBTYPE(ifr->ifr_media) == IFM_1000_T
15569f55f5f5SRafal Jaworowski 		    && !(ifr->ifr_media & IFM_FDX)) {
15579f55f5f5SRafal Jaworowski 			device_printf(sc->dev,
15589f55f5f5SRafal Jaworowski 			    "1000baseTX half-duplex unsupported\n");
15599f55f5f5SRafal Jaworowski 			return 0;
15609f55f5f5SRafal Jaworowski 		}
15619f55f5f5SRafal Jaworowski 		error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command);
15629f55f5f5SRafal Jaworowski 		break;
15639f55f5f5SRafal Jaworowski 	default:
15649f55f5f5SRafal Jaworowski 		error = ether_ioctl(ifp, command, data);
15659f55f5f5SRafal Jaworowski 	}
15669f55f5f5SRafal Jaworowski 	return (error);
15679f55f5f5SRafal Jaworowski }
15689f55f5f5SRafal Jaworowski 
15699f55f5f5SRafal Jaworowski static int
15709f55f5f5SRafal Jaworowski mge_miibus_readreg(device_t dev, int phy, int reg)
15719f55f5f5SRafal Jaworowski {
15729f55f5f5SRafal Jaworowski 
15733c71b84fSZbigniew Bodek 	KASSERT(!switch_attached, ("miibus used with switch attached"));
15749f55f5f5SRafal Jaworowski 
15753c71b84fSZbigniew Bodek 	return (mv_read_ext_phy(dev, phy, reg));
15769f55f5f5SRafal Jaworowski }
15779f55f5f5SRafal Jaworowski 
15788e45f0b7SAndriy Gapon static int
15799f55f5f5SRafal Jaworowski mge_miibus_writereg(device_t dev, int phy, int reg, int value)
15809f55f5f5SRafal Jaworowski {
1581db5ef4fcSRafal Jaworowski 
15823c71b84fSZbigniew Bodek 	KASSERT(!switch_attached, ("miibus used with switch attached"));
15839f55f5f5SRafal Jaworowski 
15843c71b84fSZbigniew Bodek 	mv_write_ext_phy(dev, phy, reg, value);
15859f55f5f5SRafal Jaworowski 
15868e45f0b7SAndriy Gapon 	return (0);
15879f55f5f5SRafal Jaworowski }
15889f55f5f5SRafal Jaworowski 
15899f55f5f5SRafal Jaworowski static int
15909f55f5f5SRafal Jaworowski mge_probe(device_t dev)
15919f55f5f5SRafal Jaworowski {
15929f55f5f5SRafal Jaworowski 
1593add35ed5SIan Lepore 	if (!ofw_bus_status_okay(dev))
1594add35ed5SIan Lepore 		return (ENXIO);
1595add35ed5SIan Lepore 
1596db5ef4fcSRafal Jaworowski 	if (!ofw_bus_is_compatible(dev, "mrvl,ge"))
1597db5ef4fcSRafal Jaworowski 		return (ENXIO);
1598db5ef4fcSRafal Jaworowski 
15999f55f5f5SRafal Jaworowski 	device_set_desc(dev, "Marvell Gigabit Ethernet controller");
16009f55f5f5SRafal Jaworowski 	return (BUS_PROBE_DEFAULT);
16019f55f5f5SRafal Jaworowski }
16029f55f5f5SRafal Jaworowski 
16039f55f5f5SRafal Jaworowski static int
16049f55f5f5SRafal Jaworowski mge_resume(device_t dev)
16059f55f5f5SRafal Jaworowski {
16069f55f5f5SRafal Jaworowski 
16079f55f5f5SRafal Jaworowski 	device_printf(dev, "%s\n", __FUNCTION__);
16089f55f5f5SRafal Jaworowski 	return (0);
16099f55f5f5SRafal Jaworowski }
16109f55f5f5SRafal Jaworowski 
16119f55f5f5SRafal Jaworowski static int
16129f55f5f5SRafal Jaworowski mge_shutdown(device_t dev)
16139f55f5f5SRafal Jaworowski {
16149f55f5f5SRafal Jaworowski 	struct mge_softc *sc = device_get_softc(dev);
16159f55f5f5SRafal Jaworowski 
16169f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
16179f55f5f5SRafal Jaworowski 
16189f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
161996ab5e71SJustin Hibbits         if (if_getcapenable(sc->ifp) & IFCAP_POLLING)
16209f55f5f5SRafal Jaworowski 		ether_poll_deregister(sc->ifp);
16219f55f5f5SRafal Jaworowski #endif
16229f55f5f5SRafal Jaworowski 
16239f55f5f5SRafal Jaworowski 	mge_stop(sc);
16249f55f5f5SRafal Jaworowski 
16259f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
16269f55f5f5SRafal Jaworowski 
16279f55f5f5SRafal Jaworowski 	return (0);
16289f55f5f5SRafal Jaworowski }
16299f55f5f5SRafal Jaworowski 
16309f55f5f5SRafal Jaworowski static int
16319f55f5f5SRafal Jaworowski mge_encap(struct mge_softc *sc, struct mbuf *m0)
16329f55f5f5SRafal Jaworowski {
16339f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw = NULL;
16349f55f5f5SRafal Jaworowski 	bus_dma_segment_t segs[MGE_TX_DESC_NUM];
16359f55f5f5SRafal Jaworowski 	bus_dmamap_t mapp;
16369f55f5f5SRafal Jaworowski 	int error;
16379f55f5f5SRafal Jaworowski 	int seg, nsegs;
16389f55f5f5SRafal Jaworowski 	int desc_no;
16399f55f5f5SRafal Jaworowski 
16409f55f5f5SRafal Jaworowski 	/* Fetch unused map */
16419f55f5f5SRafal Jaworowski 	desc_no = sc->tx_desc_curr;
16429f55f5f5SRafal Jaworowski 	dw = &sc->mge_tx_desc[desc_no];
16439f55f5f5SRafal Jaworowski 	mapp = dw->buffer_dmap;
16449f55f5f5SRafal Jaworowski 
16459f55f5f5SRafal Jaworowski 	/* Create mapping in DMA memory */
16469f55f5f5SRafal Jaworowski 	error = bus_dmamap_load_mbuf_sg(sc->mge_tx_dtag, mapp, m0, segs, &nsegs,
16479f55f5f5SRafal Jaworowski 	    BUS_DMA_NOWAIT);
1648b8fad6c0SFabien Thomas 	if (error != 0) {
1649b8fad6c0SFabien Thomas 		m_freem(m0);
1650b8fad6c0SFabien Thomas 		return (error);
1651b8fad6c0SFabien Thomas 	}
1652b8fad6c0SFabien Thomas 
1653b8fad6c0SFabien Thomas 	/* Only one segment is supported. */
1654b8fad6c0SFabien Thomas 	if (nsegs != 1) {
16559f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, mapp);
1656b8fad6c0SFabien Thomas 		m_freem(m0);
1657b8fad6c0SFabien Thomas 		return (-1);
16589f55f5f5SRafal Jaworowski 	}
16599f55f5f5SRafal Jaworowski 
16609f55f5f5SRafal Jaworowski 	bus_dmamap_sync(sc->mge_tx_dtag, mapp, BUS_DMASYNC_PREWRITE);
16619f55f5f5SRafal Jaworowski 
16629f55f5f5SRafal Jaworowski 	/* Everything is ok, now we can send buffers */
16639f55f5f5SRafal Jaworowski 	for (seg = 0; seg < nsegs; seg++) {
16649f55f5f5SRafal Jaworowski 		dw->mge_desc->byte_count = segs[seg].ds_len;
16659f55f5f5SRafal Jaworowski 		dw->mge_desc->buffer = segs[seg].ds_addr;
16669f55f5f5SRafal Jaworowski 		dw->buffer = m0;
166775f1438bSOleksandr Tymoshenko 		dw->mge_desc->cmd_status = 0;
16689f55f5f5SRafal Jaworowski 		if (seg == 0)
16699f55f5f5SRafal Jaworowski 			mge_offload_setup_descriptor(sc, dw);
167075f1438bSOleksandr Tymoshenko 		dw->mge_desc->cmd_status |= MGE_TX_LAST | MGE_TX_FIRST |
167175f1438bSOleksandr Tymoshenko 		    MGE_TX_ETH_CRC | MGE_TX_EN_INT | MGE_TX_PADDING |
167275f1438bSOleksandr Tymoshenko 		    MGE_DMA_OWNED;
16739f55f5f5SRafal Jaworowski 	}
16749f55f5f5SRafal Jaworowski 
1675d6bdd318SRafal Jaworowski 	bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
16769f55f5f5SRafal Jaworowski 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
16779f55f5f5SRafal Jaworowski 
16789f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = (++sc->tx_desc_curr) % MGE_TX_DESC_NUM;
16799f55f5f5SRafal Jaworowski 	sc->tx_desc_used_count++;
16809f55f5f5SRafal Jaworowski 	return (0);
16819f55f5f5SRafal Jaworowski }
16829f55f5f5SRafal Jaworowski 
16839f55f5f5SRafal Jaworowski static void
16849f55f5f5SRafal Jaworowski mge_tick(void *msc)
16859f55f5f5SRafal Jaworowski {
16869f55f5f5SRafal Jaworowski 	struct mge_softc *sc = msc;
16879f55f5f5SRafal Jaworowski 
16883c71b84fSZbigniew Bodek 	KASSERT(sc->phy_attached == 1, ("mge_tick while PHY not attached"));
16893c71b84fSZbigniew Bodek 
16903c71b84fSZbigniew Bodek 	MGE_GLOBAL_LOCK(sc);
16913c71b84fSZbigniew Bodek 
16929f55f5f5SRafal Jaworowski 	/* Check for TX timeout */
16939f55f5f5SRafal Jaworowski 	mge_watchdog(sc);
16949f55f5f5SRafal Jaworowski 
16959f55f5f5SRafal Jaworowski 	mii_tick(sc->mii);
16969f55f5f5SRafal Jaworowski 
16979f55f5f5SRafal Jaworowski 	/* Check for media type change */
16989f55f5f5SRafal Jaworowski 	if(sc->mge_media_status != sc->mii->mii_media.ifm_media)
16999f55f5f5SRafal Jaworowski 		mge_ifmedia_upd(sc->ifp);
17009f55f5f5SRafal Jaworowski 
17013c71b84fSZbigniew Bodek 	MGE_GLOBAL_UNLOCK(sc);
17023c71b84fSZbigniew Bodek 
17039f55f5f5SRafal Jaworowski 	/* Schedule another timeout one second from now */
17049f55f5f5SRafal Jaworowski 	callout_reset(&sc->wd_callout, hz, mge_tick, sc);
17053c71b84fSZbigniew Bodek 
17063c71b84fSZbigniew Bodek 	return;
17079f55f5f5SRafal Jaworowski }
17089f55f5f5SRafal Jaworowski 
17099f55f5f5SRafal Jaworowski static void
17109f55f5f5SRafal Jaworowski mge_watchdog(struct mge_softc *sc)
17119f55f5f5SRafal Jaworowski {
171298fe10c8SJustin Hibbits 	if_t ifp;
17139f55f5f5SRafal Jaworowski 
17149f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
17159f55f5f5SRafal Jaworowski 
17169f55f5f5SRafal Jaworowski 	if (sc->wd_timer == 0 || --sc->wd_timer) {
17179f55f5f5SRafal Jaworowski 		return;
17189f55f5f5SRafal Jaworowski 	}
17199f55f5f5SRafal Jaworowski 
1720c8dfaf38SGleb Smirnoff 	if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
17219f55f5f5SRafal Jaworowski 	if_printf(ifp, "watchdog timeout\n");
17229f55f5f5SRafal Jaworowski 
17239f55f5f5SRafal Jaworowski 	mge_stop(sc);
17249f55f5f5SRafal Jaworowski 	mge_init_locked(sc);
17259f55f5f5SRafal Jaworowski }
17269f55f5f5SRafal Jaworowski 
17279f55f5f5SRafal Jaworowski static void
172898fe10c8SJustin Hibbits mge_start(if_t ifp)
17299f55f5f5SRafal Jaworowski {
173098fe10c8SJustin Hibbits 	struct mge_softc *sc = if_getsoftc(ifp);
17319f55f5f5SRafal Jaworowski 
17329f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK(sc);
17339f55f5f5SRafal Jaworowski 
17349f55f5f5SRafal Jaworowski 	mge_start_locked(ifp);
17359f55f5f5SRafal Jaworowski 
17369f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_UNLOCK(sc);
17379f55f5f5SRafal Jaworowski }
17389f55f5f5SRafal Jaworowski 
17399f55f5f5SRafal Jaworowski static void
174098fe10c8SJustin Hibbits mge_start_locked(if_t ifp)
17419f55f5f5SRafal Jaworowski {
17429f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
17439f55f5f5SRafal Jaworowski 	struct mbuf *m0, *mtmp;
17449f55f5f5SRafal Jaworowski 	uint32_t reg_val, queued = 0;
17459f55f5f5SRafal Jaworowski 
174698fe10c8SJustin Hibbits 	sc = if_getsoftc(ifp);
17479f55f5f5SRafal Jaworowski 
17489f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK_ASSERT(sc);
17499f55f5f5SRafal Jaworowski 
175098fe10c8SJustin Hibbits 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
17519f55f5f5SRafal Jaworowski 	    IFF_DRV_RUNNING)
17529f55f5f5SRafal Jaworowski 		return;
17539f55f5f5SRafal Jaworowski 
17549f55f5f5SRafal Jaworowski 	for (;;) {
17559f55f5f5SRafal Jaworowski 		/* Get packet from the queue */
175698fe10c8SJustin Hibbits 		m0 = if_dequeue(ifp);
17579f55f5f5SRafal Jaworowski 		if (m0 == NULL)
17589f55f5f5SRafal Jaworowski 			break;
17599f55f5f5SRafal Jaworowski 
1760b8fad6c0SFabien Thomas 		if (m0->m_pkthdr.csum_flags & (CSUM_IP|CSUM_TCP|CSUM_UDP) ||
1761b8fad6c0SFabien Thomas 		    m0->m_flags & M_VLANTAG) {
1762b8fad6c0SFabien Thomas 			if (M_WRITABLE(m0) == 0) {
1763b8fad6c0SFabien Thomas 				mtmp = m_dup(m0, M_NOWAIT);
1764b8fad6c0SFabien Thomas 				m_freem(m0);
1765b8fad6c0SFabien Thomas 				if (mtmp == NULL)
1766b8fad6c0SFabien Thomas 					continue;
1767b8fad6c0SFabien Thomas 				m0 = mtmp;
1768b8fad6c0SFabien Thomas 			}
1769b8fad6c0SFabien Thomas 		}
1770b8fad6c0SFabien Thomas 		/* The driver support only one DMA fragment. */
1771b8fad6c0SFabien Thomas 		if (m0->m_next != NULL) {
1772c6499eccSGleb Smirnoff 			mtmp = m_defrag(m0, M_NOWAIT);
17734ac30cc1SZbigniew Bodek 			if (mtmp != NULL)
17749f55f5f5SRafal Jaworowski 				m0 = mtmp;
1775b8fad6c0SFabien Thomas 		}
17769f55f5f5SRafal Jaworowski 
1777b8fad6c0SFabien Thomas 		/* Check for free descriptors */
1778b8fad6c0SFabien Thomas 		if (sc->tx_desc_used_count + 1 >= MGE_TX_DESC_NUM) {
177998fe10c8SJustin Hibbits 			if_sendq_prepend(ifp, m0);
178098fe10c8SJustin Hibbits 			if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
17819f55f5f5SRafal Jaworowski 			break;
17829f55f5f5SRafal Jaworowski 		}
1783b8fad6c0SFabien Thomas 
1784b8fad6c0SFabien Thomas 		if (mge_encap(sc, m0) != 0)
1785b8fad6c0SFabien Thomas 			break;
1786b8fad6c0SFabien Thomas 
17879f55f5f5SRafal Jaworowski 		queued++;
17889f55f5f5SRafal Jaworowski 		BPF_MTAP(ifp, m0);
17899f55f5f5SRafal Jaworowski 	}
17909f55f5f5SRafal Jaworowski 
17919f55f5f5SRafal Jaworowski 	if (queued) {
17929f55f5f5SRafal Jaworowski 		/* Enable transmitter and watchdog timer */
17939f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD);
17949f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_ENABLE_TXQ);
17959f55f5f5SRafal Jaworowski 		sc->wd_timer = 5;
17969f55f5f5SRafal Jaworowski 	}
17979f55f5f5SRafal Jaworowski }
17989f55f5f5SRafal Jaworowski 
17999f55f5f5SRafal Jaworowski static void
18009f55f5f5SRafal Jaworowski mge_stop(struct mge_softc *sc)
18019f55f5f5SRafal Jaworowski {
180298fe10c8SJustin Hibbits 	if_t ifp;
18039f55f5f5SRafal Jaworowski 	volatile uint32_t reg_val, status;
18049f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
18059f55f5f5SRafal Jaworowski 	struct mge_desc *desc;
18069f55f5f5SRafal Jaworowski 	int count;
18079f55f5f5SRafal Jaworowski 
18089f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
18099f55f5f5SRafal Jaworowski 
181098fe10c8SJustin Hibbits 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
18119f55f5f5SRafal Jaworowski 		return;
18129f55f5f5SRafal Jaworowski 
18139f55f5f5SRafal Jaworowski 	/* Stop tick engine */
18149f55f5f5SRafal Jaworowski 	callout_stop(&sc->wd_callout);
18159f55f5f5SRafal Jaworowski 
18169f55f5f5SRafal Jaworowski 	/* Disable interface */
181798fe10c8SJustin Hibbits 	if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
18189f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
18199f55f5f5SRafal Jaworowski 
18209f55f5f5SRafal Jaworowski 	/* Disable interrupts */
18219f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 0);
18229f55f5f5SRafal Jaworowski 
18239f55f5f5SRafal Jaworowski 	/* Disable Rx and Tx */
18249f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD);
18259f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_DISABLE_TXQ);
18269f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_DISABLE_RXQ_ALL);
18279f55f5f5SRafal Jaworowski 
18289f55f5f5SRafal Jaworowski 	/* Remove pending data from TX queue */
18295817716fSRafal Jaworowski 	while (sc->tx_desc_used_idx != sc->tx_desc_curr &&
18305817716fSRafal Jaworowski 	    sc->tx_desc_used_count) {
18319f55f5f5SRafal Jaworowski 		/* Get the descriptor */
18329f55f5f5SRafal Jaworowski 		dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
18339f55f5f5SRafal Jaworowski 		desc = dw->mge_desc;
18349f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
18359f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
18369f55f5f5SRafal Jaworowski 
18379f55f5f5SRafal Jaworowski 		/* Get descriptor status */
18389f55f5f5SRafal Jaworowski 		status = desc->cmd_status;
18399f55f5f5SRafal Jaworowski 
18409f55f5f5SRafal Jaworowski 		if (status & MGE_DMA_OWNED)
18419f55f5f5SRafal Jaworowski 			break;
18429f55f5f5SRafal Jaworowski 
18439f55f5f5SRafal Jaworowski 		sc->tx_desc_used_idx = (++sc->tx_desc_used_idx) %
18449f55f5f5SRafal Jaworowski 		    MGE_TX_DESC_NUM;
18455817716fSRafal Jaworowski 		sc->tx_desc_used_count--;
18469f55f5f5SRafal Jaworowski 
18479f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
18489f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTWRITE);
18499f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap);
18509f55f5f5SRafal Jaworowski 
18519f55f5f5SRafal Jaworowski 		m_freem(dw->buffer);
18529f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
18539f55f5f5SRafal Jaworowski 	}
18549f55f5f5SRafal Jaworowski 
18559f55f5f5SRafal Jaworowski 	/* Wait for end of transmission */
18569f55f5f5SRafal Jaworowski 	count = 0x100000;
18579f55f5f5SRafal Jaworowski 	while (count--) {
18589f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_PORT_STATUS);
18599f55f5f5SRafal Jaworowski 		if ( !(reg_val & MGE_STATUS_TX_IN_PROG) &&
18609f55f5f5SRafal Jaworowski 		    (reg_val & MGE_STATUS_TX_FIFO_EMPTY))
18619f55f5f5SRafal Jaworowski 			break;
18629f55f5f5SRafal Jaworowski 		DELAY(100);
18639f55f5f5SRafal Jaworowski 	}
18649f55f5f5SRafal Jaworowski 
18654ac30cc1SZbigniew Bodek 	if (count == 0)
18664ac30cc1SZbigniew Bodek 		if_printf(ifp,
18674ac30cc1SZbigniew Bodek 		    "%s: timeout while waiting for end of transmission\n",
18689f55f5f5SRafal Jaworowski 		    __FUNCTION__);
18699f55f5f5SRafal Jaworowski 
18709f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL);
18719f55f5f5SRafal Jaworowski 	reg_val &= ~(PORT_SERIAL_ENABLE);
18729f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL ,reg_val);
18739f55f5f5SRafal Jaworowski }
18749f55f5f5SRafal Jaworowski 
18759f55f5f5SRafal Jaworowski static int
18769f55f5f5SRafal Jaworowski mge_suspend(device_t dev)
18779f55f5f5SRafal Jaworowski {
18789f55f5f5SRafal Jaworowski 
18799f55f5f5SRafal Jaworowski 	device_printf(dev, "%s\n", __FUNCTION__);
18809f55f5f5SRafal Jaworowski 	return (0);
18819f55f5f5SRafal Jaworowski }
18829f55f5f5SRafal Jaworowski 
18839f55f5f5SRafal Jaworowski static void
188498fe10c8SJustin Hibbits mge_offload_process_frame(if_t ifp, struct mbuf *frame,
18859f55f5f5SRafal Jaworowski     uint32_t status, uint16_t bufsize)
18869f55f5f5SRafal Jaworowski {
18879f55f5f5SRafal Jaworowski 	int csum_flags = 0;
18889f55f5f5SRafal Jaworowski 
188998fe10c8SJustin Hibbits 	if (if_getcapenable(ifp) & IFCAP_RXCSUM) {
18909f55f5f5SRafal Jaworowski 		if ((status & MGE_RX_L3_IS_IP) && (status & MGE_RX_IP_OK))
18919f55f5f5SRafal Jaworowski 			csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID;
18929f55f5f5SRafal Jaworowski 
18939f55f5f5SRafal Jaworowski 		if ((bufsize & MGE_RX_IP_FRAGMENT) == 0 &&
18949f55f5f5SRafal Jaworowski 		    (MGE_RX_L4_IS_TCP(status) || MGE_RX_L4_IS_UDP(status)) &&
18959f55f5f5SRafal Jaworowski 		    (status & MGE_RX_L4_CSUM_OK)) {
18969f55f5f5SRafal Jaworowski 			csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
18979f55f5f5SRafal Jaworowski 			frame->m_pkthdr.csum_data = 0xFFFF;
18989f55f5f5SRafal Jaworowski 		}
18999f55f5f5SRafal Jaworowski 
19009f55f5f5SRafal Jaworowski 		frame->m_pkthdr.csum_flags = csum_flags;
19019f55f5f5SRafal Jaworowski 	}
19029f55f5f5SRafal Jaworowski }
19039f55f5f5SRafal Jaworowski 
19049f55f5f5SRafal Jaworowski static void
19059f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(struct mge_softc *sc, struct mge_desc_wrapper *dw)
19069f55f5f5SRafal Jaworowski {
19079f55f5f5SRafal Jaworowski 	struct mbuf *m0 = dw->buffer;
19089f55f5f5SRafal Jaworowski 	struct ether_vlan_header *eh = mtod(m0, struct ether_vlan_header *);
19099f55f5f5SRafal Jaworowski 	int csum_flags = m0->m_pkthdr.csum_flags;
19109f55f5f5SRafal Jaworowski 	int cmd_status = 0;
19119f55f5f5SRafal Jaworowski 	struct ip *ip;
19129f55f5f5SRafal Jaworowski 	int ehlen, etype;
19139f55f5f5SRafal Jaworowski 
19144ac30cc1SZbigniew Bodek 	if (csum_flags != 0) {
19159f55f5f5SRafal Jaworowski 		if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
19169f55f5f5SRafal Jaworowski 			etype = ntohs(eh->evl_proto);
19179f55f5f5SRafal Jaworowski 			ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
19189f55f5f5SRafal Jaworowski 			csum_flags |= MGE_TX_VLAN_TAGGED;
19199f55f5f5SRafal Jaworowski 		} else {
19209f55f5f5SRafal Jaworowski 			etype = ntohs(eh->evl_encap_proto);
19219f55f5f5SRafal Jaworowski 			ehlen = ETHER_HDR_LEN;
19229f55f5f5SRafal Jaworowski 		}
19239f55f5f5SRafal Jaworowski 
19249f55f5f5SRafal Jaworowski 		if (etype != ETHERTYPE_IP) {
19259f55f5f5SRafal Jaworowski 			if_printf(sc->ifp,
19269f55f5f5SRafal Jaworowski 			    "TCP/IP Offload enabled for unsupported "
19279f55f5f5SRafal Jaworowski 			    "protocol!\n");
19289f55f5f5SRafal Jaworowski 			return;
19299f55f5f5SRafal Jaworowski 		}
19309f55f5f5SRafal Jaworowski 
19319f55f5f5SRafal Jaworowski 		ip = (struct ip *)(m0->m_data + ehlen);
19329f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_IP_HDR_SIZE(ip->ip_hl);
19339f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_NOT_FRAGMENT;
19349f55f5f5SRafal Jaworowski 	}
19359f55f5f5SRafal Jaworowski 
19369f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_IP)
19379f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_IP_CSUM;
19389f55f5f5SRafal Jaworowski 
19399f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_TCP)
19409f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_L4_CSUM;
19419f55f5f5SRafal Jaworowski 
19429f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_UDP)
19439f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_L4_CSUM | MGE_TX_UDP;
19449f55f5f5SRafal Jaworowski 
19459f55f5f5SRafal Jaworowski 	dw->mge_desc->cmd_status |= cmd_status;
19469f55f5f5SRafal Jaworowski }
19479f55f5f5SRafal Jaworowski 
19489f55f5f5SRafal Jaworowski static void
19499f55f5f5SRafal Jaworowski mge_intrs_ctrl(struct mge_softc *sc, int enable)
19509f55f5f5SRafal Jaworowski {
19519f55f5f5SRafal Jaworowski 
19529f55f5f5SRafal Jaworowski 	if (enable) {
19539f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK , MGE_PORT_INT_RXQ0 |
19549f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXTEND | MGE_PORT_INT_RXERRQ0);
19559f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT , MGE_PORT_INT_EXT_TXERR0 |
19569f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXT_RXOR | MGE_PORT_INT_EXT_TXUR |
19579f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXT_TXBUF0);
19589f55f5f5SRafal Jaworowski 	} else {
19599f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_INT_CAUSE, 0x0);
19609f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_INT_MASK, 0x0);
19619f55f5f5SRafal Jaworowski 
19629f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE, 0x0);
19639f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, 0x0);
19649f55f5f5SRafal Jaworowski 
19659f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK, 0x0);
19669f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT, 0x0);
19679f55f5f5SRafal Jaworowski 	}
19689f55f5f5SRafal Jaworowski }
19699f55f5f5SRafal Jaworowski 
19709f55f5f5SRafal Jaworowski static uint8_t
19719f55f5f5SRafal Jaworowski mge_crc8(uint8_t *data, int size)
19729f55f5f5SRafal Jaworowski {
19739f55f5f5SRafal Jaworowski 	uint8_t crc = 0;
19749f55f5f5SRafal Jaworowski 	static const uint8_t ct[256] = {
19759f55f5f5SRafal Jaworowski 		0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
19769f55f5f5SRafal Jaworowski 		0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
19779f55f5f5SRafal Jaworowski 		0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
19789f55f5f5SRafal Jaworowski 		0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
19799f55f5f5SRafal Jaworowski 		0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
19809f55f5f5SRafal Jaworowski 		0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
19819f55f5f5SRafal Jaworowski 		0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
19829f55f5f5SRafal Jaworowski 		0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
19839f55f5f5SRafal Jaworowski 		0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
19849f55f5f5SRafal Jaworowski 		0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
19859f55f5f5SRafal Jaworowski 		0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
19869f55f5f5SRafal Jaworowski 		0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
19879f55f5f5SRafal Jaworowski 		0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
19889f55f5f5SRafal Jaworowski 		0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
19899f55f5f5SRafal Jaworowski 		0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
19909f55f5f5SRafal Jaworowski 		0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
19919f55f5f5SRafal Jaworowski 		0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
19929f55f5f5SRafal Jaworowski 		0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
19939f55f5f5SRafal Jaworowski 		0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
19949f55f5f5SRafal Jaworowski 		0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
19959f55f5f5SRafal Jaworowski 		0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
19969f55f5f5SRafal Jaworowski 		0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
19979f55f5f5SRafal Jaworowski 		0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
19989f55f5f5SRafal Jaworowski 		0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
19999f55f5f5SRafal Jaworowski 		0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
20009f55f5f5SRafal Jaworowski 		0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
20019f55f5f5SRafal Jaworowski 		0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
20029f55f5f5SRafal Jaworowski 		0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
20039f55f5f5SRafal Jaworowski 		0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
20049f55f5f5SRafal Jaworowski 		0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
20059f55f5f5SRafal Jaworowski 		0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
20069f55f5f5SRafal Jaworowski 		0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
20079f55f5f5SRafal Jaworowski 	};
20089f55f5f5SRafal Jaworowski 
20099f55f5f5SRafal Jaworowski 	while(size--)
20109f55f5f5SRafal Jaworowski 		crc = ct[crc ^ *(data++)];
20119f55f5f5SRafal Jaworowski 
20129f55f5f5SRafal Jaworowski 	return(crc);
20139f55f5f5SRafal Jaworowski }
20149f55f5f5SRafal Jaworowski 
201553dc8c23SGleb Smirnoff struct mge_hash_maddr_ctx {
201653dc8c23SGleb Smirnoff 	uint32_t smt[MGE_MCAST_REG_NUMBER];
201753dc8c23SGleb Smirnoff 	uint32_t omt[MGE_MCAST_REG_NUMBER];
201853dc8c23SGleb Smirnoff };
201953dc8c23SGleb Smirnoff 
202053dc8c23SGleb Smirnoff static u_int
202153dc8c23SGleb Smirnoff mge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
202253dc8c23SGleb Smirnoff {
202353dc8c23SGleb Smirnoff 	static const uint8_t special[5] = { 0x01, 0x00, 0x5E, 0x00, 0x00 };
202453dc8c23SGleb Smirnoff 	struct mge_hash_maddr_ctx *ctx = arg;
202553dc8c23SGleb Smirnoff 	static const uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1;
202653dc8c23SGleb Smirnoff 	uint8_t *mac;
202753dc8c23SGleb Smirnoff 	int i;
202853dc8c23SGleb Smirnoff 
202953dc8c23SGleb Smirnoff 	mac = LLADDR(sdl);
203053dc8c23SGleb Smirnoff 	if (memcmp(mac, special, sizeof(special)) == 0) {
203153dc8c23SGleb Smirnoff 		i = mac[5];
203253dc8c23SGleb Smirnoff 		ctx->smt[i >> 2] |= v << ((i & 0x03) << 3);
203353dc8c23SGleb Smirnoff 	} else {
203453dc8c23SGleb Smirnoff 		i = mge_crc8(mac, ETHER_ADDR_LEN);
203553dc8c23SGleb Smirnoff 		ctx->omt[i >> 2] |= v << ((i & 0x03) << 3);
203653dc8c23SGleb Smirnoff 	}
203753dc8c23SGleb Smirnoff 	return (1);
203853dc8c23SGleb Smirnoff }
203953dc8c23SGleb Smirnoff 
20409f55f5f5SRafal Jaworowski static void
20419f55f5f5SRafal Jaworowski mge_setup_multicast(struct mge_softc *sc)
20429f55f5f5SRafal Jaworowski {
204353dc8c23SGleb Smirnoff 	struct mge_hash_maddr_ctx ctx;
204498fe10c8SJustin Hibbits 	if_t ifp = sc->ifp;
204553dc8c23SGleb Smirnoff 	static const uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1;
20469f55f5f5SRafal Jaworowski 	int i;
20479f55f5f5SRafal Jaworowski 
204898fe10c8SJustin Hibbits 	if (if_getflags(ifp) & IFF_ALLMULTI) {
20499f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++)
205053dc8c23SGleb Smirnoff 			ctx.smt[i] = ctx.omt[i] =
205153dc8c23SGleb Smirnoff 			    (v << 24) | (v << 16) | (v << 8) | v;
20529f55f5f5SRafal Jaworowski 	} else {
205353dc8c23SGleb Smirnoff 		memset(&ctx, 0, sizeof(ctx));
205453dc8c23SGleb Smirnoff 		if_foreach_llmaddr(ifp, mge_hash_maddr, &ctx);
20559f55f5f5SRafal Jaworowski 	}
20569f55f5f5SRafal Jaworowski 
20579f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
205853dc8c23SGleb Smirnoff 		MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), ctx.smt[i]);
205953dc8c23SGleb Smirnoff 		MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), ctx.omt[i]);
20609f55f5f5SRafal Jaworowski 	}
20619f55f5f5SRafal Jaworowski }
20629f55f5f5SRafal Jaworowski 
20639f55f5f5SRafal Jaworowski static void
20649f55f5f5SRafal Jaworowski mge_set_rxic(struct mge_softc *sc)
20659f55f5f5SRafal Jaworowski {
20669f55f5f5SRafal Jaworowski 	uint32_t reg;
20679f55f5f5SRafal Jaworowski 
20688e1dc58eSRafal Jaworowski 	if (sc->rx_ic_time > sc->mge_rx_ipg_max)
20698e1dc58eSRafal Jaworowski 		sc->rx_ic_time = sc->mge_rx_ipg_max;
20709f55f5f5SRafal Jaworowski 
20719f55f5f5SRafal Jaworowski 	reg = MGE_READ(sc, MGE_SDMA_CONFIG);
20728e1dc58eSRafal Jaworowski 	reg &= ~mge_rx_ipg(sc->mge_rx_ipg_max, sc->mge_ver);
20738e1dc58eSRafal Jaworowski 	reg |= mge_rx_ipg(sc->rx_ic_time, sc->mge_ver);
20749f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_SDMA_CONFIG, reg);
20759f55f5f5SRafal Jaworowski }
20769f55f5f5SRafal Jaworowski 
20779f55f5f5SRafal Jaworowski static void
20789f55f5f5SRafal Jaworowski mge_set_txic(struct mge_softc *sc)
20799f55f5f5SRafal Jaworowski {
20809f55f5f5SRafal Jaworowski 	uint32_t reg;
20819f55f5f5SRafal Jaworowski 
20828e1dc58eSRafal Jaworowski 	if (sc->tx_ic_time > sc->mge_tfut_ipg_max)
20838e1dc58eSRafal Jaworowski 		sc->tx_ic_time = sc->mge_tfut_ipg_max;
20849f55f5f5SRafal Jaworowski 
20859f55f5f5SRafal Jaworowski 	reg = MGE_READ(sc, MGE_TX_FIFO_URGENT_TRSH);
20868e1dc58eSRafal Jaworowski 	reg &= ~mge_tfut_ipg(sc->mge_tfut_ipg_max, sc->mge_ver);
20878e1dc58eSRafal Jaworowski 	reg |= mge_tfut_ipg(sc->tx_ic_time, sc->mge_ver);
20889f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, reg);
20899f55f5f5SRafal Jaworowski }
20909f55f5f5SRafal Jaworowski 
20919f55f5f5SRafal Jaworowski static int
20929f55f5f5SRafal Jaworowski mge_sysctl_ic(SYSCTL_HANDLER_ARGS)
20939f55f5f5SRafal Jaworowski {
20949f55f5f5SRafal Jaworowski 	struct mge_softc *sc = (struct mge_softc *)arg1;
20958e1dc58eSRafal Jaworowski 	uint32_t time;
20969f55f5f5SRafal Jaworowski 	int error;
20979f55f5f5SRafal Jaworowski 
20988e1dc58eSRafal Jaworowski 	time = (arg2 == MGE_IC_RX) ? sc->rx_ic_time : sc->tx_ic_time;
20999f55f5f5SRafal Jaworowski 	error = sysctl_handle_int(oidp, &time, 0, req);
21009f55f5f5SRafal Jaworowski 	if (error != 0)
21019f55f5f5SRafal Jaworowski 		return(error);
21029f55f5f5SRafal Jaworowski 
21039f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
21049f55f5f5SRafal Jaworowski 	if (arg2 == MGE_IC_RX) {
21059f55f5f5SRafal Jaworowski 		sc->rx_ic_time = time;
21069f55f5f5SRafal Jaworowski 		mge_set_rxic(sc);
21079f55f5f5SRafal Jaworowski 	} else {
21089f55f5f5SRafal Jaworowski 		sc->tx_ic_time = time;
21099f55f5f5SRafal Jaworowski 		mge_set_txic(sc);
21109f55f5f5SRafal Jaworowski 	}
21119f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
21129f55f5f5SRafal Jaworowski 
21139f55f5f5SRafal Jaworowski 	return(0);
21149f55f5f5SRafal Jaworowski }
21159f55f5f5SRafal Jaworowski 
21169f55f5f5SRafal Jaworowski static void
21179f55f5f5SRafal Jaworowski mge_add_sysctls(struct mge_softc *sc)
21189f55f5f5SRafal Jaworowski {
21199f55f5f5SRafal Jaworowski 	struct sysctl_ctx_list *ctx;
21209f55f5f5SRafal Jaworowski 	struct sysctl_oid_list *children;
21219f55f5f5SRafal Jaworowski 	struct sysctl_oid *tree;
21229f55f5f5SRafal Jaworowski 
21239f55f5f5SRafal Jaworowski 	ctx = device_get_sysctl_ctx(sc->dev);
21249f55f5f5SRafal Jaworowski 	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
21259f55f5f5SRafal Jaworowski 	tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "int_coal",
21267029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "MGE Interrupts coalescing");
21279f55f5f5SRafal Jaworowski 	children = SYSCTL_CHILDREN(tree);
21289f55f5f5SRafal Jaworowski 
21299f55f5f5SRafal Jaworowski 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_time",
21306b2ff27cSAlexander Motin 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, MGE_IC_RX,
21317029da5cSPawel Biernacki 	    mge_sysctl_ic, "I", "IC RX time threshold");
21329f55f5f5SRafal Jaworowski 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_time",
21336b2ff27cSAlexander Motin 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, MGE_IC_TX,
21347029da5cSPawel Biernacki 	    mge_sysctl_ic, "I", "IC TX time threshold");
21359f55f5f5SRafal Jaworowski }
21363c71b84fSZbigniew Bodek 
21373c71b84fSZbigniew Bodek static int
21383c71b84fSZbigniew Bodek mge_mdio_writereg(device_t dev, int phy, int reg, int value)
21393c71b84fSZbigniew Bodek {
21403c71b84fSZbigniew Bodek 
21413c71b84fSZbigniew Bodek 	mv_write_ge_smi(dev, phy, reg, value);
21423c71b84fSZbigniew Bodek 
21433c71b84fSZbigniew Bodek 	return (0);
21443c71b84fSZbigniew Bodek }
21453c71b84fSZbigniew Bodek 
21463c71b84fSZbigniew Bodek 
21473c71b84fSZbigniew Bodek static int
21483c71b84fSZbigniew Bodek mge_mdio_readreg(device_t dev, int phy, int reg)
21493c71b84fSZbigniew Bodek {
21503c71b84fSZbigniew Bodek 	int ret;
21513c71b84fSZbigniew Bodek 
21523c71b84fSZbigniew Bodek 	ret = mv_read_ge_smi(dev, phy, reg);
21533c71b84fSZbigniew Bodek 
21543c71b84fSZbigniew Bodek 	return (ret);
21553c71b84fSZbigniew Bodek }
2156