xref: /freebsd/sys/dev/mge/if_mge.c (revision 71e8eac4fd89dedbcb4130379add151d3ed942fa)
19f55f5f5SRafal Jaworowski /*-
29f55f5f5SRafal Jaworowski  * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
33c71b84fSZbigniew Bodek  * Copyright (C) 2009-2015 Semihalf
43c71b84fSZbigniew Bodek  * Copyright (C) 2015 Stormshield
59f55f5f5SRafal Jaworowski  * All rights reserved.
69f55f5f5SRafal Jaworowski  *
79f55f5f5SRafal Jaworowski  * Developed by Semihalf.
89f55f5f5SRafal Jaworowski  *
99f55f5f5SRafal Jaworowski  * Redistribution and use in source and binary forms, with or without
109f55f5f5SRafal Jaworowski  * modification, are permitted provided that the following conditions
119f55f5f5SRafal Jaworowski  * are met:
129f55f5f5SRafal Jaworowski  * 1. Redistributions of source code must retain the above copyright
139f55f5f5SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer.
149f55f5f5SRafal Jaworowski  * 2. Redistributions in binary form must reproduce the above copyright
159f55f5f5SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer in the
169f55f5f5SRafal Jaworowski  *    documentation and/or other materials provided with the distribution.
179f55f5f5SRafal Jaworowski  * 3. Neither the name of MARVELL nor the names of contributors
189f55f5f5SRafal Jaworowski  *    may be used to endorse or promote products derived from this software
199f55f5f5SRafal Jaworowski  *    without specific prior written permission.
209f55f5f5SRafal Jaworowski  *
219f55f5f5SRafal Jaworowski  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
229f55f5f5SRafal Jaworowski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
239f55f5f5SRafal Jaworowski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
249f55f5f5SRafal Jaworowski  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
259f55f5f5SRafal Jaworowski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
269f55f5f5SRafal Jaworowski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
279f55f5f5SRafal Jaworowski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
289f55f5f5SRafal Jaworowski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
299f55f5f5SRafal Jaworowski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
309f55f5f5SRafal Jaworowski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
319f55f5f5SRafal Jaworowski  * SUCH DAMAGE.
329f55f5f5SRafal Jaworowski  */
339f55f5f5SRafal Jaworowski 
349f55f5f5SRafal Jaworowski #ifdef HAVE_KERNEL_OPTION_HEADERS
359f55f5f5SRafal Jaworowski #include "opt_device_polling.h"
369f55f5f5SRafal Jaworowski #endif
379f55f5f5SRafal Jaworowski 
389f55f5f5SRafal Jaworowski #include <sys/cdefs.h>
399f55f5f5SRafal Jaworowski __FBSDID("$FreeBSD$");
409f55f5f5SRafal Jaworowski 
419f55f5f5SRafal Jaworowski #include <sys/param.h>
429f55f5f5SRafal Jaworowski #include <sys/systm.h>
439f55f5f5SRafal Jaworowski #include <sys/endian.h>
449f55f5f5SRafal Jaworowski #include <sys/mbuf.h>
459f55f5f5SRafal Jaworowski #include <sys/lock.h>
469f55f5f5SRafal Jaworowski #include <sys/mutex.h>
479f55f5f5SRafal Jaworowski #include <sys/kernel.h>
489f55f5f5SRafal Jaworowski #include <sys/module.h>
499f55f5f5SRafal Jaworowski #include <sys/socket.h>
509f55f5f5SRafal Jaworowski #include <sys/sysctl.h>
519f55f5f5SRafal Jaworowski 
529f55f5f5SRafal Jaworowski #include <net/ethernet.h>
539f55f5f5SRafal Jaworowski #include <net/bpf.h>
549f55f5f5SRafal Jaworowski #include <net/if.h>
559f55f5f5SRafal Jaworowski #include <net/if_arp.h>
569f55f5f5SRafal Jaworowski #include <net/if_dl.h>
579f55f5f5SRafal Jaworowski #include <net/if_media.h>
589f55f5f5SRafal Jaworowski #include <net/if_types.h>
599f55f5f5SRafal Jaworowski #include <net/if_vlan_var.h>
609f55f5f5SRafal Jaworowski 
619f55f5f5SRafal Jaworowski #include <netinet/in_systm.h>
629f55f5f5SRafal Jaworowski #include <netinet/in.h>
639f55f5f5SRafal Jaworowski #include <netinet/ip.h>
649f55f5f5SRafal Jaworowski 
659f55f5f5SRafal Jaworowski #include <sys/sockio.h>
669f55f5f5SRafal Jaworowski #include <sys/bus.h>
679f55f5f5SRafal Jaworowski #include <machine/bus.h>
689f55f5f5SRafal Jaworowski #include <sys/rman.h>
699f55f5f5SRafal Jaworowski #include <machine/resource.h>
709f55f5f5SRafal Jaworowski 
719f55f5f5SRafal Jaworowski #include <dev/mii/mii.h>
729f55f5f5SRafal Jaworowski #include <dev/mii/miivar.h>
739f55f5f5SRafal Jaworowski 
74db5ef4fcSRafal Jaworowski #include <dev/fdt/fdt_common.h>
75db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus.h>
76db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h>
77*71e8eac4SAdrian Chadd #include <dev/mdio/mdio.h>
789f55f5f5SRafal Jaworowski 
799f55f5f5SRafal Jaworowski #include <dev/mge/if_mgevar.h>
809f55f5f5SRafal Jaworowski #include <arm/mv/mvreg.h>
818e1dc58eSRafal Jaworowski #include <arm/mv/mvvar.h>
829f55f5f5SRafal Jaworowski 
839f55f5f5SRafal Jaworowski #include "miibus_if.h"
843c71b84fSZbigniew Bodek #include "mdio_if.h"
853c71b84fSZbigniew Bodek 
863c71b84fSZbigniew Bodek #define	MGE_DELAY(x)	pause("SMI access sleep", (x) / tick_sbt)
879f55f5f5SRafal Jaworowski 
889f55f5f5SRafal Jaworowski static int mge_probe(device_t dev);
899f55f5f5SRafal Jaworowski static int mge_attach(device_t dev);
909f55f5f5SRafal Jaworowski static int mge_detach(device_t dev);
919f55f5f5SRafal Jaworowski static int mge_shutdown(device_t dev);
929f55f5f5SRafal Jaworowski static int mge_suspend(device_t dev);
939f55f5f5SRafal Jaworowski static int mge_resume(device_t dev);
949f55f5f5SRafal Jaworowski 
959f55f5f5SRafal Jaworowski static int mge_miibus_readreg(device_t dev, int phy, int reg);
968e45f0b7SAndriy Gapon static int mge_miibus_writereg(device_t dev, int phy, int reg, int value);
979f55f5f5SRafal Jaworowski 
983c71b84fSZbigniew Bodek static int mge_mdio_readreg(device_t dev, int phy, int reg);
993c71b84fSZbigniew Bodek static int mge_mdio_writereg(device_t dev, int phy, int reg, int value);
1003c71b84fSZbigniew Bodek 
1019f55f5f5SRafal Jaworowski static int mge_ifmedia_upd(struct ifnet *ifp);
1029f55f5f5SRafal Jaworowski static void mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
1039f55f5f5SRafal Jaworowski 
1049f55f5f5SRafal Jaworowski static void mge_init(void *arg);
1059f55f5f5SRafal Jaworowski static void mge_init_locked(void *arg);
1069f55f5f5SRafal Jaworowski static void mge_start(struct ifnet *ifp);
1079f55f5f5SRafal Jaworowski static void mge_start_locked(struct ifnet *ifp);
1089f55f5f5SRafal Jaworowski static void mge_watchdog(struct mge_softc *sc);
1099f55f5f5SRafal Jaworowski static int mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
1109f55f5f5SRafal Jaworowski 
1118e1dc58eSRafal Jaworowski static uint32_t mge_tfut_ipg(uint32_t val, int ver);
1128e1dc58eSRafal Jaworowski static uint32_t mge_rx_ipg(uint32_t val, int ver);
1138e1dc58eSRafal Jaworowski static void mge_ver_params(struct mge_softc *sc);
1148e1dc58eSRafal Jaworowski 
1159f55f5f5SRafal Jaworowski static void mge_intrs_ctrl(struct mge_softc *sc, int enable);
11675f1438bSOleksandr Tymoshenko static void mge_intr_rxtx(void *arg);
1179f55f5f5SRafal Jaworowski static void mge_intr_rx(void *arg);
11875f1438bSOleksandr Tymoshenko static void mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause,
11975f1438bSOleksandr Tymoshenko     uint32_t int_cause_ext);
1201abcdbd1SAttilio Rao static int mge_intr_rx_locked(struct mge_softc *sc, int count);
1219f55f5f5SRafal Jaworowski static void mge_intr_tx(void *arg);
1229f55f5f5SRafal Jaworowski static void mge_intr_tx_locked(struct mge_softc *sc);
1239f55f5f5SRafal Jaworowski static void mge_intr_misc(void *arg);
1249f55f5f5SRafal Jaworowski static void mge_intr_sum(void *arg);
1259f55f5f5SRafal Jaworowski static void mge_intr_err(void *arg);
1269f55f5f5SRafal Jaworowski static void mge_stop(struct mge_softc *sc);
1279f55f5f5SRafal Jaworowski static void mge_tick(void *msc);
1289f55f5f5SRafal Jaworowski static uint32_t mge_set_port_serial_control(uint32_t media);
1299f55f5f5SRafal Jaworowski static void mge_get_mac_address(struct mge_softc *sc, uint8_t *addr);
1309f55f5f5SRafal Jaworowski static void mge_set_mac_address(struct mge_softc *sc);
1319f55f5f5SRafal Jaworowski static void mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte,
1329f55f5f5SRafal Jaworowski     uint8_t queue);
1339f55f5f5SRafal Jaworowski static void mge_set_prom_mode(struct mge_softc *sc, uint8_t queue);
1349f55f5f5SRafal Jaworowski static int mge_allocate_dma(struct mge_softc *sc);
1359f55f5f5SRafal Jaworowski static int mge_alloc_desc_dma(struct mge_softc *sc,
1364ac30cc1SZbigniew Bodek     struct mge_desc_wrapper* desc_tab, uint32_t size,
1374ac30cc1SZbigniew Bodek     bus_dma_tag_t *buffer_tag);
1389f55f5f5SRafal Jaworowski static int mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map,
1399f55f5f5SRafal Jaworowski     struct mbuf **mbufp, bus_addr_t *paddr);
1404ac30cc1SZbigniew Bodek static void mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg,
1414ac30cc1SZbigniew Bodek     int error);
1429f55f5f5SRafal Jaworowski static void mge_free_dma(struct mge_softc *sc);
1434ac30cc1SZbigniew Bodek static void mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab,
1444ac30cc1SZbigniew Bodek     uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs);
1459f55f5f5SRafal Jaworowski static void mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame,
1469f55f5f5SRafal Jaworowski     uint32_t status, uint16_t bufsize);
1479f55f5f5SRafal Jaworowski static void mge_offload_setup_descriptor(struct mge_softc *sc,
1489f55f5f5SRafal Jaworowski     struct mge_desc_wrapper *dw);
1499f55f5f5SRafal Jaworowski static uint8_t mge_crc8(uint8_t *data, int size);
1509f55f5f5SRafal Jaworowski static void mge_setup_multicast(struct mge_softc *sc);
1519f55f5f5SRafal Jaworowski static void mge_set_rxic(struct mge_softc *sc);
1529f55f5f5SRafal Jaworowski static void mge_set_txic(struct mge_softc *sc);
1539f55f5f5SRafal Jaworowski static void mge_add_sysctls(struct mge_softc *sc);
1549f55f5f5SRafal Jaworowski static int mge_sysctl_ic(SYSCTL_HANDLER_ARGS);
1559f55f5f5SRafal Jaworowski 
1569f55f5f5SRafal Jaworowski static device_method_t mge_methods[] = {
1579f55f5f5SRafal Jaworowski 	/* Device interface */
1589f55f5f5SRafal Jaworowski 	DEVMETHOD(device_probe,		mge_probe),
1599f55f5f5SRafal Jaworowski 	DEVMETHOD(device_attach,	mge_attach),
1609f55f5f5SRafal Jaworowski 	DEVMETHOD(device_detach,	mge_detach),
1619f55f5f5SRafal Jaworowski 	DEVMETHOD(device_shutdown,	mge_shutdown),
1629f55f5f5SRafal Jaworowski 	DEVMETHOD(device_suspend,	mge_suspend),
1639f55f5f5SRafal Jaworowski 	DEVMETHOD(device_resume,	mge_resume),
1649f55f5f5SRafal Jaworowski 	/* MII interface */
1659f55f5f5SRafal Jaworowski 	DEVMETHOD(miibus_readreg,	mge_miibus_readreg),
1669f55f5f5SRafal Jaworowski 	DEVMETHOD(miibus_writereg,	mge_miibus_writereg),
1673c71b84fSZbigniew Bodek 	/* MDIO interface */
1683c71b84fSZbigniew Bodek 	DEVMETHOD(mdio_readreg,		mge_mdio_readreg),
1693c71b84fSZbigniew Bodek 	DEVMETHOD(mdio_writereg,	mge_mdio_writereg),
1709f55f5f5SRafal Jaworowski 	{ 0, 0 }
1719f55f5f5SRafal Jaworowski };
1729f55f5f5SRafal Jaworowski 
1733c71b84fSZbigniew Bodek DEFINE_CLASS_0(mge, mge_driver, mge_methods, sizeof(struct mge_softc));
1749f55f5f5SRafal Jaworowski 
1759f55f5f5SRafal Jaworowski static devclass_t mge_devclass;
1763c71b84fSZbigniew Bodek static int switch_attached = 0;
1779f55f5f5SRafal Jaworowski 
178db5ef4fcSRafal Jaworowski DRIVER_MODULE(mge, simplebus, mge_driver, mge_devclass, 0, 0);
1799f55f5f5SRafal Jaworowski DRIVER_MODULE(miibus, mge, miibus_driver, miibus_devclass, 0, 0);
1803c71b84fSZbigniew Bodek DRIVER_MODULE(mdio, mge, mdio_driver, mdio_devclass, 0, 0);
1819f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, ether, 1, 1, 1);
1829f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, miibus, 1, 1, 1);
1833c71b84fSZbigniew Bodek MODULE_DEPEND(mge, mdio, 1, 1, 1);
1849f55f5f5SRafal Jaworowski 
1859f55f5f5SRafal Jaworowski static struct resource_spec res_spec[] = {
1869f55f5f5SRafal Jaworowski 	{ SYS_RES_MEMORY, 0, RF_ACTIVE },
1879f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
1889f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE },
1899f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE },
1909f55f5f5SRafal Jaworowski 	{ -1, 0 }
1919f55f5f5SRafal Jaworowski };
1929f55f5f5SRafal Jaworowski 
1939f55f5f5SRafal Jaworowski static struct {
1949f55f5f5SRafal Jaworowski 	driver_intr_t *handler;
1959f55f5f5SRafal Jaworowski 	char * description;
19675f1438bSOleksandr Tymoshenko } mge_intrs[MGE_INTR_COUNT + 1] = {
19775f1438bSOleksandr Tymoshenko 	{ mge_intr_rxtx,"GbE aggregated interrupt" },
1989f55f5f5SRafal Jaworowski 	{ mge_intr_rx,	"GbE receive interrupt" },
1999f55f5f5SRafal Jaworowski 	{ mge_intr_tx,	"GbE transmit interrupt" },
2009f55f5f5SRafal Jaworowski 	{ mge_intr_misc,"GbE misc interrupt" },
2019f55f5f5SRafal Jaworowski 	{ mge_intr_sum,	"GbE summary interrupt" },
2029f55f5f5SRafal Jaworowski 	{ mge_intr_err,	"GbE error interrupt" },
2039f55f5f5SRafal Jaworowski };
2049f55f5f5SRafal Jaworowski 
2053c71b84fSZbigniew Bodek /* SMI access interlock */
2063c71b84fSZbigniew Bodek static struct sx sx_smi;
2073c71b84fSZbigniew Bodek 
2083c71b84fSZbigniew Bodek static uint32_t
2093c71b84fSZbigniew Bodek mv_read_ge_smi(device_t dev, int phy, int reg)
2103c71b84fSZbigniew Bodek {
2113c71b84fSZbigniew Bodek 	uint32_t timeout;
2123c71b84fSZbigniew Bodek 	uint32_t ret;
2133c71b84fSZbigniew Bodek 	struct mge_softc *sc;
2143c71b84fSZbigniew Bodek 
2153c71b84fSZbigniew Bodek 	sc = device_get_softc(dev);
2163c71b84fSZbigniew Bodek 	KASSERT(sc != NULL, ("NULL softc ptr!"));
2173c71b84fSZbigniew Bodek 	timeout = MGE_SMI_WRITE_RETRIES;
2183c71b84fSZbigniew Bodek 
2193c71b84fSZbigniew Bodek 	MGE_SMI_LOCK();
2203c71b84fSZbigniew Bodek 	while (--timeout &&
2213c71b84fSZbigniew Bodek 	    (MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_BUSY))
2223c71b84fSZbigniew Bodek 		MGE_DELAY(MGE_SMI_WRITE_DELAY);
2233c71b84fSZbigniew Bodek 
2243c71b84fSZbigniew Bodek 	if (timeout == 0) {
2253c71b84fSZbigniew Bodek 		device_printf(dev, "SMI write timeout.\n");
2263c71b84fSZbigniew Bodek 		ret = ~0U;
2273c71b84fSZbigniew Bodek 		goto out;
2283c71b84fSZbigniew Bodek 	}
2293c71b84fSZbigniew Bodek 
2303c71b84fSZbigniew Bodek 	MGE_WRITE(sc, MGE_REG_SMI, MGE_SMI_MASK &
2313c71b84fSZbigniew Bodek 	    (MGE_SMI_READ | (reg << 21) | (phy << 16)));
2323c71b84fSZbigniew Bodek 
2333c71b84fSZbigniew Bodek 	/* Wait till finished. */
2343c71b84fSZbigniew Bodek 	timeout = MGE_SMI_WRITE_RETRIES;
2353c71b84fSZbigniew Bodek 	while (--timeout &&
2363c71b84fSZbigniew Bodek 	    !((MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_READVALID)))
2373c71b84fSZbigniew Bodek 		MGE_DELAY(MGE_SMI_WRITE_DELAY);
2383c71b84fSZbigniew Bodek 
2393c71b84fSZbigniew Bodek 	if (timeout == 0) {
2403c71b84fSZbigniew Bodek 		device_printf(dev, "SMI write validation timeout.\n");
2413c71b84fSZbigniew Bodek 		ret = ~0U;
2423c71b84fSZbigniew Bodek 		goto out;
2433c71b84fSZbigniew Bodek 	}
2443c71b84fSZbigniew Bodek 
2453c71b84fSZbigniew Bodek 	/* Wait for the data to update in the SMI register */
2463c71b84fSZbigniew Bodek 	MGE_DELAY(MGE_SMI_DELAY);
2473c71b84fSZbigniew Bodek 	ret = MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_DATA_MASK;
2483c71b84fSZbigniew Bodek 
2493c71b84fSZbigniew Bodek out:
2503c71b84fSZbigniew Bodek 	MGE_SMI_UNLOCK();
2513c71b84fSZbigniew Bodek 	return (ret);
2523c71b84fSZbigniew Bodek 
2533c71b84fSZbigniew Bodek }
2543c71b84fSZbigniew Bodek 
2553c71b84fSZbigniew Bodek static void
2563c71b84fSZbigniew Bodek mv_write_ge_smi(device_t dev, int phy, int reg, uint32_t value)
2573c71b84fSZbigniew Bodek {
2583c71b84fSZbigniew Bodek 	uint32_t timeout;
2593c71b84fSZbigniew Bodek 	struct mge_softc *sc;
2603c71b84fSZbigniew Bodek 
2613c71b84fSZbigniew Bodek 	sc = device_get_softc(dev);
2623c71b84fSZbigniew Bodek 	KASSERT(sc != NULL, ("NULL softc ptr!"));
2633c71b84fSZbigniew Bodek 
2643c71b84fSZbigniew Bodek 	MGE_SMI_LOCK();
2653c71b84fSZbigniew Bodek 	timeout = MGE_SMI_READ_RETRIES;
2663c71b84fSZbigniew Bodek 	while (--timeout &&
2673c71b84fSZbigniew Bodek 	    (MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_BUSY))
2683c71b84fSZbigniew Bodek 		MGE_DELAY(MGE_SMI_READ_DELAY);
2693c71b84fSZbigniew Bodek 
2703c71b84fSZbigniew Bodek 	if (timeout == 0) {
2713c71b84fSZbigniew Bodek 		device_printf(dev, "SMI read timeout.\n");
2723c71b84fSZbigniew Bodek 		goto out;
2733c71b84fSZbigniew Bodek 	}
2743c71b84fSZbigniew Bodek 
2753c71b84fSZbigniew Bodek 	MGE_WRITE(sc, MGE_REG_SMI, MGE_SMI_MASK &
2763c71b84fSZbigniew Bodek 	    (MGE_SMI_WRITE | (reg << 21) | (phy << 16) |
2773c71b84fSZbigniew Bodek 	    (value & MGE_SMI_DATA_MASK)));
2783c71b84fSZbigniew Bodek 
2793c71b84fSZbigniew Bodek out:
2803c71b84fSZbigniew Bodek 	MGE_SMI_UNLOCK();
2813c71b84fSZbigniew Bodek }
2823c71b84fSZbigniew Bodek 
2833c71b84fSZbigniew Bodek static int
2843c71b84fSZbigniew Bodek mv_read_ext_phy(device_t dev, int phy, int reg)
2853c71b84fSZbigniew Bodek {
2863c71b84fSZbigniew Bodek 	uint32_t retries;
2873c71b84fSZbigniew Bodek 	struct mge_softc *sc;
2883c71b84fSZbigniew Bodek 	uint32_t ret;
2893c71b84fSZbigniew Bodek 
2903c71b84fSZbigniew Bodek 	sc = device_get_softc(dev);
2913c71b84fSZbigniew Bodek 
2923c71b84fSZbigniew Bodek 	MGE_SMI_LOCK();
2933c71b84fSZbigniew Bodek 	MGE_WRITE(sc->phy_sc, MGE_REG_SMI, MGE_SMI_MASK &
2943c71b84fSZbigniew Bodek 	    (MGE_SMI_READ | (reg << 21) | (phy << 16)));
2953c71b84fSZbigniew Bodek 
2963c71b84fSZbigniew Bodek 	retries = MGE_SMI_READ_RETRIES;
2973c71b84fSZbigniew Bodek 	while (--retries &&
2983c71b84fSZbigniew Bodek 	    !(MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_READVALID))
2993c71b84fSZbigniew Bodek 		DELAY(MGE_SMI_READ_DELAY);
3003c71b84fSZbigniew Bodek 
3013c71b84fSZbigniew Bodek 	if (retries == 0)
3023c71b84fSZbigniew Bodek 		device_printf(dev, "Timeout while reading from PHY\n");
3033c71b84fSZbigniew Bodek 
3043c71b84fSZbigniew Bodek 	ret = MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_DATA_MASK;
3053c71b84fSZbigniew Bodek 	MGE_SMI_UNLOCK();
3063c71b84fSZbigniew Bodek 
3073c71b84fSZbigniew Bodek 	return (ret);
3083c71b84fSZbigniew Bodek }
3093c71b84fSZbigniew Bodek 
3103c71b84fSZbigniew Bodek static void
3113c71b84fSZbigniew Bodek mv_write_ext_phy(device_t dev, int phy, int reg, int value)
3123c71b84fSZbigniew Bodek {
3133c71b84fSZbigniew Bodek 	uint32_t retries;
3143c71b84fSZbigniew Bodek 	struct mge_softc *sc;
3153c71b84fSZbigniew Bodek 
3163c71b84fSZbigniew Bodek 	sc = device_get_softc(dev);
3173c71b84fSZbigniew Bodek 
3183c71b84fSZbigniew Bodek 	MGE_SMI_LOCK();
3193c71b84fSZbigniew Bodek 	MGE_WRITE(sc->phy_sc, MGE_REG_SMI, MGE_SMI_MASK &
3203c71b84fSZbigniew Bodek 	    (MGE_SMI_WRITE | (reg << 21) | (phy << 16) |
3213c71b84fSZbigniew Bodek 	    (value & MGE_SMI_DATA_MASK)));
3223c71b84fSZbigniew Bodek 
3233c71b84fSZbigniew Bodek 	retries = MGE_SMI_WRITE_RETRIES;
3243c71b84fSZbigniew Bodek 	while (--retries && MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_BUSY)
3253c71b84fSZbigniew Bodek 		DELAY(MGE_SMI_WRITE_DELAY);
3263c71b84fSZbigniew Bodek 
3273c71b84fSZbigniew Bodek 	if (retries == 0)
3283c71b84fSZbigniew Bodek 		device_printf(dev, "Timeout while writing to PHY\n");
3293c71b84fSZbigniew Bodek 	MGE_SMI_UNLOCK();
3303c71b84fSZbigniew Bodek }
3313c71b84fSZbigniew Bodek 
3329f55f5f5SRafal Jaworowski static void
3339f55f5f5SRafal Jaworowski mge_get_mac_address(struct mge_softc *sc, uint8_t *addr)
3349f55f5f5SRafal Jaworowski {
3359f55f5f5SRafal Jaworowski 	uint32_t mac_l, mac_h;
336db5ef4fcSRafal Jaworowski 	uint8_t lmac[6];
337db5ef4fcSRafal Jaworowski 	int i, valid;
3389f55f5f5SRafal Jaworowski 
339db5ef4fcSRafal Jaworowski 	/*
340db5ef4fcSRafal Jaworowski 	 * Retrieve hw address from the device tree.
341db5ef4fcSRafal Jaworowski 	 */
342db5ef4fcSRafal Jaworowski 	i = OF_getprop(sc->node, "local-mac-address", (void *)lmac, 6);
343db5ef4fcSRafal Jaworowski 	if (i == 6) {
344db5ef4fcSRafal Jaworowski 		valid = 0;
345db5ef4fcSRafal Jaworowski 		for (i = 0; i < 6; i++)
346db5ef4fcSRafal Jaworowski 			if (lmac[i] != 0) {
347db5ef4fcSRafal Jaworowski 				valid = 1;
348db5ef4fcSRafal Jaworowski 				break;
349db5ef4fcSRafal Jaworowski 			}
3509f55f5f5SRafal Jaworowski 
351db5ef4fcSRafal Jaworowski 		if (valid) {
352db5ef4fcSRafal Jaworowski 			bcopy(lmac, addr, 6);
353db5ef4fcSRafal Jaworowski 			return;
354db5ef4fcSRafal Jaworowski 		}
355db5ef4fcSRafal Jaworowski 	}
356db5ef4fcSRafal Jaworowski 
357db5ef4fcSRafal Jaworowski 	/*
358db5ef4fcSRafal Jaworowski 	 * Fall back -- use the currently programmed address.
359db5ef4fcSRafal Jaworowski 	 */
3609f55f5f5SRafal Jaworowski 	mac_l = MGE_READ(sc, MGE_MAC_ADDR_L);
3619f55f5f5SRafal Jaworowski 	mac_h = MGE_READ(sc, MGE_MAC_ADDR_H);
3629f55f5f5SRafal Jaworowski 
3639f55f5f5SRafal Jaworowski 	addr[0] = (mac_h & 0xff000000) >> 24;
3649f55f5f5SRafal Jaworowski 	addr[1] = (mac_h & 0x00ff0000) >> 16;
3659f55f5f5SRafal Jaworowski 	addr[2] = (mac_h & 0x0000ff00) >> 8;
3669f55f5f5SRafal Jaworowski 	addr[3] = (mac_h & 0x000000ff);
3679f55f5f5SRafal Jaworowski 	addr[4] = (mac_l & 0x0000ff00) >> 8;
3689f55f5f5SRafal Jaworowski 	addr[5] = (mac_l & 0x000000ff);
3699f55f5f5SRafal Jaworowski }
3709f55f5f5SRafal Jaworowski 
3718e1dc58eSRafal Jaworowski static uint32_t
3728e1dc58eSRafal Jaworowski mge_tfut_ipg(uint32_t val, int ver)
3738e1dc58eSRafal Jaworowski {
3748e1dc58eSRafal Jaworowski 
3758e1dc58eSRafal Jaworowski 	switch (ver) {
3768e1dc58eSRafal Jaworowski 	case 1:
3778e1dc58eSRafal Jaworowski 		return ((val & 0x3fff) << 4);
3788e1dc58eSRafal Jaworowski 	case 2:
3798e1dc58eSRafal Jaworowski 	default:
3808e1dc58eSRafal Jaworowski 		return ((val & 0xffff) << 4);
3818e1dc58eSRafal Jaworowski 	}
3828e1dc58eSRafal Jaworowski }
3838e1dc58eSRafal Jaworowski 
3848e1dc58eSRafal Jaworowski static uint32_t
3858e1dc58eSRafal Jaworowski mge_rx_ipg(uint32_t val, int ver)
3868e1dc58eSRafal Jaworowski {
3878e1dc58eSRafal Jaworowski 
3888e1dc58eSRafal Jaworowski 	switch (ver) {
3898e1dc58eSRafal Jaworowski 	case 1:
3908e1dc58eSRafal Jaworowski 		return ((val & 0x3fff) << 8);
3918e1dc58eSRafal Jaworowski 	case 2:
3928e1dc58eSRafal Jaworowski 	default:
3938e1dc58eSRafal Jaworowski 		return (((val & 0x8000) << 10) | ((val & 0x7fff) << 7));
3948e1dc58eSRafal Jaworowski 	}
3958e1dc58eSRafal Jaworowski }
3968e1dc58eSRafal Jaworowski 
3978e1dc58eSRafal Jaworowski static void
3988e1dc58eSRafal Jaworowski mge_ver_params(struct mge_softc *sc)
3998e1dc58eSRafal Jaworowski {
4008e1dc58eSRafal Jaworowski 	uint32_t d, r;
4018e1dc58eSRafal Jaworowski 
4028e1dc58eSRafal Jaworowski 	soc_id(&d, &r);
40375f1438bSOleksandr Tymoshenko 	if (d == MV_DEV_88F6281 || d == MV_DEV_88F6781 ||
404c8953e12SHiroki Sato 	    d == MV_DEV_88F6282 ||
405c8953e12SHiroki Sato 	    d == MV_DEV_MV78100 ||
40675f1438bSOleksandr Tymoshenko 	    d == MV_DEV_MV78100_Z0 ||
40775f1438bSOleksandr Tymoshenko 	    (d & MV_DEV_FAMILY_MASK) == MV_DEV_DISCOVERY) {
4088e1dc58eSRafal Jaworowski 		sc->mge_ver = 2;
4098e1dc58eSRafal Jaworowski 		sc->mge_mtu = 0x4e8;
4108e1dc58eSRafal Jaworowski 		sc->mge_tfut_ipg_max = 0xFFFF;
4118e1dc58eSRafal Jaworowski 		sc->mge_rx_ipg_max = 0xFFFF;
4128e1dc58eSRafal Jaworowski 		sc->mge_tx_arb_cfg = 0xFC0000FF;
4138e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cfg = 0xFFFF7FFF;
4148e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cnt = 0x3FFFFFFF;
4158e1dc58eSRafal Jaworowski 	} else {
4168e1dc58eSRafal Jaworowski 		sc->mge_ver = 1;
4178e1dc58eSRafal Jaworowski 		sc->mge_mtu = 0x458;
4188e1dc58eSRafal Jaworowski 		sc->mge_tfut_ipg_max = 0x3FFF;
4198e1dc58eSRafal Jaworowski 		sc->mge_rx_ipg_max = 0x3FFF;
4208e1dc58eSRafal Jaworowski 		sc->mge_tx_arb_cfg = 0x000000FF;
4218e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cfg = 0x3FFFFFFF;
4228e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cnt = 0x3FFFFFFF;
4238e1dc58eSRafal Jaworowski 	}
42475f1438bSOleksandr Tymoshenko 	if (d == MV_DEV_88RC8180)
42575f1438bSOleksandr Tymoshenko 		sc->mge_intr_cnt = 1;
42675f1438bSOleksandr Tymoshenko 	else
42775f1438bSOleksandr Tymoshenko 		sc->mge_intr_cnt = 2;
42875f1438bSOleksandr Tymoshenko 
42975f1438bSOleksandr Tymoshenko 	if (d == MV_DEV_MV78160 || d == MV_DEV_MV78260 || d == MV_DEV_MV78460)
43075f1438bSOleksandr Tymoshenko 		sc->mge_hw_csum = 0;
43175f1438bSOleksandr Tymoshenko 	else
43275f1438bSOleksandr Tymoshenko 		sc->mge_hw_csum = 1;
4338e1dc58eSRafal Jaworowski }
4348e1dc58eSRafal Jaworowski 
4359f55f5f5SRafal Jaworowski static void
4369f55f5f5SRafal Jaworowski mge_set_mac_address(struct mge_softc *sc)
4379f55f5f5SRafal Jaworowski {
4389f55f5f5SRafal Jaworowski 	char *if_mac;
4399f55f5f5SRafal Jaworowski 	uint32_t mac_l, mac_h;
4409f55f5f5SRafal Jaworowski 
4419f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK_ASSERT(sc);
4429f55f5f5SRafal Jaworowski 
4439f55f5f5SRafal Jaworowski 	if_mac = (char *)IF_LLADDR(sc->ifp);
4449f55f5f5SRafal Jaworowski 
4459f55f5f5SRafal Jaworowski 	mac_l = (if_mac[4] << 8) | (if_mac[5]);
4469f55f5f5SRafal Jaworowski 	mac_h = (if_mac[0] << 24)| (if_mac[1] << 16) |
4479f55f5f5SRafal Jaworowski 	    (if_mac[2] << 8) | (if_mac[3] << 0);
4489f55f5f5SRafal Jaworowski 
4499f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_MAC_ADDR_L, mac_l);
4509f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_MAC_ADDR_H, mac_h);
4519f55f5f5SRafal Jaworowski 
4529f55f5f5SRafal Jaworowski 	mge_set_ucast_address(sc, if_mac[5], MGE_RX_DEFAULT_QUEUE);
4539f55f5f5SRafal Jaworowski }
4549f55f5f5SRafal Jaworowski 
4559f55f5f5SRafal Jaworowski static void
4569f55f5f5SRafal Jaworowski mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte, uint8_t queue)
4579f55f5f5SRafal Jaworowski {
4589f55f5f5SRafal Jaworowski 	uint32_t reg_idx, reg_off, reg_val, i;
4599f55f5f5SRafal Jaworowski 
4609f55f5f5SRafal Jaworowski 	last_byte &= 0xf;
4619f55f5f5SRafal Jaworowski 	reg_idx = last_byte / MGE_UCAST_REG_NUMBER;
4629f55f5f5SRafal Jaworowski 	reg_off = (last_byte % MGE_UCAST_REG_NUMBER) * 8;
4639f55f5f5SRafal Jaworowski 	reg_val = (1 | (queue << 1)) << reg_off;
4649f55f5f5SRafal Jaworowski 
4659f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_UCAST_REG_NUMBER; i++) {
4669f55f5f5SRafal Jaworowski 		if ( i == reg_idx)
4679f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val);
4689f55f5f5SRafal Jaworowski 		else
4699f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), 0);
4709f55f5f5SRafal Jaworowski 	}
4719f55f5f5SRafal Jaworowski }
4729f55f5f5SRafal Jaworowski 
4739f55f5f5SRafal Jaworowski static void
4749f55f5f5SRafal Jaworowski mge_set_prom_mode(struct mge_softc *sc, uint8_t queue)
4759f55f5f5SRafal Jaworowski {
4769f55f5f5SRafal Jaworowski 	uint32_t port_config;
4779f55f5f5SRafal Jaworowski 	uint32_t reg_val, i;
4789f55f5f5SRafal Jaworowski 
4799f55f5f5SRafal Jaworowski 	/* Enable or disable promiscuous mode as needed */
4809f55f5f5SRafal Jaworowski 	if (sc->ifp->if_flags & IFF_PROMISC) {
4819f55f5f5SRafal Jaworowski 		port_config = MGE_READ(sc, MGE_PORT_CONFIG);
4829f55f5f5SRafal Jaworowski 		port_config |= PORT_CONFIG_UPM;
4839f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_CONFIG, port_config);
4849f55f5f5SRafal Jaworowski 
4859f55f5f5SRafal Jaworowski 		reg_val = ((1 | (queue << 1)) | (1 | (queue << 1)) << 8 |
4869f55f5f5SRafal Jaworowski 		   (1 | (queue << 1)) << 16 | (1 | (queue << 1)) << 24);
4879f55f5f5SRafal Jaworowski 
4889f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
4899f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), reg_val);
4909f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), reg_val);
4919f55f5f5SRafal Jaworowski 		}
4929f55f5f5SRafal Jaworowski 
4939f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_UCAST_REG_NUMBER; i++)
4949f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val);
4959f55f5f5SRafal Jaworowski 
4969f55f5f5SRafal Jaworowski 	} else {
4979f55f5f5SRafal Jaworowski 		port_config = MGE_READ(sc, MGE_PORT_CONFIG);
4989f55f5f5SRafal Jaworowski 		port_config &= ~PORT_CONFIG_UPM;
4999f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_CONFIG, port_config);
5009f55f5f5SRafal Jaworowski 
5019f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
5029f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), 0);
5039f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), 0);
5049f55f5f5SRafal Jaworowski 		}
5059f55f5f5SRafal Jaworowski 
5069f55f5f5SRafal Jaworowski 		mge_set_mac_address(sc);
5079f55f5f5SRafal Jaworowski 	}
5089f55f5f5SRafal Jaworowski }
5099f55f5f5SRafal Jaworowski 
5109f55f5f5SRafal Jaworowski static void
5119f55f5f5SRafal Jaworowski mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
5129f55f5f5SRafal Jaworowski {
5139f55f5f5SRafal Jaworowski 	u_int32_t *paddr;
5149f55f5f5SRafal Jaworowski 
5159f55f5f5SRafal Jaworowski 	KASSERT(nseg == 1, ("wrong number of segments, should be 1"));
5169f55f5f5SRafal Jaworowski 	paddr = arg;
5179f55f5f5SRafal Jaworowski 
5189f55f5f5SRafal Jaworowski 	*paddr = segs->ds_addr;
5199f55f5f5SRafal Jaworowski }
5209f55f5f5SRafal Jaworowski 
5219f55f5f5SRafal Jaworowski static int
5229f55f5f5SRafal Jaworowski mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf **mbufp,
5239f55f5f5SRafal Jaworowski     bus_addr_t *paddr)
5249f55f5f5SRafal Jaworowski {
5259f55f5f5SRafal Jaworowski 	struct mbuf *new_mbuf;
5269f55f5f5SRafal Jaworowski 	bus_dma_segment_t seg[1];
5279f55f5f5SRafal Jaworowski 	int error;
5289f55f5f5SRafal Jaworowski 	int nsegs;
5299f55f5f5SRafal Jaworowski 
5309f55f5f5SRafal Jaworowski 	KASSERT(mbufp != NULL, ("NULL mbuf pointer!"));
5319f55f5f5SRafal Jaworowski 
532c6499eccSGleb Smirnoff 	new_mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
5339f55f5f5SRafal Jaworowski 	if (new_mbuf == NULL)
5349f55f5f5SRafal Jaworowski 		return (ENOBUFS);
5359f55f5f5SRafal Jaworowski 	new_mbuf->m_len = new_mbuf->m_pkthdr.len = new_mbuf->m_ext.ext_size;
5369f55f5f5SRafal Jaworowski 
5379f55f5f5SRafal Jaworowski 	if (*mbufp) {
5389f55f5f5SRafal Jaworowski 		bus_dmamap_sync(tag, map, BUS_DMASYNC_POSTREAD);
5399f55f5f5SRafal Jaworowski 		bus_dmamap_unload(tag, map);
5409f55f5f5SRafal Jaworowski 	}
5419f55f5f5SRafal Jaworowski 
5429f55f5f5SRafal Jaworowski 	error = bus_dmamap_load_mbuf_sg(tag, map, new_mbuf, seg, &nsegs,
5439f55f5f5SRafal Jaworowski 	    BUS_DMA_NOWAIT);
5449f55f5f5SRafal Jaworowski 	KASSERT(nsegs == 1, ("Too many segments returned!"));
5459f55f5f5SRafal Jaworowski 	if (nsegs != 1 || error)
5469f55f5f5SRafal Jaworowski 		panic("mge_new_rxbuf(): nsegs(%d), error(%d)", nsegs, error);
5479f55f5f5SRafal Jaworowski 
5489f55f5f5SRafal Jaworowski 	bus_dmamap_sync(tag, map, BUS_DMASYNC_PREREAD);
5499f55f5f5SRafal Jaworowski 
5509f55f5f5SRafal Jaworowski 	(*mbufp) = new_mbuf;
5519f55f5f5SRafal Jaworowski 	(*paddr) = seg->ds_addr;
5529f55f5f5SRafal Jaworowski 	return (0);
5539f55f5f5SRafal Jaworowski }
5549f55f5f5SRafal Jaworowski 
5559f55f5f5SRafal Jaworowski static int
5569f55f5f5SRafal Jaworowski mge_alloc_desc_dma(struct mge_softc *sc, struct mge_desc_wrapper* tab,
5579f55f5f5SRafal Jaworowski     uint32_t size, bus_dma_tag_t *buffer_tag)
5589f55f5f5SRafal Jaworowski {
5599f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
5609f55f5f5SRafal Jaworowski 	bus_addr_t desc_paddr;
5619f55f5f5SRafal Jaworowski 	int i, error;
5629f55f5f5SRafal Jaworowski 
5639f55f5f5SRafal Jaworowski 	desc_paddr = 0;
5649f55f5f5SRafal Jaworowski 	for (i = size - 1; i >= 0; i--) {
5659f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
5669f55f5f5SRafal Jaworowski 		error = bus_dmamem_alloc(sc->mge_desc_dtag,
5679f55f5f5SRafal Jaworowski 		    (void**)&(dw->mge_desc),
5689f55f5f5SRafal Jaworowski 		    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
5699f55f5f5SRafal Jaworowski 		    &(dw->desc_dmap));
5709f55f5f5SRafal Jaworowski 
5719f55f5f5SRafal Jaworowski 		if (error) {
5729f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "failed to allocate DMA memory\n");
5739f55f5f5SRafal Jaworowski 			dw->mge_desc = NULL;
5749f55f5f5SRafal Jaworowski 			return (ENXIO);
5759f55f5f5SRafal Jaworowski 		}
5769f55f5f5SRafal Jaworowski 
5779f55f5f5SRafal Jaworowski 		error = bus_dmamap_load(sc->mge_desc_dtag, dw->desc_dmap,
5789f55f5f5SRafal Jaworowski 		    dw->mge_desc, sizeof(struct mge_desc), mge_get_dma_addr,
5799f55f5f5SRafal Jaworowski 		    &(dw->mge_desc_paddr), BUS_DMA_NOWAIT);
5809f55f5f5SRafal Jaworowski 
5819f55f5f5SRafal Jaworowski 		if (error) {
5829f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "can't load descriptor\n");
5839f55f5f5SRafal Jaworowski 			bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc,
5849f55f5f5SRafal Jaworowski 			    dw->desc_dmap);
5859f55f5f5SRafal Jaworowski 			dw->mge_desc = NULL;
5869f55f5f5SRafal Jaworowski 			return (ENXIO);
5879f55f5f5SRafal Jaworowski 		}
5889f55f5f5SRafal Jaworowski 
5899f55f5f5SRafal Jaworowski 		/* Chain descriptors */
5909f55f5f5SRafal Jaworowski 		dw->mge_desc->next_desc = desc_paddr;
5919f55f5f5SRafal Jaworowski 		desc_paddr = dw->mge_desc_paddr;
5929f55f5f5SRafal Jaworowski 	}
5939f55f5f5SRafal Jaworowski 	tab[size - 1].mge_desc->next_desc = desc_paddr;
5949f55f5f5SRafal Jaworowski 
5959f55f5f5SRafal Jaworowski 	/* Allocate a busdma tag for mbufs. */
59662ce43ccSScott Long 	error = bus_dma_tag_create(bus_get_dma_tag(sc->dev),	/* parent */
59775f1438bSOleksandr Tymoshenko 	    1, 0,				/* alignment, boundary */
5989f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
5999f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR,			/* highaddr */
6009f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* filtfunc, filtfuncarg */
6019f55f5f5SRafal Jaworowski 	    MCLBYTES, 1,			/* maxsize, nsegments */
6029f55f5f5SRafal Jaworowski 	    MCLBYTES, 0,			/* maxsegsz, flags */
6039f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* lockfunc, lockfuncarg */
6049f55f5f5SRafal Jaworowski 	    buffer_tag);			/* dmat */
6059f55f5f5SRafal Jaworowski 	if (error) {
6069f55f5f5SRafal Jaworowski 		if_printf(sc->ifp, "failed to create busdma tag for mbufs\n");
6079f55f5f5SRafal Jaworowski 		return (ENXIO);
6089f55f5f5SRafal Jaworowski 	}
6099f55f5f5SRafal Jaworowski 
6109f55f5f5SRafal Jaworowski 	/* Create TX busdma maps */
6119f55f5f5SRafal Jaworowski 	for (i = 0; i < size; i++) {
6129f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
6139f55f5f5SRafal Jaworowski 		error = bus_dmamap_create(*buffer_tag, 0, &dw->buffer_dmap);
6149f55f5f5SRafal Jaworowski 		if (error) {
6159f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "failed to create map for mbuf\n");
6169f55f5f5SRafal Jaworowski 			return (ENXIO);
6179f55f5f5SRafal Jaworowski 		}
6189f55f5f5SRafal Jaworowski 
6199f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
6209f55f5f5SRafal Jaworowski 		dw->mge_desc->buffer = (bus_addr_t)NULL;
6219f55f5f5SRafal Jaworowski 	}
6229f55f5f5SRafal Jaworowski 
6239f55f5f5SRafal Jaworowski 	return (0);
6249f55f5f5SRafal Jaworowski }
6259f55f5f5SRafal Jaworowski 
6269f55f5f5SRafal Jaworowski static int
6279f55f5f5SRafal Jaworowski mge_allocate_dma(struct mge_softc *sc)
6289f55f5f5SRafal Jaworowski {
6299f55f5f5SRafal Jaworowski 	int error;
6309f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
631d6bdd318SRafal Jaworowski 	int i;
6329f55f5f5SRafal Jaworowski 
6339f55f5f5SRafal Jaworowski 	/* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
63462ce43ccSScott Long 	error = bus_dma_tag_create(bus_get_dma_tag(sc->dev),	/* parent */
6359f55f5f5SRafal Jaworowski 	    16, 0,				/* alignment, boundary */
6369f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
6379f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR,			/* highaddr */
6389f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* filtfunc, filtfuncarg */
6399f55f5f5SRafal Jaworowski 	    sizeof(struct mge_desc), 1,		/* maxsize, nsegments */
6409f55f5f5SRafal Jaworowski 	    sizeof(struct mge_desc), 0,		/* maxsegsz, flags */
6419f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* lockfunc, lockfuncarg */
6429f55f5f5SRafal Jaworowski 	    &sc->mge_desc_dtag);		/* dmat */
6439f55f5f5SRafal Jaworowski 
6449f55f5f5SRafal Jaworowski 
6459f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM,
6469f55f5f5SRafal Jaworowski 	    &sc->mge_tx_dtag);
6479f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM,
6489f55f5f5SRafal Jaworowski 	    &sc->mge_rx_dtag);
6499f55f5f5SRafal Jaworowski 
6509f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
6519f55f5f5SRafal Jaworowski 		dw = &(sc->mge_rx_desc[i]);
6529f55f5f5SRafal Jaworowski 		mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer,
6539f55f5f5SRafal Jaworowski 		    &dw->mge_desc->buffer);
6549f55f5f5SRafal Jaworowski 	}
6559f55f5f5SRafal Jaworowski 
6569f55f5f5SRafal Jaworowski 	sc->tx_desc_start = sc->mge_tx_desc[0].mge_desc_paddr;
6579f55f5f5SRafal Jaworowski 	sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr;
6589f55f5f5SRafal Jaworowski 
6599f55f5f5SRafal Jaworowski 	return (0);
6609f55f5f5SRafal Jaworowski }
6619f55f5f5SRafal Jaworowski 
6629f55f5f5SRafal Jaworowski static void
6639f55f5f5SRafal Jaworowski mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab,
6649f55f5f5SRafal Jaworowski     uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs)
6659f55f5f5SRafal Jaworowski {
6669f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
6679f55f5f5SRafal Jaworowski 	int i;
6689f55f5f5SRafal Jaworowski 
6699f55f5f5SRafal Jaworowski 	for (i = 0; i < size; i++) {
6709f55f5f5SRafal Jaworowski 		/* Free RX mbuf */
6719f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
6729f55f5f5SRafal Jaworowski 
6739f55f5f5SRafal Jaworowski 		if (dw->buffer_dmap) {
6749f55f5f5SRafal Jaworowski 			if (free_mbufs) {
6759f55f5f5SRafal Jaworowski 				bus_dmamap_sync(buffer_tag, dw->buffer_dmap,
6769f55f5f5SRafal Jaworowski 				    BUS_DMASYNC_POSTREAD);
6779f55f5f5SRafal Jaworowski 				bus_dmamap_unload(buffer_tag, dw->buffer_dmap);
6789f55f5f5SRafal Jaworowski 			}
6799f55f5f5SRafal Jaworowski 			bus_dmamap_destroy(buffer_tag, dw->buffer_dmap);
6809f55f5f5SRafal Jaworowski 			if (free_mbufs)
6819f55f5f5SRafal Jaworowski 				m_freem(dw->buffer);
6829f55f5f5SRafal Jaworowski 		}
6839f55f5f5SRafal Jaworowski 		/* Free RX descriptors */
6849f55f5f5SRafal Jaworowski 		if (dw->desc_dmap) {
6859f55f5f5SRafal Jaworowski 			bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
6869f55f5f5SRafal Jaworowski 			    BUS_DMASYNC_POSTREAD);
6879f55f5f5SRafal Jaworowski 			bus_dmamap_unload(sc->mge_desc_dtag, dw->desc_dmap);
6889f55f5f5SRafal Jaworowski 			bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc,
6899f55f5f5SRafal Jaworowski 			    dw->desc_dmap);
6909f55f5f5SRafal Jaworowski 		}
6919f55f5f5SRafal Jaworowski 	}
6929f55f5f5SRafal Jaworowski }
6939f55f5f5SRafal Jaworowski 
6949f55f5f5SRafal Jaworowski static void
6959f55f5f5SRafal Jaworowski mge_free_dma(struct mge_softc *sc)
6969f55f5f5SRafal Jaworowski {
6974ac30cc1SZbigniew Bodek 
6989f55f5f5SRafal Jaworowski 	/* Free desciptors and mbufs */
6999f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1);
7009f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM, sc->mge_tx_dtag, 0);
7019f55f5f5SRafal Jaworowski 
7029f55f5f5SRafal Jaworowski 	/* Destroy mbuf dma tag */
7039f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_tx_dtag);
7049f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_rx_dtag);
7059f55f5f5SRafal Jaworowski 	/* Destroy descriptors tag */
7069f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_desc_dtag);
7079f55f5f5SRafal Jaworowski }
7089f55f5f5SRafal Jaworowski 
7099f55f5f5SRafal Jaworowski static void
7109f55f5f5SRafal Jaworowski mge_reinit_rx(struct mge_softc *sc)
7119f55f5f5SRafal Jaworowski {
7129f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
7139f55f5f5SRafal Jaworowski 	int i;
7149f55f5f5SRafal Jaworowski 
715d6bdd318SRafal Jaworowski 	MGE_RECEIVE_LOCK_ASSERT(sc);
7169f55f5f5SRafal Jaworowski 
7179f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1);
7189f55f5f5SRafal Jaworowski 
7199f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM,
7209f55f5f5SRafal Jaworowski 	    &sc->mge_rx_dtag);
7219f55f5f5SRafal Jaworowski 
7229f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
7239f55f5f5SRafal Jaworowski 		dw = &(sc->mge_rx_desc[i]);
7249f55f5f5SRafal Jaworowski 		mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer,
7259f55f5f5SRafal Jaworowski 		&dw->mge_desc->buffer);
7269f55f5f5SRafal Jaworowski 	}
7279f55f5f5SRafal Jaworowski 
7289f55f5f5SRafal Jaworowski 	sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr;
7299f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
7309f55f5f5SRafal Jaworowski 
7319f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE),
7329f55f5f5SRafal Jaworowski 	    sc->rx_desc_start);
7339f55f5f5SRafal Jaworowski 
7349f55f5f5SRafal Jaworowski 	/* Enable RX queue */
7359f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE));
7369f55f5f5SRafal Jaworowski }
7379f55f5f5SRafal Jaworowski 
7389f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
7399f55f5f5SRafal Jaworowski static poll_handler_t mge_poll;
7409f55f5f5SRafal Jaworowski 
7411abcdbd1SAttilio Rao static int
7429f55f5f5SRafal Jaworowski mge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
7439f55f5f5SRafal Jaworowski {
7449f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
7459f55f5f5SRafal Jaworowski 	uint32_t int_cause, int_cause_ext;
7461abcdbd1SAttilio Rao 	int rx_npkts = 0;
7479f55f5f5SRafal Jaworowski 
7483c71b84fSZbigniew Bodek 	MGE_RECEIVE_LOCK(sc);
7499f55f5f5SRafal Jaworowski 
7509f55f5f5SRafal Jaworowski 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
7513c71b84fSZbigniew Bodek 		MGE_RECEIVE_UNLOCK(sc);
7521abcdbd1SAttilio Rao 		return (rx_npkts);
7539f55f5f5SRafal Jaworowski 	}
7549f55f5f5SRafal Jaworowski 
7559f55f5f5SRafal Jaworowski 	if (cmd == POLL_AND_CHECK_STATUS) {
7569f55f5f5SRafal Jaworowski 		int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
7579f55f5f5SRafal Jaworowski 		int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
7589f55f5f5SRafal Jaworowski 
7599f55f5f5SRafal Jaworowski 		/* Check for resource error */
7609f55f5f5SRafal Jaworowski 		if (int_cause & MGE_PORT_INT_RXERRQ0)
7619f55f5f5SRafal Jaworowski 			mge_reinit_rx(sc);
7629f55f5f5SRafal Jaworowski 
7639f55f5f5SRafal Jaworowski 		if (int_cause || int_cause_ext) {
7649f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause);
7659f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext);
7669f55f5f5SRafal Jaworowski 		}
7679f55f5f5SRafal Jaworowski 	}
7689f55f5f5SRafal Jaworowski 
7693c71b84fSZbigniew Bodek 
7701abcdbd1SAttilio Rao 	rx_npkts = mge_intr_rx_locked(sc, count);
7719f55f5f5SRafal Jaworowski 
7723c71b84fSZbigniew Bodek 	MGE_RECEIVE_UNLOCK(sc);
7733c71b84fSZbigniew Bodek 	MGE_TRANSMIT_LOCK(sc);
7743c71b84fSZbigniew Bodek 	mge_intr_tx_locked(sc);
7753c71b84fSZbigniew Bodek 	MGE_TRANSMIT_UNLOCK(sc);
7761abcdbd1SAttilio Rao 	return (rx_npkts);
7779f55f5f5SRafal Jaworowski }
7789f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */
7799f55f5f5SRafal Jaworowski 
7809f55f5f5SRafal Jaworowski static int
7819f55f5f5SRafal Jaworowski mge_attach(device_t dev)
7829f55f5f5SRafal Jaworowski {
7839f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
784a6eb469dSPhilip Paeps 	struct mii_softc *miisc;
7859f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
7869f55f5f5SRafal Jaworowski 	uint8_t hwaddr[ETHER_ADDR_LEN];
7878e5d93dbSMarius Strobl 	int i, error, phy;
7889f55f5f5SRafal Jaworowski 
7899f55f5f5SRafal Jaworowski 	sc = device_get_softc(dev);
7909f55f5f5SRafal Jaworowski 	sc->dev = dev;
791db5ef4fcSRafal Jaworowski 	sc->node = ofw_bus_get_node(dev);
7923c71b84fSZbigniew Bodek 	phy = 0;
7933c71b84fSZbigniew Bodek 
7943c71b84fSZbigniew Bodek 	if (fdt_get_phyaddr(sc->node, sc->dev, &phy, (void **)&sc->phy_sc) == 0) {
7953c71b84fSZbigniew Bodek 		device_printf(dev, "PHY%i attached, phy_sc points to %s\n", phy,
7963c71b84fSZbigniew Bodek 		    device_get_nameunit(sc->phy_sc->dev));
7973c71b84fSZbigniew Bodek 		sc->phy_attached = 1;
7983c71b84fSZbigniew Bodek 	} else {
7993c71b84fSZbigniew Bodek 		device_printf(dev, "PHY not attached.\n");
8003c71b84fSZbigniew Bodek 		sc->phy_attached = 0;
8013c71b84fSZbigniew Bodek 		sc->phy_sc = sc;
8023c71b84fSZbigniew Bodek 	}
8033c71b84fSZbigniew Bodek 
8043c71b84fSZbigniew Bodek 	if (fdt_find_compatible(sc->node, "mrvl,sw", 1) != 0) {
8053c71b84fSZbigniew Bodek 		device_printf(dev, "Switch attached.\n");
8063c71b84fSZbigniew Bodek 		sc->switch_attached = 1;
8073c71b84fSZbigniew Bodek 		/* additional variable available across instances */
8083c71b84fSZbigniew Bodek 		switch_attached = 1;
8093c71b84fSZbigniew Bodek 	} else {
8103c71b84fSZbigniew Bodek 		sc->switch_attached = 0;
8113c71b84fSZbigniew Bodek 	}
8123c71b84fSZbigniew Bodek 
8133c71b84fSZbigniew Bodek 	if (device_get_unit(dev) == 0) {
8143c71b84fSZbigniew Bodek 		sx_init(&sx_smi, "mge_tick() SMI access threads interlock");
8153c71b84fSZbigniew Bodek 	}
8169f55f5f5SRafal Jaworowski 
8178e1dc58eSRafal Jaworowski 	/* Set chip version-dependent parameters */
8188e1dc58eSRafal Jaworowski 	mge_ver_params(sc);
8198e1dc58eSRafal Jaworowski 
8209f55f5f5SRafal Jaworowski 	/* Initialize mutexes */
8214ac30cc1SZbigniew Bodek 	mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "mge TX lock",
8224ac30cc1SZbigniew Bodek 	    MTX_DEF);
8234ac30cc1SZbigniew Bodek 	mtx_init(&sc->receive_lock, device_get_nameunit(dev), "mge RX lock",
8244ac30cc1SZbigniew Bodek 	    MTX_DEF);
8259f55f5f5SRafal Jaworowski 
8269f55f5f5SRafal Jaworowski 	/* Allocate IO and IRQ resources */
8279f55f5f5SRafal Jaworowski 	error = bus_alloc_resources(dev, res_spec, sc->res);
8289f55f5f5SRafal Jaworowski 	if (error) {
8299f55f5f5SRafal Jaworowski 		device_printf(dev, "could not allocate resources\n");
8309f55f5f5SRafal Jaworowski 		mge_detach(dev);
8319f55f5f5SRafal Jaworowski 		return (ENXIO);
8329f55f5f5SRafal Jaworowski 	}
8339f55f5f5SRafal Jaworowski 
8349f55f5f5SRafal Jaworowski 	/* Allocate DMA, buffers, buffer descriptors */
8359f55f5f5SRafal Jaworowski 	error = mge_allocate_dma(sc);
8369f55f5f5SRafal Jaworowski 	if (error) {
8379f55f5f5SRafal Jaworowski 		mge_detach(dev);
8389f55f5f5SRafal Jaworowski 		return (ENXIO);
8399f55f5f5SRafal Jaworowski 	}
8409f55f5f5SRafal Jaworowski 
8419f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = 0;
8429f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
8439f55f5f5SRafal Jaworowski 	sc->tx_desc_used_idx = 0;
8445817716fSRafal Jaworowski 	sc->tx_desc_used_count = 0;
8459f55f5f5SRafal Jaworowski 
8469f55f5f5SRafal Jaworowski 	/* Configure defaults for interrupts coalescing */
8479f55f5f5SRafal Jaworowski 	sc->rx_ic_time = 768;
8489f55f5f5SRafal Jaworowski 	sc->tx_ic_time = 768;
8499f55f5f5SRafal Jaworowski 	mge_add_sysctls(sc);
8509f55f5f5SRafal Jaworowski 
8519f55f5f5SRafal Jaworowski 	/* Allocate network interface */
8529f55f5f5SRafal Jaworowski 	ifp = sc->ifp = if_alloc(IFT_ETHER);
8539f55f5f5SRafal Jaworowski 	if (ifp == NULL) {
8549f55f5f5SRafal Jaworowski 		device_printf(dev, "if_alloc() failed\n");
8559f55f5f5SRafal Jaworowski 		mge_detach(dev);
8569f55f5f5SRafal Jaworowski 		return (ENOMEM);
8579f55f5f5SRafal Jaworowski 	}
8589f55f5f5SRafal Jaworowski 
8599f55f5f5SRafal Jaworowski 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
8609f55f5f5SRafal Jaworowski 	ifp->if_softc = sc;
8619f55f5f5SRafal Jaworowski 	ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST;
86275f1438bSOleksandr Tymoshenko 	ifp->if_capabilities = IFCAP_VLAN_MTU;
86375f1438bSOleksandr Tymoshenko 	if (sc->mge_hw_csum) {
86475f1438bSOleksandr Tymoshenko 		ifp->if_capabilities |= IFCAP_HWCSUM;
8659f55f5f5SRafal Jaworowski 		ifp->if_hwassist = MGE_CHECKSUM_FEATURES;
86675f1438bSOleksandr Tymoshenko 	}
86775f1438bSOleksandr Tymoshenko 	ifp->if_capenable = ifp->if_capabilities;
8689f55f5f5SRafal Jaworowski 
8699f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
8709f55f5f5SRafal Jaworowski 	/* Advertise that polling is supported */
8719f55f5f5SRafal Jaworowski 	ifp->if_capabilities |= IFCAP_POLLING;
8729f55f5f5SRafal Jaworowski #endif
8739f55f5f5SRafal Jaworowski 
8749f55f5f5SRafal Jaworowski 	ifp->if_init = mge_init;
8759f55f5f5SRafal Jaworowski 	ifp->if_start = mge_start;
8769f55f5f5SRafal Jaworowski 	ifp->if_ioctl = mge_ioctl;
8779f55f5f5SRafal Jaworowski 
8789f55f5f5SRafal Jaworowski 	ifp->if_snd.ifq_drv_maxlen = MGE_TX_DESC_NUM - 1;
8799f55f5f5SRafal Jaworowski 	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
8809f55f5f5SRafal Jaworowski 	IFQ_SET_READY(&ifp->if_snd);
8819f55f5f5SRafal Jaworowski 
8829f55f5f5SRafal Jaworowski 	mge_get_mac_address(sc, hwaddr);
8839f55f5f5SRafal Jaworowski 	ether_ifattach(ifp, hwaddr);
8849f55f5f5SRafal Jaworowski 	callout_init(&sc->wd_callout, 0);
8859f55f5f5SRafal Jaworowski 
8868e5d93dbSMarius Strobl 	/* Attach PHY(s) */
8873c71b84fSZbigniew Bodek 	if (sc->phy_attached) {
8888e5d93dbSMarius Strobl 		error = mii_attach(dev, &sc->miibus, ifp, mge_ifmedia_upd,
8898e5d93dbSMarius Strobl 		    mge_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
8909f55f5f5SRafal Jaworowski 		if (error) {
8913c71b84fSZbigniew Bodek 			device_printf(dev, "MII failed to find PHY\n");
8923c71b84fSZbigniew Bodek 			if_free(ifp);
8933c71b84fSZbigniew Bodek 			sc->ifp = NULL;
8949f55f5f5SRafal Jaworowski 			mge_detach(dev);
8959f55f5f5SRafal Jaworowski 			return (error);
8969f55f5f5SRafal Jaworowski 		}
8979f55f5f5SRafal Jaworowski 		sc->mii = device_get_softc(sc->miibus);
8989f55f5f5SRafal Jaworowski 
899a6eb469dSPhilip Paeps 		/* Tell the MAC where to find the PHY so autoneg works */
900a6eb469dSPhilip Paeps 		miisc = LIST_FIRST(&sc->mii->mii_phys);
901a6eb469dSPhilip Paeps 		MGE_WRITE(sc, MGE_REG_PHYDEV, miisc->mii_phy);
9023c71b84fSZbigniew Bodek 	} else {
9033c71b84fSZbigniew Bodek 		/* no PHY, so use hard-coded values */
9043c71b84fSZbigniew Bodek 		ifmedia_init(&sc->mge_ifmedia, 0,
9053c71b84fSZbigniew Bodek 		    mge_ifmedia_upd,
9063c71b84fSZbigniew Bodek 		    mge_ifmedia_sts);
9073c71b84fSZbigniew Bodek 		ifmedia_add(&sc->mge_ifmedia,
9083c71b84fSZbigniew Bodek 		    IFM_ETHER | IFM_1000_T | IFM_FDX,
9093c71b84fSZbigniew Bodek 		    0, NULL);
9103c71b84fSZbigniew Bodek 		ifmedia_set(&sc->mge_ifmedia,
9113c71b84fSZbigniew Bodek 		    IFM_ETHER | IFM_1000_T | IFM_FDX);
9123c71b84fSZbigniew Bodek 	}
913a6eb469dSPhilip Paeps 
9149f55f5f5SRafal Jaworowski 	/* Attach interrupt handlers */
91575f1438bSOleksandr Tymoshenko 	/* TODO: review flags, in part. mark RX as INTR_ENTROPY ? */
91675f1438bSOleksandr Tymoshenko 	for (i = 1; i <= sc->mge_intr_cnt; ++i) {
91775f1438bSOleksandr Tymoshenko 		error = bus_setup_intr(dev, sc->res[i],
91875f1438bSOleksandr Tymoshenko 		    INTR_TYPE_NET | INTR_MPSAFE,
91975f1438bSOleksandr Tymoshenko 		    NULL, *mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].handler,
92075f1438bSOleksandr Tymoshenko 		    sc, &sc->ih_cookie[i - 1]);
9219f55f5f5SRafal Jaworowski 		if (error) {
9229f55f5f5SRafal Jaworowski 			device_printf(dev, "could not setup %s\n",
92375f1438bSOleksandr Tymoshenko 			    mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].description);
924a6eb469dSPhilip Paeps 			mge_detach(dev);
9259f55f5f5SRafal Jaworowski 			return (error);
9269f55f5f5SRafal Jaworowski 		}
9279f55f5f5SRafal Jaworowski 	}
9289f55f5f5SRafal Jaworowski 
9293c71b84fSZbigniew Bodek 	if (sc->switch_attached) {
9303c71b84fSZbigniew Bodek 		device_t child;
9313c71b84fSZbigniew Bodek 		MGE_WRITE(sc, MGE_REG_PHYDEV, MGE_SWITCH_PHYDEV);
9323c71b84fSZbigniew Bodek 		child = device_add_child(dev, "mdio", -1);
9333c71b84fSZbigniew Bodek 		bus_generic_attach(dev);
9343c71b84fSZbigniew Bodek 	}
9353c71b84fSZbigniew Bodek 
9369f55f5f5SRafal Jaworowski 	return (0);
9379f55f5f5SRafal Jaworowski }
9389f55f5f5SRafal Jaworowski 
9399f55f5f5SRafal Jaworowski static int
9409f55f5f5SRafal Jaworowski mge_detach(device_t dev)
9419f55f5f5SRafal Jaworowski {
9429f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
9439f55f5f5SRafal Jaworowski 	int error,i;
9449f55f5f5SRafal Jaworowski 
9459f55f5f5SRafal Jaworowski 	sc = device_get_softc(dev);
9469f55f5f5SRafal Jaworowski 
9479f55f5f5SRafal Jaworowski 	/* Stop controller and free TX queue */
9489f55f5f5SRafal Jaworowski 	if (sc->ifp)
9499f55f5f5SRafal Jaworowski 		mge_shutdown(dev);
9509f55f5f5SRafal Jaworowski 
9519f55f5f5SRafal Jaworowski 	/* Wait for stopping ticks */
9529f55f5f5SRafal Jaworowski         callout_drain(&sc->wd_callout);
9539f55f5f5SRafal Jaworowski 
9549f55f5f5SRafal Jaworowski 	/* Stop and release all interrupts */
95575f1438bSOleksandr Tymoshenko 	for (i = 0; i < sc->mge_intr_cnt; ++i) {
956a6eb469dSPhilip Paeps 		if (!sc->ih_cookie[i])
957a6eb469dSPhilip Paeps 			continue;
958a6eb469dSPhilip Paeps 
9594ac30cc1SZbigniew Bodek 		error = bus_teardown_intr(dev, sc->res[1 + i],
9604ac30cc1SZbigniew Bodek 		    sc->ih_cookie[i]);
9619f55f5f5SRafal Jaworowski 		if (error)
9629f55f5f5SRafal Jaworowski 			device_printf(dev, "could not release %s\n",
96375f1438bSOleksandr Tymoshenko 			    mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i + 1)].description);
9649f55f5f5SRafal Jaworowski 	}
9659f55f5f5SRafal Jaworowski 
9669f55f5f5SRafal Jaworowski 	/* Detach network interface */
9679f55f5f5SRafal Jaworowski 	if (sc->ifp) {
9689f55f5f5SRafal Jaworowski 		ether_ifdetach(sc->ifp);
9699f55f5f5SRafal Jaworowski 		if_free(sc->ifp);
9709f55f5f5SRafal Jaworowski 	}
9719f55f5f5SRafal Jaworowski 
9729f55f5f5SRafal Jaworowski 	/* Free DMA resources */
9739f55f5f5SRafal Jaworowski 	mge_free_dma(sc);
9749f55f5f5SRafal Jaworowski 
9759f55f5f5SRafal Jaworowski 	/* Free IO memory handler */
9769f55f5f5SRafal Jaworowski 	bus_release_resources(dev, res_spec, sc->res);
9779f55f5f5SRafal Jaworowski 
9789f55f5f5SRafal Jaworowski 	/* Destroy mutexes */
9799f55f5f5SRafal Jaworowski 	mtx_destroy(&sc->receive_lock);
9809f55f5f5SRafal Jaworowski 	mtx_destroy(&sc->transmit_lock);
9819f55f5f5SRafal Jaworowski 
9823c71b84fSZbigniew Bodek 	if (device_get_unit(dev) == 0)
9833c71b84fSZbigniew Bodek 		sx_destroy(&sx_smi);
9843c71b84fSZbigniew Bodek 
9859f55f5f5SRafal Jaworowski 	return (0);
9869f55f5f5SRafal Jaworowski }
9879f55f5f5SRafal Jaworowski 
9889f55f5f5SRafal Jaworowski static void
9899f55f5f5SRafal Jaworowski mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
9909f55f5f5SRafal Jaworowski {
9914ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
9929f55f5f5SRafal Jaworowski 	struct mii_data *mii;
9939f55f5f5SRafal Jaworowski 
9944ac30cc1SZbigniew Bodek 	sc = ifp->if_softc;
9953c71b84fSZbigniew Bodek 	MGE_GLOBAL_LOCK(sc);
9963c71b84fSZbigniew Bodek 
9973c71b84fSZbigniew Bodek 	if (!sc->phy_attached) {
9983c71b84fSZbigniew Bodek 		ifmr->ifm_active = IFM_1000_T | IFM_FDX | IFM_ETHER;
9993c71b84fSZbigniew Bodek 		ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
10003c71b84fSZbigniew Bodek 		goto out_unlock;
10013c71b84fSZbigniew Bodek 	}
10029f55f5f5SRafal Jaworowski 
10039f55f5f5SRafal Jaworowski 	mii = sc->mii;
10049f55f5f5SRafal Jaworowski 	mii_pollstat(mii);
10059f55f5f5SRafal Jaworowski 
10069f55f5f5SRafal Jaworowski 	ifmr->ifm_active = mii->mii_media_active;
10079f55f5f5SRafal Jaworowski 	ifmr->ifm_status = mii->mii_media_status;
10089f55f5f5SRafal Jaworowski 
10093c71b84fSZbigniew Bodek out_unlock:
10103c71b84fSZbigniew Bodek 	MGE_GLOBAL_UNLOCK(sc);
10119f55f5f5SRafal Jaworowski }
10129f55f5f5SRafal Jaworowski 
10139f55f5f5SRafal Jaworowski static uint32_t
10149f55f5f5SRafal Jaworowski mge_set_port_serial_control(uint32_t media)
10159f55f5f5SRafal Jaworowski {
10169f55f5f5SRafal Jaworowski 	uint32_t port_config;
10179f55f5f5SRafal Jaworowski 
10189f55f5f5SRafal Jaworowski 	port_config = PORT_SERIAL_RES_BIT9 | PORT_SERIAL_FORCE_LINK_FAIL |
10199f55f5f5SRafal Jaworowski 	    PORT_SERIAL_MRU(PORT_SERIAL_MRU_1552);
10209f55f5f5SRafal Jaworowski 
10219f55f5f5SRafal Jaworowski 	if (IFM_TYPE(media) == IFM_ETHER) {
10229f55f5f5SRafal Jaworowski 		switch(IFM_SUBTYPE(media)) {
10239f55f5f5SRafal Jaworowski 			case IFM_AUTO:
10249f55f5f5SRafal Jaworowski 				break;
10259f55f5f5SRafal Jaworowski 			case IFM_1000_T:
10269f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_GMII_SPEED_1000 |
10273c71b84fSZbigniew Bodek 				    PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC
10283c71b84fSZbigniew Bodek 				    | PORT_SERIAL_SPEED_AUTONEG);
10299f55f5f5SRafal Jaworowski 				break;
10309f55f5f5SRafal Jaworowski 			case IFM_100_TX:
10319f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_MII_SPEED_100 |
10323c71b84fSZbigniew Bodek 				    PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC
10333c71b84fSZbigniew Bodek 				    | PORT_SERIAL_SPEED_AUTONEG);
10349f55f5f5SRafal Jaworowski 				break;
10359f55f5f5SRafal Jaworowski 			case IFM_10_T:
10369f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_AUTONEG |
10379f55f5f5SRafal Jaworowski 				    PORT_SERIAL_AUTONEG_FC |
10389f55f5f5SRafal Jaworowski 				    PORT_SERIAL_SPEED_AUTONEG);
10399f55f5f5SRafal Jaworowski 				break;
10409f55f5f5SRafal Jaworowski 		}
10419f55f5f5SRafal Jaworowski 		if (media & IFM_FDX)
10429f55f5f5SRafal Jaworowski 			port_config |= PORT_SERIAL_FULL_DUPLEX;
10439f55f5f5SRafal Jaworowski 	}
10449f55f5f5SRafal Jaworowski 	return (port_config);
10459f55f5f5SRafal Jaworowski }
10469f55f5f5SRafal Jaworowski 
10479f55f5f5SRafal Jaworowski static int
10489f55f5f5SRafal Jaworowski mge_ifmedia_upd(struct ifnet *ifp)
10499f55f5f5SRafal Jaworowski {
10509f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
10519f55f5f5SRafal Jaworowski 
10523c71b84fSZbigniew Bodek 	/*
10533c71b84fSZbigniew Bodek 	 * Do not do anything for switch here, as updating media between
10543c71b84fSZbigniew Bodek 	 * MGE MAC and switch MAC is hardcoded in PCB. Changing it here would
10553c71b84fSZbigniew Bodek 	 * break the link.
10563c71b84fSZbigniew Bodek 	 */
10573c71b84fSZbigniew Bodek 	if (sc->phy_attached) {
10589f55f5f5SRafal Jaworowski 		MGE_GLOBAL_LOCK(sc);
10593c71b84fSZbigniew Bodek 		if (ifp->if_flags & IFF_UP) {
10609f55f5f5SRafal Jaworowski 			sc->mge_media_status = sc->mii->mii_media.ifm_media;
10619f55f5f5SRafal Jaworowski 			mii_mediachg(sc->mii);
10623c71b84fSZbigniew Bodek 
10633c71b84fSZbigniew Bodek 			/* MGE MAC needs to be reinitialized. */
10649f55f5f5SRafal Jaworowski 			mge_init_locked(sc);
10659f55f5f5SRafal Jaworowski 
10663c71b84fSZbigniew Bodek 		}
10679f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
10689f55f5f5SRafal Jaworowski 	}
10699f55f5f5SRafal Jaworowski 
10709f55f5f5SRafal Jaworowski 	return (0);
10719f55f5f5SRafal Jaworowski }
10729f55f5f5SRafal Jaworowski 
10739f55f5f5SRafal Jaworowski static void
10749f55f5f5SRafal Jaworowski mge_init(void *arg)
10759f55f5f5SRafal Jaworowski {
10764ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
10779f55f5f5SRafal Jaworowski 
10784ac30cc1SZbigniew Bodek 	sc = arg;
10799f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
10809f55f5f5SRafal Jaworowski 
10819f55f5f5SRafal Jaworowski 	mge_init_locked(arg);
10829f55f5f5SRafal Jaworowski 
10839f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
10849f55f5f5SRafal Jaworowski }
10859f55f5f5SRafal Jaworowski 
10869f55f5f5SRafal Jaworowski static void
10879f55f5f5SRafal Jaworowski mge_init_locked(void *arg)
10889f55f5f5SRafal Jaworowski {
10899f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
10909f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
10919f55f5f5SRafal Jaworowski 	volatile uint32_t reg_val;
10929f55f5f5SRafal Jaworowski 	int i, count;
10933c71b84fSZbigniew Bodek 	uint32_t media_status;
10949f55f5f5SRafal Jaworowski 
10959f55f5f5SRafal Jaworowski 
10969f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK_ASSERT(sc);
10979f55f5f5SRafal Jaworowski 
10989f55f5f5SRafal Jaworowski 	/* Stop interface */
10999f55f5f5SRafal Jaworowski 	mge_stop(sc);
11009f55f5f5SRafal Jaworowski 
11019f55f5f5SRafal Jaworowski 	/* Disable interrupts */
11029f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 0);
11039f55f5f5SRafal Jaworowski 
11049f55f5f5SRafal Jaworowski 	/* Set MAC address */
11059f55f5f5SRafal Jaworowski 	mge_set_mac_address(sc);
11069f55f5f5SRafal Jaworowski 
11079f55f5f5SRafal Jaworowski 	/* Setup multicast filters */
11089f55f5f5SRafal Jaworowski 	mge_setup_multicast(sc);
11099f55f5f5SRafal Jaworowski 
11108e1dc58eSRafal Jaworowski 	if (sc->mge_ver == 2) {
11119f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL1, MGE_RGMII_EN);
11129f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_FIXED_PRIO_CONF, MGE_FIXED_PRIO_EN(0));
11138e1dc58eSRafal Jaworowski 	}
11149f55f5f5SRafal Jaworowski 
11158e1dc58eSRafal Jaworowski 	/* Initialize TX queue configuration registers */
11168e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(0), sc->mge_tx_tok_cnt);
11178e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_TOKEN_CONF(0), sc->mge_tx_tok_cfg);
11188e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_ARBITER_CONF(0), sc->mge_tx_arb_cfg);
11198e1dc58eSRafal Jaworowski 
11208e1dc58eSRafal Jaworowski 	/* Clear TX queue configuration registers for unused queues */
11219f55f5f5SRafal Jaworowski 	for (i = 1; i < 7; i++) {
11228e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(i), 0);
11238e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_TOKEN_CONF(i), 0);
11248e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_ARBITER_CONF(i), 0);
11259f55f5f5SRafal Jaworowski 	}
11269f55f5f5SRafal Jaworowski 
11279f55f5f5SRafal Jaworowski 	/* Set default MTU */
11288e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, sc->mge_mtu, 0);
11299f55f5f5SRafal Jaworowski 
11309f55f5f5SRafal Jaworowski 	/* Port configuration */
11319f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_CONFIG,
11329f55f5f5SRafal Jaworowski 	    PORT_CONFIG_RXCS | PORT_CONFIG_DFLT_RXQ(0) |
11339f55f5f5SRafal Jaworowski 	    PORT_CONFIG_ARO_RXQ(0));
11349f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_EXT_CONFIG , 0x0);
11359f55f5f5SRafal Jaworowski 
11363c71b84fSZbigniew Bodek 	/* Configure promisc mode */
11373c71b84fSZbigniew Bodek 	mge_set_prom_mode(sc, MGE_RX_DEFAULT_QUEUE);
11383c71b84fSZbigniew Bodek 
11393c71b84fSZbigniew Bodek 	media_status = sc->mge_media_status;
11403c71b84fSZbigniew Bodek 	if (sc->switch_attached) {
11413c71b84fSZbigniew Bodek 		media_status &= ~IFM_TMASK;
11423c71b84fSZbigniew Bodek 		media_status |= IFM_1000_T;
11433c71b84fSZbigniew Bodek 	}
11443c71b84fSZbigniew Bodek 
11459f55f5f5SRafal Jaworowski 	/* Setup port configuration */
11463c71b84fSZbigniew Bodek 	reg_val = mge_set_port_serial_control(media_status);
11479f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
11489f55f5f5SRafal Jaworowski 
11499f55f5f5SRafal Jaworowski 	/* Setup SDMA configuration */
11509f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_SDMA_CONFIG , MGE_SDMA_RX_BYTE_SWAP |
11519f55f5f5SRafal Jaworowski 	    MGE_SDMA_TX_BYTE_SWAP |
11529f55f5f5SRafal Jaworowski 	    MGE_SDMA_RX_BURST_SIZE(MGE_SDMA_BURST_16_WORD) |
11539f55f5f5SRafal Jaworowski 	    MGE_SDMA_TX_BURST_SIZE(MGE_SDMA_BURST_16_WORD));
11549f55f5f5SRafal Jaworowski 
11559f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, 0x0);
11569f55f5f5SRafal Jaworowski 
11579f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_CUR_DESC_PTR, sc->tx_desc_start);
11589f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE),
11599f55f5f5SRafal Jaworowski 	    sc->rx_desc_start);
11609f55f5f5SRafal Jaworowski 
11619f55f5f5SRafal Jaworowski 	/* Reset descriptor indexes */
11629f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = 0;
11639f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
11649f55f5f5SRafal Jaworowski 	sc->tx_desc_used_idx = 0;
11655817716fSRafal Jaworowski 	sc->tx_desc_used_count = 0;
11669f55f5f5SRafal Jaworowski 
11679f55f5f5SRafal Jaworowski 	/* Enable RX descriptors */
11689f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
11699f55f5f5SRafal Jaworowski 		dw = &sc->mge_rx_desc[i];
11709f55f5f5SRafal Jaworowski 		dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
11719f55f5f5SRafal Jaworowski 		dw->mge_desc->buff_size = MCLBYTES;
11729f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
11739f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
11749f55f5f5SRafal Jaworowski 	}
11759f55f5f5SRafal Jaworowski 
11769f55f5f5SRafal Jaworowski 	/* Enable RX queue */
11779f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE));
11789f55f5f5SRafal Jaworowski 
11799f55f5f5SRafal Jaworowski 	/* Enable port */
11809f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL);
11819f55f5f5SRafal Jaworowski 	reg_val |= PORT_SERIAL_ENABLE;
11829f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
11839f55f5f5SRafal Jaworowski 	count = 0x100000;
11849f55f5f5SRafal Jaworowski 	for (;;) {
11859f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_PORT_STATUS);
11869f55f5f5SRafal Jaworowski 		if (reg_val & MGE_STATUS_LINKUP)
11879f55f5f5SRafal Jaworowski 			break;
11889f55f5f5SRafal Jaworowski 		DELAY(100);
11899f55f5f5SRafal Jaworowski 		if (--count == 0) {
11909f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "Timeout on link-up\n");
11919f55f5f5SRafal Jaworowski 			break;
11929f55f5f5SRafal Jaworowski 		}
11939f55f5f5SRafal Jaworowski 	}
11949f55f5f5SRafal Jaworowski 
11959f55f5f5SRafal Jaworowski 	/* Setup interrupts coalescing */
11969f55f5f5SRafal Jaworowski 	mge_set_rxic(sc);
11979f55f5f5SRafal Jaworowski 	mge_set_txic(sc);
11989f55f5f5SRafal Jaworowski 
11999f55f5f5SRafal Jaworowski 	/* Enable interrupts */
12009f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
12019f55f5f5SRafal Jaworowski         /*
12029f55f5f5SRafal Jaworowski 	 * * ...only if polling is not turned on. Disable interrupts explicitly
12039f55f5f5SRafal Jaworowski 	 * if polling is enabled.
12049f55f5f5SRafal Jaworowski 	 */
12059f55f5f5SRafal Jaworowski 	if (sc->ifp->if_capenable & IFCAP_POLLING)
12069f55f5f5SRafal Jaworowski 		mge_intrs_ctrl(sc, 0);
12079f55f5f5SRafal Jaworowski 	else
12089f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */
12099f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 1);
12109f55f5f5SRafal Jaworowski 
12119f55f5f5SRafal Jaworowski 	/* Activate network interface */
12129f55f5f5SRafal Jaworowski 	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
12139f55f5f5SRafal Jaworowski 	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
12149f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
12159f55f5f5SRafal Jaworowski 
12169f55f5f5SRafal Jaworowski 	/* Schedule watchdog timeout */
12173c71b84fSZbigniew Bodek 	if (sc->phy_attached)
12189f55f5f5SRafal Jaworowski 		callout_reset(&sc->wd_callout, hz, mge_tick, sc);
12199f55f5f5SRafal Jaworowski }
12209f55f5f5SRafal Jaworowski 
12219f55f5f5SRafal Jaworowski static void
122275f1438bSOleksandr Tymoshenko mge_intr_rxtx(void *arg)
122375f1438bSOleksandr Tymoshenko {
12244ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
122575f1438bSOleksandr Tymoshenko 	uint32_t int_cause, int_cause_ext;
122675f1438bSOleksandr Tymoshenko 
12274ac30cc1SZbigniew Bodek 	sc = arg;
122875f1438bSOleksandr Tymoshenko 	MGE_GLOBAL_LOCK(sc);
122975f1438bSOleksandr Tymoshenko 
123075f1438bSOleksandr Tymoshenko #ifdef DEVICE_POLLING
123175f1438bSOleksandr Tymoshenko 	if (sc->ifp->if_capenable & IFCAP_POLLING) {
123275f1438bSOleksandr Tymoshenko 		MGE_GLOBAL_UNLOCK(sc);
123375f1438bSOleksandr Tymoshenko 		return;
123475f1438bSOleksandr Tymoshenko 	}
123575f1438bSOleksandr Tymoshenko #endif
123675f1438bSOleksandr Tymoshenko 
123775f1438bSOleksandr Tymoshenko 	/* Get interrupt cause */
123875f1438bSOleksandr Tymoshenko 	int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
123975f1438bSOleksandr Tymoshenko 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
124075f1438bSOleksandr Tymoshenko 
124175f1438bSOleksandr Tymoshenko 	/* Check for Transmit interrupt */
124275f1438bSOleksandr Tymoshenko 	if (int_cause_ext & (MGE_PORT_INT_EXT_TXBUF0 |
124375f1438bSOleksandr Tymoshenko 	    MGE_PORT_INT_EXT_TXUR)) {
124475f1438bSOleksandr Tymoshenko 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext &
124575f1438bSOleksandr Tymoshenko 		    (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR)));
124675f1438bSOleksandr Tymoshenko 		mge_intr_tx_locked(sc);
124775f1438bSOleksandr Tymoshenko 	}
124875f1438bSOleksandr Tymoshenko 
124975f1438bSOleksandr Tymoshenko 	MGE_TRANSMIT_UNLOCK(sc);
125075f1438bSOleksandr Tymoshenko 
125175f1438bSOleksandr Tymoshenko 	/* Check for Receive interrupt */
125275f1438bSOleksandr Tymoshenko 	mge_intr_rx_check(sc, int_cause, int_cause_ext);
125375f1438bSOleksandr Tymoshenko 
125475f1438bSOleksandr Tymoshenko 	MGE_RECEIVE_UNLOCK(sc);
125575f1438bSOleksandr Tymoshenko }
125675f1438bSOleksandr Tymoshenko 
125775f1438bSOleksandr Tymoshenko static void
12589f55f5f5SRafal Jaworowski mge_intr_err(void *arg)
12599f55f5f5SRafal Jaworowski {
12604ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
12619f55f5f5SRafal Jaworowski 	struct ifnet *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_misc(void *arg)
12709f55f5f5SRafal Jaworowski {
12714ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
12729f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
12739f55f5f5SRafal Jaworowski 
12744ac30cc1SZbigniew Bodek 	sc = arg;
12759f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
12769f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
12779f55f5f5SRafal Jaworowski }
12789f55f5f5SRafal Jaworowski 
12799f55f5f5SRafal Jaworowski static void
12809f55f5f5SRafal Jaworowski mge_intr_rx(void *arg) {
12814ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
12829f55f5f5SRafal Jaworowski 	uint32_t int_cause, int_cause_ext;
12839f55f5f5SRafal Jaworowski 
12844ac30cc1SZbigniew Bodek 	sc = arg;
12859f55f5f5SRafal Jaworowski 	MGE_RECEIVE_LOCK(sc);
12869f55f5f5SRafal Jaworowski 
12879f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
12889f55f5f5SRafal Jaworowski 	if (sc->ifp->if_capenable & IFCAP_POLLING) {
12899f55f5f5SRafal Jaworowski 		MGE_RECEIVE_UNLOCK(sc);
12909f55f5f5SRafal Jaworowski 		return;
12919f55f5f5SRafal Jaworowski 	}
12929f55f5f5SRafal Jaworowski #endif
12939f55f5f5SRafal Jaworowski 
12949f55f5f5SRafal Jaworowski 	/* Get interrupt cause */
12959f55f5f5SRafal Jaworowski 	int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
12969f55f5f5SRafal Jaworowski 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
12979f55f5f5SRafal Jaworowski 
129875f1438bSOleksandr Tymoshenko 	mge_intr_rx_check(sc, int_cause, int_cause_ext);
129975f1438bSOleksandr Tymoshenko 
130075f1438bSOleksandr Tymoshenko 	MGE_RECEIVE_UNLOCK(sc);
130175f1438bSOleksandr Tymoshenko }
130275f1438bSOleksandr Tymoshenko 
130375f1438bSOleksandr Tymoshenko static void
130475f1438bSOleksandr Tymoshenko mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause,
130575f1438bSOleksandr Tymoshenko     uint32_t int_cause_ext)
130675f1438bSOleksandr Tymoshenko {
13079f55f5f5SRafal Jaworowski 	/* Check for resource error */
13089f55f5f5SRafal Jaworowski 	if (int_cause & MGE_PORT_INT_RXERRQ0) {
13099f55f5f5SRafal Jaworowski 		mge_reinit_rx(sc);
13109f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE,
131175f1438bSOleksandr Tymoshenko 		    ~(int_cause & MGE_PORT_INT_RXERRQ0));
13129f55f5f5SRafal Jaworowski 	}
13139f55f5f5SRafal Jaworowski 
13149f55f5f5SRafal Jaworowski 	int_cause &= MGE_PORT_INT_RXQ0;
13159f55f5f5SRafal Jaworowski 	int_cause_ext &= MGE_PORT_INT_EXT_RXOR;
13169f55f5f5SRafal Jaworowski 
13179f55f5f5SRafal Jaworowski 	if (int_cause || int_cause_ext) {
13189f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause);
13199f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext);
13209f55f5f5SRafal Jaworowski 		mge_intr_rx_locked(sc, -1);
13219f55f5f5SRafal Jaworowski 	}
13229f55f5f5SRafal Jaworowski }
13239f55f5f5SRafal Jaworowski 
13241abcdbd1SAttilio Rao static int
13259f55f5f5SRafal Jaworowski mge_intr_rx_locked(struct mge_softc *sc, int count)
13269f55f5f5SRafal Jaworowski {
13279f55f5f5SRafal Jaworowski 	struct ifnet *ifp = sc->ifp;
13289f55f5f5SRafal Jaworowski 	uint32_t status;
13299f55f5f5SRafal Jaworowski 	uint16_t bufsize;
13309f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper* dw;
13319f55f5f5SRafal Jaworowski 	struct mbuf *mb;
13321abcdbd1SAttilio Rao 	int rx_npkts = 0;
13339f55f5f5SRafal Jaworowski 
13349f55f5f5SRafal Jaworowski 	MGE_RECEIVE_LOCK_ASSERT(sc);
13359f55f5f5SRafal Jaworowski 
13369f55f5f5SRafal Jaworowski 	while (count != 0) {
13379f55f5f5SRafal Jaworowski 		dw = &sc->mge_rx_desc[sc->rx_desc_curr];
13389f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
13399f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
13409f55f5f5SRafal Jaworowski 
13419f55f5f5SRafal Jaworowski 		/* Get status */
13429f55f5f5SRafal Jaworowski 		status = dw->mge_desc->cmd_status;
13439f55f5f5SRafal Jaworowski 		bufsize = dw->mge_desc->buff_size;
13449f55f5f5SRafal Jaworowski 		if ((status & MGE_DMA_OWNED) != 0)
13459f55f5f5SRafal Jaworowski 			break;
13469f55f5f5SRafal Jaworowski 
13479f55f5f5SRafal Jaworowski 		if (dw->mge_desc->byte_count &&
13489f55f5f5SRafal Jaworowski 		    ~(status & MGE_ERR_SUMMARY)) {
13499f55f5f5SRafal Jaworowski 
13509f55f5f5SRafal Jaworowski 			bus_dmamap_sync(sc->mge_rx_dtag, dw->buffer_dmap,
13519f55f5f5SRafal Jaworowski 			    BUS_DMASYNC_POSTREAD);
13529f55f5f5SRafal Jaworowski 
13539f55f5f5SRafal Jaworowski 			mb = m_devget(dw->buffer->m_data,
13549f55f5f5SRafal Jaworowski 			    dw->mge_desc->byte_count - ETHER_CRC_LEN,
13559f55f5f5SRafal Jaworowski 			    0, ifp, NULL);
13569f55f5f5SRafal Jaworowski 
13575817716fSRafal Jaworowski 			if (mb == NULL)
13585817716fSRafal Jaworowski 				/* Give up if no mbufs */
13595817716fSRafal Jaworowski 				break;
13605817716fSRafal Jaworowski 
13619f55f5f5SRafal Jaworowski 			mb->m_len -= 2;
13629f55f5f5SRafal Jaworowski 			mb->m_pkthdr.len -= 2;
13639f55f5f5SRafal Jaworowski 			mb->m_data += 2;
13649f55f5f5SRafal Jaworowski 
1365b8fad6c0SFabien Thomas 			mb->m_pkthdr.rcvif = ifp;
1366b8fad6c0SFabien Thomas 
13679f55f5f5SRafal Jaworowski 			mge_offload_process_frame(ifp, mb, status,
13689f55f5f5SRafal Jaworowski 			    bufsize);
13699f55f5f5SRafal Jaworowski 
13709f55f5f5SRafal Jaworowski 			MGE_RECEIVE_UNLOCK(sc);
13719f55f5f5SRafal Jaworowski 			(*ifp->if_input)(ifp, mb);
13729f55f5f5SRafal Jaworowski 			MGE_RECEIVE_LOCK(sc);
13731abcdbd1SAttilio Rao 			rx_npkts++;
13749f55f5f5SRafal Jaworowski 		}
13759f55f5f5SRafal Jaworowski 
13769f55f5f5SRafal Jaworowski 		dw->mge_desc->byte_count = 0;
13779f55f5f5SRafal Jaworowski 		dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
13785817716fSRafal Jaworowski 		sc->rx_desc_curr = (++sc->rx_desc_curr % MGE_RX_DESC_NUM);
13799f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
13809f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
13819f55f5f5SRafal Jaworowski 
13829f55f5f5SRafal Jaworowski 		if (count > 0)
13839f55f5f5SRafal Jaworowski 			count -= 1;
13849f55f5f5SRafal Jaworowski 	}
13859f55f5f5SRafal Jaworowski 
1386c8dfaf38SGleb Smirnoff 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_npkts);
1387b8fad6c0SFabien Thomas 
13881abcdbd1SAttilio Rao 	return (rx_npkts);
13899f55f5f5SRafal Jaworowski }
13909f55f5f5SRafal Jaworowski 
13919f55f5f5SRafal Jaworowski static void
13929f55f5f5SRafal Jaworowski mge_intr_sum(void *arg)
13939f55f5f5SRafal Jaworowski {
13949f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
13959f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
13969f55f5f5SRafal Jaworowski 
13979f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
13989f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
13999f55f5f5SRafal Jaworowski }
14009f55f5f5SRafal Jaworowski 
14019f55f5f5SRafal Jaworowski static void
14029f55f5f5SRafal Jaworowski mge_intr_tx(void *arg)
14039f55f5f5SRafal Jaworowski {
14049f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
14059f55f5f5SRafal Jaworowski 	uint32_t int_cause_ext;
14069f55f5f5SRafal Jaworowski 
14079f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK(sc);
14089f55f5f5SRafal Jaworowski 
14099f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
14109f55f5f5SRafal Jaworowski 	if (sc->ifp->if_capenable & IFCAP_POLLING) {
14119f55f5f5SRafal Jaworowski 		MGE_TRANSMIT_UNLOCK(sc);
14129f55f5f5SRafal Jaworowski 		return;
14139f55f5f5SRafal Jaworowski 	}
14149f55f5f5SRafal Jaworowski #endif
14159f55f5f5SRafal Jaworowski 
14169f55f5f5SRafal Jaworowski 	/* Ack the interrupt */
14179f55f5f5SRafal Jaworowski 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
141875f1438bSOleksandr Tymoshenko 	MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext &
141975f1438bSOleksandr Tymoshenko 	    (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR)));
14209f55f5f5SRafal Jaworowski 
14219f55f5f5SRafal Jaworowski 	mge_intr_tx_locked(sc);
14229f55f5f5SRafal Jaworowski 
14239f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_UNLOCK(sc);
14249f55f5f5SRafal Jaworowski }
14259f55f5f5SRafal Jaworowski 
14269f55f5f5SRafal Jaworowski static void
14279f55f5f5SRafal Jaworowski mge_intr_tx_locked(struct mge_softc *sc)
14289f55f5f5SRafal Jaworowski {
14299f55f5f5SRafal Jaworowski 	struct ifnet *ifp = sc->ifp;
14309f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
14319f55f5f5SRafal Jaworowski 	struct mge_desc *desc;
14329f55f5f5SRafal Jaworowski 	uint32_t status;
14339f55f5f5SRafal Jaworowski 	int send = 0;
14349f55f5f5SRafal Jaworowski 
14359f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK_ASSERT(sc);
14369f55f5f5SRafal Jaworowski 
14379f55f5f5SRafal Jaworowski 	/* Disable watchdog */
14389f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
14399f55f5f5SRafal Jaworowski 
14409f55f5f5SRafal Jaworowski 	while (sc->tx_desc_used_count) {
14419f55f5f5SRafal Jaworowski 		/* Get the descriptor */
14429f55f5f5SRafal Jaworowski 		dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
14439f55f5f5SRafal Jaworowski 		desc = dw->mge_desc;
14449f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
14459f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
14469f55f5f5SRafal Jaworowski 
14479f55f5f5SRafal Jaworowski 		/* Get descriptor status */
14489f55f5f5SRafal Jaworowski 		status = desc->cmd_status;
14499f55f5f5SRafal Jaworowski 
14509f55f5f5SRafal Jaworowski 		if (status & MGE_DMA_OWNED)
14519f55f5f5SRafal Jaworowski 			break;
14529f55f5f5SRafal Jaworowski 
14539f55f5f5SRafal Jaworowski 		sc->tx_desc_used_idx =
1454c2ede4b3SMartin Blapp 			(++sc->tx_desc_used_idx) % MGE_TX_DESC_NUM;
14559f55f5f5SRafal Jaworowski 		sc->tx_desc_used_count--;
14569f55f5f5SRafal Jaworowski 
14579f55f5f5SRafal Jaworowski 		/* Update collision statistics */
14589f55f5f5SRafal Jaworowski 		if (status & MGE_ERR_SUMMARY) {
14599f55f5f5SRafal Jaworowski 			if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_LC)
1460c8dfaf38SGleb Smirnoff 				if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1);
14619f55f5f5SRafal Jaworowski 			if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_RL)
1462c8dfaf38SGleb Smirnoff 				if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 16);
14639f55f5f5SRafal Jaworowski 		}
14649f55f5f5SRafal Jaworowski 
14659f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
14669f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTWRITE);
14679f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap);
14689f55f5f5SRafal Jaworowski 		m_freem(dw->buffer);
14699f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
14709f55f5f5SRafal Jaworowski 		send++;
14719f55f5f5SRafal Jaworowski 
1472c8dfaf38SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
14739f55f5f5SRafal Jaworowski 	}
14749f55f5f5SRafal Jaworowski 
14759f55f5f5SRafal Jaworowski 	if (send) {
14769f55f5f5SRafal Jaworowski 		/* Now send anything that was pending */
14779f55f5f5SRafal Jaworowski 		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
14789f55f5f5SRafal Jaworowski 		mge_start_locked(ifp);
14799f55f5f5SRafal Jaworowski 	}
14809f55f5f5SRafal Jaworowski }
14819f55f5f5SRafal Jaworowski static int
14829f55f5f5SRafal Jaworowski mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
14839f55f5f5SRafal Jaworowski {
14849f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
14859f55f5f5SRafal Jaworowski 	struct ifreq *ifr = (struct ifreq *)data;
14869f55f5f5SRafal Jaworowski 	int mask, error;
14879f55f5f5SRafal Jaworowski 	uint32_t flags;
14889f55f5f5SRafal Jaworowski 
14899f55f5f5SRafal Jaworowski 	error = 0;
14909f55f5f5SRafal Jaworowski 
14919f55f5f5SRafal Jaworowski 	switch (command) {
14929f55f5f5SRafal Jaworowski 	case SIOCSIFFLAGS:
14939f55f5f5SRafal Jaworowski 		MGE_GLOBAL_LOCK(sc);
14949f55f5f5SRafal Jaworowski 
14959f55f5f5SRafal Jaworowski 		if (ifp->if_flags & IFF_UP) {
14969f55f5f5SRafal Jaworowski 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
14979f55f5f5SRafal Jaworowski 				flags = ifp->if_flags ^ sc->mge_if_flags;
14989f55f5f5SRafal Jaworowski 				if (flags & IFF_PROMISC)
14999f55f5f5SRafal Jaworowski 					mge_set_prom_mode(sc,
15009f55f5f5SRafal Jaworowski 					    MGE_RX_DEFAULT_QUEUE);
15019f55f5f5SRafal Jaworowski 
15029f55f5f5SRafal Jaworowski 				if (flags & IFF_ALLMULTI)
15039f55f5f5SRafal Jaworowski 					mge_setup_multicast(sc);
15049f55f5f5SRafal Jaworowski 			} else
15059f55f5f5SRafal Jaworowski 				mge_init_locked(sc);
15069f55f5f5SRafal Jaworowski 		}
15079f55f5f5SRafal Jaworowski 		else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
15089f55f5f5SRafal Jaworowski 			mge_stop(sc);
15099f55f5f5SRafal Jaworowski 
15109f55f5f5SRafal Jaworowski 		sc->mge_if_flags = ifp->if_flags;
15119f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
15129f55f5f5SRafal Jaworowski 		break;
15139f55f5f5SRafal Jaworowski 	case SIOCADDMULTI:
15149f55f5f5SRafal Jaworowski 	case SIOCDELMULTI:
15159f55f5f5SRafal Jaworowski 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
15169f55f5f5SRafal Jaworowski 			MGE_GLOBAL_LOCK(sc);
15179f55f5f5SRafal Jaworowski 			mge_setup_multicast(sc);
15189f55f5f5SRafal Jaworowski 			MGE_GLOBAL_UNLOCK(sc);
15199f55f5f5SRafal Jaworowski 		}
15209f55f5f5SRafal Jaworowski 		break;
15219f55f5f5SRafal Jaworowski 	case SIOCSIFCAP:
15229f55f5f5SRafal Jaworowski 		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
15239f55f5f5SRafal Jaworowski 		if (mask & IFCAP_HWCSUM) {
15249f55f5f5SRafal Jaworowski 			ifp->if_capenable &= ~IFCAP_HWCSUM;
15259f55f5f5SRafal Jaworowski 			ifp->if_capenable |= IFCAP_HWCSUM & ifr->ifr_reqcap;
15269f55f5f5SRafal Jaworowski 			if (ifp->if_capenable & IFCAP_TXCSUM)
15279f55f5f5SRafal Jaworowski 				ifp->if_hwassist = MGE_CHECKSUM_FEATURES;
15289f55f5f5SRafal Jaworowski 			else
15299f55f5f5SRafal Jaworowski 				ifp->if_hwassist = 0;
15309f55f5f5SRafal Jaworowski 		}
15319f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
15329f55f5f5SRafal Jaworowski 		if (mask & IFCAP_POLLING) {
15339f55f5f5SRafal Jaworowski 			if (ifr->ifr_reqcap & IFCAP_POLLING) {
15349f55f5f5SRafal Jaworowski 				error = ether_poll_register(mge_poll, ifp);
15359f55f5f5SRafal Jaworowski 				if (error)
15369f55f5f5SRafal Jaworowski 					return(error);
15379f55f5f5SRafal Jaworowski 
15389f55f5f5SRafal Jaworowski 				MGE_GLOBAL_LOCK(sc);
15399f55f5f5SRafal Jaworowski 				mge_intrs_ctrl(sc, 0);
15409f55f5f5SRafal Jaworowski 				ifp->if_capenable |= IFCAP_POLLING;
15419f55f5f5SRafal Jaworowski 				MGE_GLOBAL_UNLOCK(sc);
15429f55f5f5SRafal Jaworowski 			} else {
15439f55f5f5SRafal Jaworowski 				error = ether_poll_deregister(ifp);
15449f55f5f5SRafal Jaworowski 				MGE_GLOBAL_LOCK(sc);
15459f55f5f5SRafal Jaworowski 				mge_intrs_ctrl(sc, 1);
15469f55f5f5SRafal Jaworowski 				ifp->if_capenable &= ~IFCAP_POLLING;
15479f55f5f5SRafal Jaworowski 				MGE_GLOBAL_UNLOCK(sc);
15489f55f5f5SRafal Jaworowski 			}
15499f55f5f5SRafal Jaworowski 		}
15509f55f5f5SRafal Jaworowski #endif
15519f55f5f5SRafal Jaworowski 		break;
15529f55f5f5SRafal Jaworowski 	case SIOCGIFMEDIA: /* fall through */
15539f55f5f5SRafal Jaworowski 	case SIOCSIFMEDIA:
15543c71b84fSZbigniew Bodek 		/*
15553c71b84fSZbigniew Bodek 		 * Setting up media type via ioctls is *not* supported for MAC
15563c71b84fSZbigniew Bodek 		 * which is connected to switch. Use etherswitchcfg.
15573c71b84fSZbigniew Bodek 		 */
15583c71b84fSZbigniew Bodek 		if (!sc->phy_attached && (command == SIOCSIFMEDIA))
15593c71b84fSZbigniew Bodek 			return (0);
15603c71b84fSZbigniew Bodek 		else if (!sc->phy_attached) {
15613c71b84fSZbigniew Bodek 			error = ifmedia_ioctl(ifp, ifr, &sc->mge_ifmedia,
15623c71b84fSZbigniew Bodek 			    command);
15633c71b84fSZbigniew Bodek 			break;
15643c71b84fSZbigniew Bodek 		}
15653c71b84fSZbigniew Bodek 
15669f55f5f5SRafal Jaworowski 		if (IFM_SUBTYPE(ifr->ifr_media) == IFM_1000_T
15679f55f5f5SRafal Jaworowski 		    && !(ifr->ifr_media & IFM_FDX)) {
15689f55f5f5SRafal Jaworowski 			device_printf(sc->dev,
15699f55f5f5SRafal Jaworowski 			    "1000baseTX half-duplex unsupported\n");
15709f55f5f5SRafal Jaworowski 			return 0;
15719f55f5f5SRafal Jaworowski 		}
15729f55f5f5SRafal Jaworowski 		error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command);
15739f55f5f5SRafal Jaworowski 		break;
15749f55f5f5SRafal Jaworowski 	default:
15759f55f5f5SRafal Jaworowski 		error = ether_ioctl(ifp, command, data);
15769f55f5f5SRafal Jaworowski 	}
15779f55f5f5SRafal Jaworowski 	return (error);
15789f55f5f5SRafal Jaworowski }
15799f55f5f5SRafal Jaworowski 
15809f55f5f5SRafal Jaworowski static int
15819f55f5f5SRafal Jaworowski mge_miibus_readreg(device_t dev, int phy, int reg)
15829f55f5f5SRafal Jaworowski {
1583db5ef4fcSRafal Jaworowski 	struct mge_softc *sc;
1584db5ef4fcSRafal Jaworowski 	sc = device_get_softc(dev);
15859f55f5f5SRafal Jaworowski 
15863c71b84fSZbigniew Bodek 	KASSERT(!switch_attached, ("miibus used with switch attached"));
15879f55f5f5SRafal Jaworowski 
15883c71b84fSZbigniew Bodek 	return (mv_read_ext_phy(dev, phy, reg));
15899f55f5f5SRafal Jaworowski }
15909f55f5f5SRafal Jaworowski 
15918e45f0b7SAndriy Gapon static int
15929f55f5f5SRafal Jaworowski mge_miibus_writereg(device_t dev, int phy, int reg, int value)
15939f55f5f5SRafal Jaworowski {
1594db5ef4fcSRafal Jaworowski 	struct mge_softc *sc;
1595db5ef4fcSRafal Jaworowski 	sc = device_get_softc(dev);
1596db5ef4fcSRafal Jaworowski 
15973c71b84fSZbigniew Bodek 	KASSERT(!switch_attached, ("miibus used with switch attached"));
15989f55f5f5SRafal Jaworowski 
15993c71b84fSZbigniew Bodek 	mv_write_ext_phy(dev, phy, reg, value);
16009f55f5f5SRafal Jaworowski 
16018e45f0b7SAndriy Gapon 	return (0);
16029f55f5f5SRafal Jaworowski }
16039f55f5f5SRafal Jaworowski 
16049f55f5f5SRafal Jaworowski static int
16059f55f5f5SRafal Jaworowski mge_probe(device_t dev)
16069f55f5f5SRafal Jaworowski {
16079f55f5f5SRafal Jaworowski 
1608add35ed5SIan Lepore 	if (!ofw_bus_status_okay(dev))
1609add35ed5SIan Lepore 		return (ENXIO);
1610add35ed5SIan Lepore 
1611db5ef4fcSRafal Jaworowski 	if (!ofw_bus_is_compatible(dev, "mrvl,ge"))
1612db5ef4fcSRafal Jaworowski 		return (ENXIO);
1613db5ef4fcSRafal Jaworowski 
16149f55f5f5SRafal Jaworowski 	device_set_desc(dev, "Marvell Gigabit Ethernet controller");
16159f55f5f5SRafal Jaworowski 	return (BUS_PROBE_DEFAULT);
16169f55f5f5SRafal Jaworowski }
16179f55f5f5SRafal Jaworowski 
16189f55f5f5SRafal Jaworowski static int
16199f55f5f5SRafal Jaworowski mge_resume(device_t dev)
16209f55f5f5SRafal Jaworowski {
16219f55f5f5SRafal Jaworowski 
16229f55f5f5SRafal Jaworowski 	device_printf(dev, "%s\n", __FUNCTION__);
16239f55f5f5SRafal Jaworowski 	return (0);
16249f55f5f5SRafal Jaworowski }
16259f55f5f5SRafal Jaworowski 
16269f55f5f5SRafal Jaworowski static int
16279f55f5f5SRafal Jaworowski mge_shutdown(device_t dev)
16289f55f5f5SRafal Jaworowski {
16299f55f5f5SRafal Jaworowski 	struct mge_softc *sc = device_get_softc(dev);
16309f55f5f5SRafal Jaworowski 
16319f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
16329f55f5f5SRafal Jaworowski 
16339f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
16349f55f5f5SRafal Jaworowski         if (sc->ifp->if_capenable & IFCAP_POLLING)
16359f55f5f5SRafal Jaworowski 		ether_poll_deregister(sc->ifp);
16369f55f5f5SRafal Jaworowski #endif
16379f55f5f5SRafal Jaworowski 
16389f55f5f5SRafal Jaworowski 	mge_stop(sc);
16399f55f5f5SRafal Jaworowski 
16409f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
16419f55f5f5SRafal Jaworowski 
16429f55f5f5SRafal Jaworowski 	return (0);
16439f55f5f5SRafal Jaworowski }
16449f55f5f5SRafal Jaworowski 
16459f55f5f5SRafal Jaworowski static int
16469f55f5f5SRafal Jaworowski mge_encap(struct mge_softc *sc, struct mbuf *m0)
16479f55f5f5SRafal Jaworowski {
16489f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw = NULL;
16499f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
16509f55f5f5SRafal Jaworowski 	bus_dma_segment_t segs[MGE_TX_DESC_NUM];
16519f55f5f5SRafal Jaworowski 	bus_dmamap_t mapp;
16529f55f5f5SRafal Jaworowski 	int error;
16539f55f5f5SRafal Jaworowski 	int seg, nsegs;
16549f55f5f5SRafal Jaworowski 	int desc_no;
16559f55f5f5SRafal Jaworowski 
16569f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
16579f55f5f5SRafal Jaworowski 
16589f55f5f5SRafal Jaworowski 	/* Fetch unused map */
16599f55f5f5SRafal Jaworowski 	desc_no = sc->tx_desc_curr;
16609f55f5f5SRafal Jaworowski 	dw = &sc->mge_tx_desc[desc_no];
16619f55f5f5SRafal Jaworowski 	mapp = dw->buffer_dmap;
16629f55f5f5SRafal Jaworowski 
16639f55f5f5SRafal Jaworowski 	/* Create mapping in DMA memory */
16649f55f5f5SRafal Jaworowski 	error = bus_dmamap_load_mbuf_sg(sc->mge_tx_dtag, mapp, m0, segs, &nsegs,
16659f55f5f5SRafal Jaworowski 	    BUS_DMA_NOWAIT);
1666b8fad6c0SFabien Thomas 	if (error != 0) {
1667b8fad6c0SFabien Thomas 		m_freem(m0);
1668b8fad6c0SFabien Thomas 		return (error);
1669b8fad6c0SFabien Thomas 	}
1670b8fad6c0SFabien Thomas 
1671b8fad6c0SFabien Thomas 	/* Only one segment is supported. */
1672b8fad6c0SFabien Thomas 	if (nsegs != 1) {
16739f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, mapp);
1674b8fad6c0SFabien Thomas 		m_freem(m0);
1675b8fad6c0SFabien Thomas 		return (-1);
16769f55f5f5SRafal Jaworowski 	}
16779f55f5f5SRafal Jaworowski 
16789f55f5f5SRafal Jaworowski 	bus_dmamap_sync(sc->mge_tx_dtag, mapp, BUS_DMASYNC_PREWRITE);
16799f55f5f5SRafal Jaworowski 
16809f55f5f5SRafal Jaworowski 	/* Everything is ok, now we can send buffers */
16819f55f5f5SRafal Jaworowski 	for (seg = 0; seg < nsegs; seg++) {
16829f55f5f5SRafal Jaworowski 		dw->mge_desc->byte_count = segs[seg].ds_len;
16839f55f5f5SRafal Jaworowski 		dw->mge_desc->buffer = segs[seg].ds_addr;
16849f55f5f5SRafal Jaworowski 		dw->buffer = m0;
168575f1438bSOleksandr Tymoshenko 		dw->mge_desc->cmd_status = 0;
16869f55f5f5SRafal Jaworowski 		if (seg == 0)
16879f55f5f5SRafal Jaworowski 			mge_offload_setup_descriptor(sc, dw);
168875f1438bSOleksandr Tymoshenko 		dw->mge_desc->cmd_status |= MGE_TX_LAST | MGE_TX_FIRST |
168975f1438bSOleksandr Tymoshenko 		    MGE_TX_ETH_CRC | MGE_TX_EN_INT | MGE_TX_PADDING |
169075f1438bSOleksandr Tymoshenko 		    MGE_DMA_OWNED;
16919f55f5f5SRafal Jaworowski 	}
16929f55f5f5SRafal Jaworowski 
1693d6bdd318SRafal Jaworowski 	bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
16949f55f5f5SRafal Jaworowski 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
16959f55f5f5SRafal Jaworowski 
16969f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = (++sc->tx_desc_curr) % MGE_TX_DESC_NUM;
16979f55f5f5SRafal Jaworowski 	sc->tx_desc_used_count++;
16989f55f5f5SRafal Jaworowski 	return (0);
16999f55f5f5SRafal Jaworowski }
17009f55f5f5SRafal Jaworowski 
17019f55f5f5SRafal Jaworowski static void
17029f55f5f5SRafal Jaworowski mge_tick(void *msc)
17039f55f5f5SRafal Jaworowski {
17049f55f5f5SRafal Jaworowski 	struct mge_softc *sc = msc;
17059f55f5f5SRafal Jaworowski 
17063c71b84fSZbigniew Bodek 	KASSERT(sc->phy_attached == 1, ("mge_tick while PHY not attached"));
17073c71b84fSZbigniew Bodek 
17083c71b84fSZbigniew Bodek 	MGE_GLOBAL_LOCK(sc);
17093c71b84fSZbigniew Bodek 
17109f55f5f5SRafal Jaworowski 	/* Check for TX timeout */
17119f55f5f5SRafal Jaworowski 	mge_watchdog(sc);
17129f55f5f5SRafal Jaworowski 
17139f55f5f5SRafal Jaworowski 	mii_tick(sc->mii);
17149f55f5f5SRafal Jaworowski 
17159f55f5f5SRafal Jaworowski 	/* Check for media type change */
17169f55f5f5SRafal Jaworowski 	if(sc->mge_media_status != sc->mii->mii_media.ifm_media)
17179f55f5f5SRafal Jaworowski 		mge_ifmedia_upd(sc->ifp);
17189f55f5f5SRafal Jaworowski 
17193c71b84fSZbigniew Bodek 	MGE_GLOBAL_UNLOCK(sc);
17203c71b84fSZbigniew Bodek 
17219f55f5f5SRafal Jaworowski 	/* Schedule another timeout one second from now */
17229f55f5f5SRafal Jaworowski 	callout_reset(&sc->wd_callout, hz, mge_tick, sc);
17233c71b84fSZbigniew Bodek 
17243c71b84fSZbigniew Bodek 	return;
17259f55f5f5SRafal Jaworowski }
17269f55f5f5SRafal Jaworowski 
17279f55f5f5SRafal Jaworowski static void
17289f55f5f5SRafal Jaworowski mge_watchdog(struct mge_softc *sc)
17299f55f5f5SRafal Jaworowski {
17309f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
17319f55f5f5SRafal Jaworowski 
17329f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
17339f55f5f5SRafal Jaworowski 
17349f55f5f5SRafal Jaworowski 	if (sc->wd_timer == 0 || --sc->wd_timer) {
17359f55f5f5SRafal Jaworowski 		return;
17369f55f5f5SRafal Jaworowski 	}
17379f55f5f5SRafal Jaworowski 
1738c8dfaf38SGleb Smirnoff 	if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
17399f55f5f5SRafal Jaworowski 	if_printf(ifp, "watchdog timeout\n");
17409f55f5f5SRafal Jaworowski 
17419f55f5f5SRafal Jaworowski 	mge_stop(sc);
17429f55f5f5SRafal Jaworowski 	mge_init_locked(sc);
17439f55f5f5SRafal Jaworowski }
17449f55f5f5SRafal Jaworowski 
17459f55f5f5SRafal Jaworowski static void
17469f55f5f5SRafal Jaworowski mge_start(struct ifnet *ifp)
17479f55f5f5SRafal Jaworowski {
17489f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
17499f55f5f5SRafal Jaworowski 
17509f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK(sc);
17519f55f5f5SRafal Jaworowski 
17529f55f5f5SRafal Jaworowski 	mge_start_locked(ifp);
17539f55f5f5SRafal Jaworowski 
17549f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_UNLOCK(sc);
17559f55f5f5SRafal Jaworowski }
17569f55f5f5SRafal Jaworowski 
17579f55f5f5SRafal Jaworowski static void
17589f55f5f5SRafal Jaworowski mge_start_locked(struct ifnet *ifp)
17599f55f5f5SRafal Jaworowski {
17609f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
17619f55f5f5SRafal Jaworowski 	struct mbuf *m0, *mtmp;
17629f55f5f5SRafal Jaworowski 	uint32_t reg_val, queued = 0;
17639f55f5f5SRafal Jaworowski 
17649f55f5f5SRafal Jaworowski 	sc = ifp->if_softc;
17659f55f5f5SRafal Jaworowski 
17669f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK_ASSERT(sc);
17679f55f5f5SRafal Jaworowski 
17689f55f5f5SRafal Jaworowski 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
17699f55f5f5SRafal Jaworowski 	    IFF_DRV_RUNNING)
17709f55f5f5SRafal Jaworowski 		return;
17719f55f5f5SRafal Jaworowski 
17729f55f5f5SRafal Jaworowski 	for (;;) {
17739f55f5f5SRafal Jaworowski 		/* Get packet from the queue */
17749f55f5f5SRafal Jaworowski 		IF_DEQUEUE(&ifp->if_snd, m0);
17759f55f5f5SRafal Jaworowski 		if (m0 == NULL)
17769f55f5f5SRafal Jaworowski 			break;
17779f55f5f5SRafal Jaworowski 
1778b8fad6c0SFabien Thomas 		if (m0->m_pkthdr.csum_flags & (CSUM_IP|CSUM_TCP|CSUM_UDP) ||
1779b8fad6c0SFabien Thomas 		    m0->m_flags & M_VLANTAG) {
1780b8fad6c0SFabien Thomas 			if (M_WRITABLE(m0) == 0) {
1781b8fad6c0SFabien Thomas 				mtmp = m_dup(m0, M_NOWAIT);
1782b8fad6c0SFabien Thomas 				m_freem(m0);
1783b8fad6c0SFabien Thomas 				if (mtmp == NULL)
1784b8fad6c0SFabien Thomas 					continue;
1785b8fad6c0SFabien Thomas 				m0 = mtmp;
1786b8fad6c0SFabien Thomas 			}
1787b8fad6c0SFabien Thomas 		}
1788b8fad6c0SFabien Thomas 		/* The driver support only one DMA fragment. */
1789b8fad6c0SFabien Thomas 		if (m0->m_next != NULL) {
1790c6499eccSGleb Smirnoff 			mtmp = m_defrag(m0, M_NOWAIT);
17914ac30cc1SZbigniew Bodek 			if (mtmp != NULL)
17929f55f5f5SRafal Jaworowski 				m0 = mtmp;
1793b8fad6c0SFabien Thomas 		}
17949f55f5f5SRafal Jaworowski 
1795b8fad6c0SFabien Thomas 		/* Check for free descriptors */
1796b8fad6c0SFabien Thomas 		if (sc->tx_desc_used_count + 1 >= MGE_TX_DESC_NUM) {
17979f55f5f5SRafal Jaworowski 			IF_PREPEND(&ifp->if_snd, m0);
17989f55f5f5SRafal Jaworowski 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
17999f55f5f5SRafal Jaworowski 			break;
18009f55f5f5SRafal Jaworowski 		}
1801b8fad6c0SFabien Thomas 
1802b8fad6c0SFabien Thomas 		if (mge_encap(sc, m0) != 0)
1803b8fad6c0SFabien Thomas 			break;
1804b8fad6c0SFabien Thomas 
18059f55f5f5SRafal Jaworowski 		queued++;
18069f55f5f5SRafal Jaworowski 		BPF_MTAP(ifp, m0);
18079f55f5f5SRafal Jaworowski 	}
18089f55f5f5SRafal Jaworowski 
18099f55f5f5SRafal Jaworowski 	if (queued) {
18109f55f5f5SRafal Jaworowski 		/* Enable transmitter and watchdog timer */
18119f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD);
18129f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_ENABLE_TXQ);
18139f55f5f5SRafal Jaworowski 		sc->wd_timer = 5;
18149f55f5f5SRafal Jaworowski 	}
18159f55f5f5SRafal Jaworowski }
18169f55f5f5SRafal Jaworowski 
18179f55f5f5SRafal Jaworowski static void
18189f55f5f5SRafal Jaworowski mge_stop(struct mge_softc *sc)
18199f55f5f5SRafal Jaworowski {
18209f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
18219f55f5f5SRafal Jaworowski 	volatile uint32_t reg_val, status;
18229f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
18239f55f5f5SRafal Jaworowski 	struct mge_desc *desc;
18249f55f5f5SRafal Jaworowski 	int count;
18259f55f5f5SRafal Jaworowski 
18269f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
18279f55f5f5SRafal Jaworowski 
18289f55f5f5SRafal Jaworowski 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
18299f55f5f5SRafal Jaworowski 		return;
18309f55f5f5SRafal Jaworowski 
18319f55f5f5SRafal Jaworowski 	/* Stop tick engine */
18329f55f5f5SRafal Jaworowski 	callout_stop(&sc->wd_callout);
18339f55f5f5SRafal Jaworowski 
18349f55f5f5SRafal Jaworowski 	/* Disable interface */
18359f55f5f5SRafal Jaworowski 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
18369f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
18379f55f5f5SRafal Jaworowski 
18389f55f5f5SRafal Jaworowski 	/* Disable interrupts */
18399f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 0);
18409f55f5f5SRafal Jaworowski 
18419f55f5f5SRafal Jaworowski 	/* Disable Rx and Tx */
18429f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD);
18439f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_DISABLE_TXQ);
18449f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_DISABLE_RXQ_ALL);
18459f55f5f5SRafal Jaworowski 
18469f55f5f5SRafal Jaworowski 	/* Remove pending data from TX queue */
18475817716fSRafal Jaworowski 	while (sc->tx_desc_used_idx != sc->tx_desc_curr &&
18485817716fSRafal Jaworowski 	    sc->tx_desc_used_count) {
18499f55f5f5SRafal Jaworowski 		/* Get the descriptor */
18509f55f5f5SRafal Jaworowski 		dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
18519f55f5f5SRafal Jaworowski 		desc = dw->mge_desc;
18529f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
18539f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
18549f55f5f5SRafal Jaworowski 
18559f55f5f5SRafal Jaworowski 		/* Get descriptor status */
18569f55f5f5SRafal Jaworowski 		status = desc->cmd_status;
18579f55f5f5SRafal Jaworowski 
18589f55f5f5SRafal Jaworowski 		if (status & MGE_DMA_OWNED)
18599f55f5f5SRafal Jaworowski 			break;
18609f55f5f5SRafal Jaworowski 
18619f55f5f5SRafal Jaworowski 		sc->tx_desc_used_idx = (++sc->tx_desc_used_idx) %
18629f55f5f5SRafal Jaworowski 		    MGE_TX_DESC_NUM;
18635817716fSRafal Jaworowski 		sc->tx_desc_used_count--;
18649f55f5f5SRafal Jaworowski 
18659f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
18669f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTWRITE);
18679f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap);
18689f55f5f5SRafal Jaworowski 
18699f55f5f5SRafal Jaworowski 		m_freem(dw->buffer);
18709f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
18719f55f5f5SRafal Jaworowski 	}
18729f55f5f5SRafal Jaworowski 
18739f55f5f5SRafal Jaworowski 	/* Wait for end of transmission */
18749f55f5f5SRafal Jaworowski 	count = 0x100000;
18759f55f5f5SRafal Jaworowski 	while (count--) {
18769f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_PORT_STATUS);
18779f55f5f5SRafal Jaworowski 		if ( !(reg_val & MGE_STATUS_TX_IN_PROG) &&
18789f55f5f5SRafal Jaworowski 		    (reg_val & MGE_STATUS_TX_FIFO_EMPTY))
18799f55f5f5SRafal Jaworowski 			break;
18809f55f5f5SRafal Jaworowski 		DELAY(100);
18819f55f5f5SRafal Jaworowski 	}
18829f55f5f5SRafal Jaworowski 
18834ac30cc1SZbigniew Bodek 	if (count == 0)
18844ac30cc1SZbigniew Bodek 		if_printf(ifp,
18854ac30cc1SZbigniew Bodek 		    "%s: timeout while waiting for end of transmission\n",
18869f55f5f5SRafal Jaworowski 		    __FUNCTION__);
18879f55f5f5SRafal Jaworowski 
18889f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL);
18899f55f5f5SRafal Jaworowski 	reg_val &= ~(PORT_SERIAL_ENABLE);
18909f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL ,reg_val);
18919f55f5f5SRafal Jaworowski }
18929f55f5f5SRafal Jaworowski 
18939f55f5f5SRafal Jaworowski static int
18949f55f5f5SRafal Jaworowski mge_suspend(device_t dev)
18959f55f5f5SRafal Jaworowski {
18969f55f5f5SRafal Jaworowski 
18979f55f5f5SRafal Jaworowski 	device_printf(dev, "%s\n", __FUNCTION__);
18989f55f5f5SRafal Jaworowski 	return (0);
18999f55f5f5SRafal Jaworowski }
19009f55f5f5SRafal Jaworowski 
19019f55f5f5SRafal Jaworowski static void
19029f55f5f5SRafal Jaworowski mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame,
19039f55f5f5SRafal Jaworowski     uint32_t status, uint16_t bufsize)
19049f55f5f5SRafal Jaworowski {
19059f55f5f5SRafal Jaworowski 	int csum_flags = 0;
19069f55f5f5SRafal Jaworowski 
19079f55f5f5SRafal Jaworowski 	if (ifp->if_capenable & IFCAP_RXCSUM) {
19089f55f5f5SRafal Jaworowski 		if ((status & MGE_RX_L3_IS_IP) && (status & MGE_RX_IP_OK))
19099f55f5f5SRafal Jaworowski 			csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID;
19109f55f5f5SRafal Jaworowski 
19119f55f5f5SRafal Jaworowski 		if ((bufsize & MGE_RX_IP_FRAGMENT) == 0 &&
19129f55f5f5SRafal Jaworowski 		    (MGE_RX_L4_IS_TCP(status) || MGE_RX_L4_IS_UDP(status)) &&
19139f55f5f5SRafal Jaworowski 		    (status & MGE_RX_L4_CSUM_OK)) {
19149f55f5f5SRafal Jaworowski 			csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
19159f55f5f5SRafal Jaworowski 			frame->m_pkthdr.csum_data = 0xFFFF;
19169f55f5f5SRafal Jaworowski 		}
19179f55f5f5SRafal Jaworowski 
19189f55f5f5SRafal Jaworowski 		frame->m_pkthdr.csum_flags = csum_flags;
19199f55f5f5SRafal Jaworowski 	}
19209f55f5f5SRafal Jaworowski }
19219f55f5f5SRafal Jaworowski 
19229f55f5f5SRafal Jaworowski static void
19239f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(struct mge_softc *sc, struct mge_desc_wrapper *dw)
19249f55f5f5SRafal Jaworowski {
19259f55f5f5SRafal Jaworowski 	struct mbuf *m0 = dw->buffer;
19269f55f5f5SRafal Jaworowski 	struct ether_vlan_header *eh = mtod(m0, struct ether_vlan_header *);
19279f55f5f5SRafal Jaworowski 	int csum_flags = m0->m_pkthdr.csum_flags;
19289f55f5f5SRafal Jaworowski 	int cmd_status = 0;
19299f55f5f5SRafal Jaworowski 	struct ip *ip;
19309f55f5f5SRafal Jaworowski 	int ehlen, etype;
19319f55f5f5SRafal Jaworowski 
19324ac30cc1SZbigniew Bodek 	if (csum_flags != 0) {
19339f55f5f5SRafal Jaworowski 		if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
19349f55f5f5SRafal Jaworowski 			etype = ntohs(eh->evl_proto);
19359f55f5f5SRafal Jaworowski 			ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
19369f55f5f5SRafal Jaworowski 			csum_flags |= MGE_TX_VLAN_TAGGED;
19379f55f5f5SRafal Jaworowski 		} else {
19389f55f5f5SRafal Jaworowski 			etype = ntohs(eh->evl_encap_proto);
19399f55f5f5SRafal Jaworowski 			ehlen = ETHER_HDR_LEN;
19409f55f5f5SRafal Jaworowski 		}
19419f55f5f5SRafal Jaworowski 
19429f55f5f5SRafal Jaworowski 		if (etype != ETHERTYPE_IP) {
19439f55f5f5SRafal Jaworowski 			if_printf(sc->ifp,
19449f55f5f5SRafal Jaworowski 			    "TCP/IP Offload enabled for unsupported "
19459f55f5f5SRafal Jaworowski 			    "protocol!\n");
19469f55f5f5SRafal Jaworowski 			return;
19479f55f5f5SRafal Jaworowski 		}
19489f55f5f5SRafal Jaworowski 
19499f55f5f5SRafal Jaworowski 		ip = (struct ip *)(m0->m_data + ehlen);
19509f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_IP_HDR_SIZE(ip->ip_hl);
19519f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_NOT_FRAGMENT;
19529f55f5f5SRafal Jaworowski 	}
19539f55f5f5SRafal Jaworowski 
19549f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_IP)
19559f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_IP_CSUM;
19569f55f5f5SRafal Jaworowski 
19579f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_TCP)
19589f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_L4_CSUM;
19599f55f5f5SRafal Jaworowski 
19609f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_UDP)
19619f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_L4_CSUM | MGE_TX_UDP;
19629f55f5f5SRafal Jaworowski 
19639f55f5f5SRafal Jaworowski 	dw->mge_desc->cmd_status |= cmd_status;
19649f55f5f5SRafal Jaworowski }
19659f55f5f5SRafal Jaworowski 
19669f55f5f5SRafal Jaworowski static void
19679f55f5f5SRafal Jaworowski mge_intrs_ctrl(struct mge_softc *sc, int enable)
19689f55f5f5SRafal Jaworowski {
19699f55f5f5SRafal Jaworowski 
19709f55f5f5SRafal Jaworowski 	if (enable) {
19719f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK , MGE_PORT_INT_RXQ0 |
19729f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXTEND | MGE_PORT_INT_RXERRQ0);
19739f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT , MGE_PORT_INT_EXT_TXERR0 |
19749f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXT_RXOR | MGE_PORT_INT_EXT_TXUR |
19759f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXT_TXBUF0);
19769f55f5f5SRafal Jaworowski 	} else {
19779f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_INT_CAUSE, 0x0);
19789f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_INT_MASK, 0x0);
19799f55f5f5SRafal Jaworowski 
19809f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE, 0x0);
19819f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, 0x0);
19829f55f5f5SRafal Jaworowski 
19839f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK, 0x0);
19849f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT, 0x0);
19859f55f5f5SRafal Jaworowski 	}
19869f55f5f5SRafal Jaworowski }
19879f55f5f5SRafal Jaworowski 
19889f55f5f5SRafal Jaworowski static uint8_t
19899f55f5f5SRafal Jaworowski mge_crc8(uint8_t *data, int size)
19909f55f5f5SRafal Jaworowski {
19919f55f5f5SRafal Jaworowski 	uint8_t crc = 0;
19929f55f5f5SRafal Jaworowski 	static const uint8_t ct[256] = {
19939f55f5f5SRafal Jaworowski 		0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
19949f55f5f5SRafal Jaworowski 		0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
19959f55f5f5SRafal Jaworowski 		0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
19969f55f5f5SRafal Jaworowski 		0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
19979f55f5f5SRafal Jaworowski 		0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
19989f55f5f5SRafal Jaworowski 		0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
19999f55f5f5SRafal Jaworowski 		0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
20009f55f5f5SRafal Jaworowski 		0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
20019f55f5f5SRafal Jaworowski 		0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
20029f55f5f5SRafal Jaworowski 		0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
20039f55f5f5SRafal Jaworowski 		0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
20049f55f5f5SRafal Jaworowski 		0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
20059f55f5f5SRafal Jaworowski 		0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
20069f55f5f5SRafal Jaworowski 		0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
20079f55f5f5SRafal Jaworowski 		0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
20089f55f5f5SRafal Jaworowski 		0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
20099f55f5f5SRafal Jaworowski 		0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
20109f55f5f5SRafal Jaworowski 		0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
20119f55f5f5SRafal Jaworowski 		0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
20129f55f5f5SRafal Jaworowski 		0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
20139f55f5f5SRafal Jaworowski 		0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
20149f55f5f5SRafal Jaworowski 		0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
20159f55f5f5SRafal Jaworowski 		0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
20169f55f5f5SRafal Jaworowski 		0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
20179f55f5f5SRafal Jaworowski 		0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
20189f55f5f5SRafal Jaworowski 		0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
20199f55f5f5SRafal Jaworowski 		0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
20209f55f5f5SRafal Jaworowski 		0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
20219f55f5f5SRafal Jaworowski 		0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
20229f55f5f5SRafal Jaworowski 		0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
20239f55f5f5SRafal Jaworowski 		0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
20249f55f5f5SRafal Jaworowski 		0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
20259f55f5f5SRafal Jaworowski 	};
20269f55f5f5SRafal Jaworowski 
20279f55f5f5SRafal Jaworowski 	while(size--)
20289f55f5f5SRafal Jaworowski 		crc = ct[crc ^ *(data++)];
20299f55f5f5SRafal Jaworowski 
20309f55f5f5SRafal Jaworowski 	return(crc);
20319f55f5f5SRafal Jaworowski }
20329f55f5f5SRafal Jaworowski 
20339f55f5f5SRafal Jaworowski static void
20349f55f5f5SRafal Jaworowski mge_setup_multicast(struct mge_softc *sc)
20359f55f5f5SRafal Jaworowski {
20369f55f5f5SRafal Jaworowski 	uint8_t special[5] = { 0x01, 0x00, 0x5E, 0x00, 0x00 };
20379f55f5f5SRafal Jaworowski 	uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1;
20389f55f5f5SRafal Jaworowski 	uint32_t smt[MGE_MCAST_REG_NUMBER];
20399f55f5f5SRafal Jaworowski 	uint32_t omt[MGE_MCAST_REG_NUMBER];
20409f55f5f5SRafal Jaworowski 	struct ifnet *ifp = sc->ifp;
20419f55f5f5SRafal Jaworowski 	struct ifmultiaddr *ifma;
20429f55f5f5SRafal Jaworowski 	uint8_t *mac;
20439f55f5f5SRafal Jaworowski 	int i;
20449f55f5f5SRafal Jaworowski 
20459f55f5f5SRafal Jaworowski 	if (ifp->if_flags & IFF_ALLMULTI) {
20469f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++)
20479f55f5f5SRafal Jaworowski 			smt[i] = omt[i] = (v << 24) | (v << 16) | (v << 8) | v;
20489f55f5f5SRafal Jaworowski 	} else {
20499f55f5f5SRafal Jaworowski 		memset(smt, 0, sizeof(smt));
20509f55f5f5SRafal Jaworowski 		memset(omt, 0, sizeof(omt));
20519f55f5f5SRafal Jaworowski 
2052eb956cd0SRobert Watson 		if_maddr_rlock(ifp);
20539f55f5f5SRafal Jaworowski 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
20549f55f5f5SRafal Jaworowski 			if (ifma->ifma_addr->sa_family != AF_LINK)
20559f55f5f5SRafal Jaworowski 				continue;
20569f55f5f5SRafal Jaworowski 
20579f55f5f5SRafal Jaworowski 			mac = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
20589f55f5f5SRafal Jaworowski 			if (memcmp(mac, special, sizeof(special)) == 0) {
20599f55f5f5SRafal Jaworowski 				i = mac[5];
20609f55f5f5SRafal Jaworowski 				smt[i >> 2] |= v << ((i & 0x03) << 3);
20619f55f5f5SRafal Jaworowski 			} else {
20629f55f5f5SRafal Jaworowski 				i = mge_crc8(mac, ETHER_ADDR_LEN);
20639f55f5f5SRafal Jaworowski 				omt[i >> 2] |= v << ((i & 0x03) << 3);
20649f55f5f5SRafal Jaworowski 			}
20659f55f5f5SRafal Jaworowski 		}
2066eb956cd0SRobert Watson 		if_maddr_runlock(ifp);
20679f55f5f5SRafal Jaworowski 	}
20689f55f5f5SRafal Jaworowski 
20699f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
20709f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), smt[i]);
20719f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), omt[i]);
20729f55f5f5SRafal Jaworowski 	}
20739f55f5f5SRafal Jaworowski }
20749f55f5f5SRafal Jaworowski 
20759f55f5f5SRafal Jaworowski static void
20769f55f5f5SRafal Jaworowski mge_set_rxic(struct mge_softc *sc)
20779f55f5f5SRafal Jaworowski {
20789f55f5f5SRafal Jaworowski 	uint32_t reg;
20799f55f5f5SRafal Jaworowski 
20808e1dc58eSRafal Jaworowski 	if (sc->rx_ic_time > sc->mge_rx_ipg_max)
20818e1dc58eSRafal Jaworowski 		sc->rx_ic_time = sc->mge_rx_ipg_max;
20829f55f5f5SRafal Jaworowski 
20839f55f5f5SRafal Jaworowski 	reg = MGE_READ(sc, MGE_SDMA_CONFIG);
20848e1dc58eSRafal Jaworowski 	reg &= ~mge_rx_ipg(sc->mge_rx_ipg_max, sc->mge_ver);
20858e1dc58eSRafal Jaworowski 	reg |= mge_rx_ipg(sc->rx_ic_time, sc->mge_ver);
20869f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_SDMA_CONFIG, reg);
20879f55f5f5SRafal Jaworowski }
20889f55f5f5SRafal Jaworowski 
20899f55f5f5SRafal Jaworowski static void
20909f55f5f5SRafal Jaworowski mge_set_txic(struct mge_softc *sc)
20919f55f5f5SRafal Jaworowski {
20929f55f5f5SRafal Jaworowski 	uint32_t reg;
20939f55f5f5SRafal Jaworowski 
20948e1dc58eSRafal Jaworowski 	if (sc->tx_ic_time > sc->mge_tfut_ipg_max)
20958e1dc58eSRafal Jaworowski 		sc->tx_ic_time = sc->mge_tfut_ipg_max;
20969f55f5f5SRafal Jaworowski 
20979f55f5f5SRafal Jaworowski 	reg = MGE_READ(sc, MGE_TX_FIFO_URGENT_TRSH);
20988e1dc58eSRafal Jaworowski 	reg &= ~mge_tfut_ipg(sc->mge_tfut_ipg_max, sc->mge_ver);
20998e1dc58eSRafal Jaworowski 	reg |= mge_tfut_ipg(sc->tx_ic_time, sc->mge_ver);
21009f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, reg);
21019f55f5f5SRafal Jaworowski }
21029f55f5f5SRafal Jaworowski 
21039f55f5f5SRafal Jaworowski static int
21049f55f5f5SRafal Jaworowski mge_sysctl_ic(SYSCTL_HANDLER_ARGS)
21059f55f5f5SRafal Jaworowski {
21069f55f5f5SRafal Jaworowski 	struct mge_softc *sc = (struct mge_softc *)arg1;
21078e1dc58eSRafal Jaworowski 	uint32_t time;
21089f55f5f5SRafal Jaworowski 	int error;
21099f55f5f5SRafal Jaworowski 
21108e1dc58eSRafal Jaworowski 	time = (arg2 == MGE_IC_RX) ? sc->rx_ic_time : sc->tx_ic_time;
21119f55f5f5SRafal Jaworowski 	error = sysctl_handle_int(oidp, &time, 0, req);
21129f55f5f5SRafal Jaworowski 	if (error != 0)
21139f55f5f5SRafal Jaworowski 		return(error);
21149f55f5f5SRafal Jaworowski 
21159f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
21169f55f5f5SRafal Jaworowski 	if (arg2 == MGE_IC_RX) {
21179f55f5f5SRafal Jaworowski 		sc->rx_ic_time = time;
21189f55f5f5SRafal Jaworowski 		mge_set_rxic(sc);
21199f55f5f5SRafal Jaworowski 	} else {
21209f55f5f5SRafal Jaworowski 		sc->tx_ic_time = time;
21219f55f5f5SRafal Jaworowski 		mge_set_txic(sc);
21229f55f5f5SRafal Jaworowski 	}
21239f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
21249f55f5f5SRafal Jaworowski 
21259f55f5f5SRafal Jaworowski 	return(0);
21269f55f5f5SRafal Jaworowski }
21279f55f5f5SRafal Jaworowski 
21289f55f5f5SRafal Jaworowski static void
21299f55f5f5SRafal Jaworowski mge_add_sysctls(struct mge_softc *sc)
21309f55f5f5SRafal Jaworowski {
21319f55f5f5SRafal Jaworowski 	struct sysctl_ctx_list *ctx;
21329f55f5f5SRafal Jaworowski 	struct sysctl_oid_list *children;
21339f55f5f5SRafal Jaworowski 	struct sysctl_oid *tree;
21349f55f5f5SRafal Jaworowski 
21359f55f5f5SRafal Jaworowski 	ctx = device_get_sysctl_ctx(sc->dev);
21369f55f5f5SRafal Jaworowski 	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
21379f55f5f5SRafal Jaworowski 	tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "int_coal",
21389f55f5f5SRafal Jaworowski 	    CTLFLAG_RD, 0, "MGE Interrupts coalescing");
21399f55f5f5SRafal Jaworowski 	children = SYSCTL_CHILDREN(tree);
21409f55f5f5SRafal Jaworowski 
21419f55f5f5SRafal Jaworowski 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_time",
21429f55f5f5SRafal Jaworowski 	    CTLTYPE_UINT | CTLFLAG_RW, sc, MGE_IC_RX, mge_sysctl_ic,
21439f55f5f5SRafal Jaworowski 	    "I", "IC RX time threshold");
21449f55f5f5SRafal Jaworowski 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_time",
21459f55f5f5SRafal Jaworowski 	    CTLTYPE_UINT | CTLFLAG_RW, sc, MGE_IC_TX, mge_sysctl_ic,
21469f55f5f5SRafal Jaworowski 	    "I", "IC TX time threshold");
21479f55f5f5SRafal Jaworowski }
21483c71b84fSZbigniew Bodek 
21493c71b84fSZbigniew Bodek static int
21503c71b84fSZbigniew Bodek mge_mdio_writereg(device_t dev, int phy, int reg, int value)
21513c71b84fSZbigniew Bodek {
21523c71b84fSZbigniew Bodek 
21533c71b84fSZbigniew Bodek 	mv_write_ge_smi(dev, phy, reg, value);
21543c71b84fSZbigniew Bodek 
21553c71b84fSZbigniew Bodek 	return (0);
21563c71b84fSZbigniew Bodek }
21573c71b84fSZbigniew Bodek 
21583c71b84fSZbigniew Bodek 
21593c71b84fSZbigniew Bodek static int
21603c71b84fSZbigniew Bodek mge_mdio_readreg(device_t dev, int phy, int reg)
21613c71b84fSZbigniew Bodek {
21623c71b84fSZbigniew Bodek 	int ret;
21633c71b84fSZbigniew Bodek 
21643c71b84fSZbigniew Bodek 	ret = mv_read_ge_smi(dev, phy, reg);
21653c71b84fSZbigniew Bodek 
21663c71b84fSZbigniew Bodek 	return (ret);
21673c71b84fSZbigniew Bodek }
2168