xref: /freebsd/sys/dev/mge/if_mge.c (revision b1603638e38b3d8c23da6599e389db9a9218c240)
19f55f5f5SRafal Jaworowski /*-
27282444bSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
37282444bSPedro F. Giffuni  *
49f55f5f5SRafal Jaworowski  * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
53c71b84fSZbigniew Bodek  * Copyright (C) 2009-2015 Semihalf
63c71b84fSZbigniew Bodek  * Copyright (C) 2015 Stormshield
79f55f5f5SRafal Jaworowski  * All rights reserved.
89f55f5f5SRafal Jaworowski  *
99f55f5f5SRafal Jaworowski  * Developed by Semihalf.
109f55f5f5SRafal Jaworowski  *
119f55f5f5SRafal Jaworowski  * Redistribution and use in source and binary forms, with or without
129f55f5f5SRafal Jaworowski  * modification, are permitted provided that the following conditions
139f55f5f5SRafal Jaworowski  * are met:
149f55f5f5SRafal Jaworowski  * 1. Redistributions of source code must retain the above copyright
159f55f5f5SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer.
169f55f5f5SRafal Jaworowski  * 2. Redistributions in binary form must reproduce the above copyright
179f55f5f5SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer in the
189f55f5f5SRafal Jaworowski  *    documentation and/or other materials provided with the distribution.
199f55f5f5SRafal Jaworowski  * 3. Neither the name of MARVELL nor the names of contributors
209f55f5f5SRafal Jaworowski  *    may be used to endorse or promote products derived from this software
219f55f5f5SRafal Jaworowski  *    without specific prior written permission.
229f55f5f5SRafal Jaworowski  *
239f55f5f5SRafal Jaworowski  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
249f55f5f5SRafal Jaworowski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
259f55f5f5SRafal Jaworowski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
269f55f5f5SRafal Jaworowski  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
279f55f5f5SRafal Jaworowski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
289f55f5f5SRafal Jaworowski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
299f55f5f5SRafal Jaworowski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
309f55f5f5SRafal Jaworowski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
319f55f5f5SRafal Jaworowski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
329f55f5f5SRafal Jaworowski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
339f55f5f5SRafal Jaworowski  * SUCH DAMAGE.
349f55f5f5SRafal Jaworowski  */
359f55f5f5SRafal Jaworowski 
369f55f5f5SRafal Jaworowski #ifdef HAVE_KERNEL_OPTION_HEADERS
379f55f5f5SRafal Jaworowski #include "opt_device_polling.h"
389f55f5f5SRafal Jaworowski #endif
399f55f5f5SRafal Jaworowski 
409f55f5f5SRafal Jaworowski #include <sys/cdefs.h>
419f55f5f5SRafal Jaworowski __FBSDID("$FreeBSD$");
429f55f5f5SRafal Jaworowski 
439f55f5f5SRafal Jaworowski #include <sys/param.h>
449f55f5f5SRafal Jaworowski #include <sys/systm.h>
459f55f5f5SRafal Jaworowski #include <sys/endian.h>
469f55f5f5SRafal Jaworowski #include <sys/mbuf.h>
479f55f5f5SRafal Jaworowski #include <sys/lock.h>
489f55f5f5SRafal Jaworowski #include <sys/mutex.h>
499f55f5f5SRafal Jaworowski #include <sys/kernel.h>
509f55f5f5SRafal Jaworowski #include <sys/module.h>
519f55f5f5SRafal Jaworowski #include <sys/socket.h>
529f55f5f5SRafal Jaworowski #include <sys/sysctl.h>
539f55f5f5SRafal Jaworowski 
549f55f5f5SRafal Jaworowski #include <net/ethernet.h>
559f55f5f5SRafal Jaworowski #include <net/bpf.h>
569f55f5f5SRafal Jaworowski #include <net/if.h>
579f55f5f5SRafal Jaworowski #include <net/if_arp.h>
589f55f5f5SRafal Jaworowski #include <net/if_dl.h>
599f55f5f5SRafal Jaworowski #include <net/if_media.h>
609f55f5f5SRafal Jaworowski #include <net/if_types.h>
619f55f5f5SRafal Jaworowski #include <net/if_vlan_var.h>
629f55f5f5SRafal Jaworowski 
639f55f5f5SRafal Jaworowski #include <netinet/in_systm.h>
649f55f5f5SRafal Jaworowski #include <netinet/in.h>
659f55f5f5SRafal Jaworowski #include <netinet/ip.h>
669f55f5f5SRafal Jaworowski 
679f55f5f5SRafal Jaworowski #include <sys/sockio.h>
689f55f5f5SRafal Jaworowski #include <sys/bus.h>
699f55f5f5SRafal Jaworowski #include <machine/bus.h>
709f55f5f5SRafal Jaworowski #include <sys/rman.h>
719f55f5f5SRafal Jaworowski #include <machine/resource.h>
729f55f5f5SRafal Jaworowski 
739f55f5f5SRafal Jaworowski #include <dev/mii/mii.h>
749f55f5f5SRafal Jaworowski #include <dev/mii/miivar.h>
759f55f5f5SRafal Jaworowski 
76db5ef4fcSRafal Jaworowski #include <dev/fdt/fdt_common.h>
77db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus.h>
78db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h>
7971e8eac4SAdrian Chadd #include <dev/mdio/mdio.h>
809f55f5f5SRafal Jaworowski 
819f55f5f5SRafal Jaworowski #include <dev/mge/if_mgevar.h>
829f55f5f5SRafal Jaworowski #include <arm/mv/mvreg.h>
838e1dc58eSRafal Jaworowski #include <arm/mv/mvvar.h>
849f55f5f5SRafal Jaworowski 
859f55f5f5SRafal Jaworowski #include "miibus_if.h"
863c71b84fSZbigniew Bodek #include "mdio_if.h"
873c71b84fSZbigniew Bodek 
883c71b84fSZbigniew Bodek #define	MGE_DELAY(x)	pause("SMI access sleep", (x) / tick_sbt)
899f55f5f5SRafal Jaworowski 
909f55f5f5SRafal Jaworowski static int mge_probe(device_t dev);
919f55f5f5SRafal Jaworowski static int mge_attach(device_t dev);
929f55f5f5SRafal Jaworowski static int mge_detach(device_t dev);
939f55f5f5SRafal Jaworowski static int mge_shutdown(device_t dev);
949f55f5f5SRafal Jaworowski static int mge_suspend(device_t dev);
959f55f5f5SRafal Jaworowski static int mge_resume(device_t dev);
969f55f5f5SRafal Jaworowski 
979f55f5f5SRafal Jaworowski static int mge_miibus_readreg(device_t dev, int phy, int reg);
988e45f0b7SAndriy Gapon static int mge_miibus_writereg(device_t dev, int phy, int reg, int value);
999f55f5f5SRafal Jaworowski 
1003c71b84fSZbigniew Bodek static int mge_mdio_readreg(device_t dev, int phy, int reg);
1013c71b84fSZbigniew Bodek static int mge_mdio_writereg(device_t dev, int phy, int reg, int value);
1023c71b84fSZbigniew Bodek 
1039f55f5f5SRafal Jaworowski static int mge_ifmedia_upd(struct ifnet *ifp);
1049f55f5f5SRafal Jaworowski static void mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
1059f55f5f5SRafal Jaworowski 
1069f55f5f5SRafal Jaworowski static void mge_init(void *arg);
1079f55f5f5SRafal Jaworowski static void mge_init_locked(void *arg);
1089f55f5f5SRafal Jaworowski static void mge_start(struct ifnet *ifp);
1099f55f5f5SRafal Jaworowski static void mge_start_locked(struct ifnet *ifp);
1109f55f5f5SRafal Jaworowski static void mge_watchdog(struct mge_softc *sc);
1119f55f5f5SRafal Jaworowski static int mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
1129f55f5f5SRafal Jaworowski 
1138e1dc58eSRafal Jaworowski static uint32_t mge_tfut_ipg(uint32_t val, int ver);
1148e1dc58eSRafal Jaworowski static uint32_t mge_rx_ipg(uint32_t val, int ver);
1158e1dc58eSRafal Jaworowski static void mge_ver_params(struct mge_softc *sc);
1168e1dc58eSRafal Jaworowski 
1179f55f5f5SRafal Jaworowski static void mge_intrs_ctrl(struct mge_softc *sc, int enable);
11875f1438bSOleksandr Tymoshenko static void mge_intr_rxtx(void *arg);
1199f55f5f5SRafal Jaworowski static void mge_intr_rx(void *arg);
12075f1438bSOleksandr Tymoshenko static void mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause,
12175f1438bSOleksandr Tymoshenko     uint32_t int_cause_ext);
1221abcdbd1SAttilio Rao static int mge_intr_rx_locked(struct mge_softc *sc, int count);
1239f55f5f5SRafal Jaworowski static void mge_intr_tx(void *arg);
1249f55f5f5SRafal Jaworowski static void mge_intr_tx_locked(struct mge_softc *sc);
1259f55f5f5SRafal Jaworowski static void mge_intr_misc(void *arg);
1269f55f5f5SRafal Jaworowski static void mge_intr_sum(void *arg);
1279f55f5f5SRafal Jaworowski static void mge_intr_err(void *arg);
1289f55f5f5SRafal Jaworowski static void mge_stop(struct mge_softc *sc);
1299f55f5f5SRafal Jaworowski static void mge_tick(void *msc);
1309f55f5f5SRafal Jaworowski static uint32_t mge_set_port_serial_control(uint32_t media);
1319f55f5f5SRafal Jaworowski static void mge_get_mac_address(struct mge_softc *sc, uint8_t *addr);
1329f55f5f5SRafal Jaworowski static void mge_set_mac_address(struct mge_softc *sc);
1339f55f5f5SRafal Jaworowski static void mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte,
1349f55f5f5SRafal Jaworowski     uint8_t queue);
1359f55f5f5SRafal Jaworowski static void mge_set_prom_mode(struct mge_softc *sc, uint8_t queue);
1369f55f5f5SRafal Jaworowski static int mge_allocate_dma(struct mge_softc *sc);
1379f55f5f5SRafal Jaworowski static int mge_alloc_desc_dma(struct mge_softc *sc,
1384ac30cc1SZbigniew Bodek     struct mge_desc_wrapper* desc_tab, uint32_t size,
1394ac30cc1SZbigniew Bodek     bus_dma_tag_t *buffer_tag);
1409f55f5f5SRafal Jaworowski static int mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map,
1419f55f5f5SRafal Jaworowski     struct mbuf **mbufp, bus_addr_t *paddr);
1424ac30cc1SZbigniew Bodek static void mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg,
1434ac30cc1SZbigniew Bodek     int error);
1449f55f5f5SRafal Jaworowski static void mge_free_dma(struct mge_softc *sc);
1454ac30cc1SZbigniew Bodek static void mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab,
1464ac30cc1SZbigniew Bodek     uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs);
1479f55f5f5SRafal Jaworowski static void mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame,
1489f55f5f5SRafal Jaworowski     uint32_t status, uint16_t bufsize);
1499f55f5f5SRafal Jaworowski static void mge_offload_setup_descriptor(struct mge_softc *sc,
1509f55f5f5SRafal Jaworowski     struct mge_desc_wrapper *dw);
1519f55f5f5SRafal Jaworowski static uint8_t mge_crc8(uint8_t *data, int size);
1529f55f5f5SRafal Jaworowski static void mge_setup_multicast(struct mge_softc *sc);
1539f55f5f5SRafal Jaworowski static void mge_set_rxic(struct mge_softc *sc);
1549f55f5f5SRafal Jaworowski static void mge_set_txic(struct mge_softc *sc);
1559f55f5f5SRafal Jaworowski static void mge_add_sysctls(struct mge_softc *sc);
1569f55f5f5SRafal Jaworowski static int mge_sysctl_ic(SYSCTL_HANDLER_ARGS);
1579f55f5f5SRafal Jaworowski 
1589f55f5f5SRafal Jaworowski static device_method_t mge_methods[] = {
1599f55f5f5SRafal Jaworowski 	/* Device interface */
1609f55f5f5SRafal Jaworowski 	DEVMETHOD(device_probe,		mge_probe),
1619f55f5f5SRafal Jaworowski 	DEVMETHOD(device_attach,	mge_attach),
1629f55f5f5SRafal Jaworowski 	DEVMETHOD(device_detach,	mge_detach),
1639f55f5f5SRafal Jaworowski 	DEVMETHOD(device_shutdown,	mge_shutdown),
1649f55f5f5SRafal Jaworowski 	DEVMETHOD(device_suspend,	mge_suspend),
1659f55f5f5SRafal Jaworowski 	DEVMETHOD(device_resume,	mge_resume),
1669f55f5f5SRafal Jaworowski 	/* MII interface */
1679f55f5f5SRafal Jaworowski 	DEVMETHOD(miibus_readreg,	mge_miibus_readreg),
1689f55f5f5SRafal Jaworowski 	DEVMETHOD(miibus_writereg,	mge_miibus_writereg),
1693c71b84fSZbigniew Bodek 	/* MDIO interface */
1703c71b84fSZbigniew Bodek 	DEVMETHOD(mdio_readreg,		mge_mdio_readreg),
1713c71b84fSZbigniew Bodek 	DEVMETHOD(mdio_writereg,	mge_mdio_writereg),
1729f55f5f5SRafal Jaworowski 	{ 0, 0 }
1739f55f5f5SRafal Jaworowski };
1749f55f5f5SRafal Jaworowski 
1753c71b84fSZbigniew Bodek DEFINE_CLASS_0(mge, mge_driver, mge_methods, sizeof(struct mge_softc));
1769f55f5f5SRafal Jaworowski 
1779f55f5f5SRafal Jaworowski static devclass_t mge_devclass;
1783c71b84fSZbigniew Bodek static int switch_attached = 0;
1799f55f5f5SRafal Jaworowski 
180db5ef4fcSRafal Jaworowski DRIVER_MODULE(mge, simplebus, mge_driver, mge_devclass, 0, 0);
1819f55f5f5SRafal Jaworowski DRIVER_MODULE(miibus, mge, miibus_driver, miibus_devclass, 0, 0);
1823c71b84fSZbigniew Bodek DRIVER_MODULE(mdio, mge, mdio_driver, mdio_devclass, 0, 0);
1839f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, ether, 1, 1, 1);
1849f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, miibus, 1, 1, 1);
1853c71b84fSZbigniew Bodek MODULE_DEPEND(mge, mdio, 1, 1, 1);
1869f55f5f5SRafal Jaworowski 
1879f55f5f5SRafal Jaworowski static struct resource_spec res_spec[] = {
1889f55f5f5SRafal Jaworowski 	{ SYS_RES_MEMORY, 0, RF_ACTIVE },
1899f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
1909f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE },
1919f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE },
1929f55f5f5SRafal Jaworowski 	{ -1, 0 }
1939f55f5f5SRafal Jaworowski };
1949f55f5f5SRafal Jaworowski 
1959f55f5f5SRafal Jaworowski static struct {
1969f55f5f5SRafal Jaworowski 	driver_intr_t *handler;
1979f55f5f5SRafal Jaworowski 	char * description;
19875f1438bSOleksandr Tymoshenko } mge_intrs[MGE_INTR_COUNT + 1] = {
19975f1438bSOleksandr Tymoshenko 	{ mge_intr_rxtx,"GbE aggregated interrupt" },
2009f55f5f5SRafal Jaworowski 	{ mge_intr_rx,	"GbE receive interrupt" },
2019f55f5f5SRafal Jaworowski 	{ mge_intr_tx,	"GbE transmit interrupt" },
2029f55f5f5SRafal Jaworowski 	{ mge_intr_misc,"GbE misc interrupt" },
2039f55f5f5SRafal Jaworowski 	{ mge_intr_sum,	"GbE summary interrupt" },
2049f55f5f5SRafal Jaworowski 	{ mge_intr_err,	"GbE error interrupt" },
2059f55f5f5SRafal Jaworowski };
2069f55f5f5SRafal Jaworowski 
2073c71b84fSZbigniew Bodek /* SMI access interlock */
2083c71b84fSZbigniew Bodek static struct sx sx_smi;
2093c71b84fSZbigniew Bodek 
2103c71b84fSZbigniew Bodek static uint32_t
2113c71b84fSZbigniew Bodek mv_read_ge_smi(device_t dev, int phy, int reg)
2123c71b84fSZbigniew Bodek {
2133c71b84fSZbigniew Bodek 	uint32_t timeout;
2143c71b84fSZbigniew Bodek 	uint32_t ret;
2153c71b84fSZbigniew Bodek 	struct mge_softc *sc;
2163c71b84fSZbigniew Bodek 
2173c71b84fSZbigniew Bodek 	sc = device_get_softc(dev);
2183c71b84fSZbigniew Bodek 	KASSERT(sc != NULL, ("NULL softc ptr!"));
2193c71b84fSZbigniew Bodek 	timeout = MGE_SMI_WRITE_RETRIES;
2203c71b84fSZbigniew Bodek 
2213c71b84fSZbigniew Bodek 	MGE_SMI_LOCK();
2223c71b84fSZbigniew Bodek 	while (--timeout &&
2233c71b84fSZbigniew Bodek 	    (MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_BUSY))
2243c71b84fSZbigniew Bodek 		MGE_DELAY(MGE_SMI_WRITE_DELAY);
2253c71b84fSZbigniew Bodek 
2263c71b84fSZbigniew Bodek 	if (timeout == 0) {
2273c71b84fSZbigniew Bodek 		device_printf(dev, "SMI write timeout.\n");
2283c71b84fSZbigniew Bodek 		ret = ~0U;
2293c71b84fSZbigniew Bodek 		goto out;
2303c71b84fSZbigniew Bodek 	}
2313c71b84fSZbigniew Bodek 
2323c71b84fSZbigniew Bodek 	MGE_WRITE(sc, MGE_REG_SMI, MGE_SMI_MASK &
2333c71b84fSZbigniew Bodek 	    (MGE_SMI_READ | (reg << 21) | (phy << 16)));
2343c71b84fSZbigniew Bodek 
2353c71b84fSZbigniew Bodek 	/* Wait till finished. */
2363c71b84fSZbigniew Bodek 	timeout = MGE_SMI_WRITE_RETRIES;
2373c71b84fSZbigniew Bodek 	while (--timeout &&
2383c71b84fSZbigniew Bodek 	    !((MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_READVALID)))
2393c71b84fSZbigniew Bodek 		MGE_DELAY(MGE_SMI_WRITE_DELAY);
2403c71b84fSZbigniew Bodek 
2413c71b84fSZbigniew Bodek 	if (timeout == 0) {
2423c71b84fSZbigniew Bodek 		device_printf(dev, "SMI write validation timeout.\n");
2433c71b84fSZbigniew Bodek 		ret = ~0U;
2443c71b84fSZbigniew Bodek 		goto out;
2453c71b84fSZbigniew Bodek 	}
2463c71b84fSZbigniew Bodek 
2473c71b84fSZbigniew Bodek 	/* Wait for the data to update in the SMI register */
2483c71b84fSZbigniew Bodek 	MGE_DELAY(MGE_SMI_DELAY);
2493c71b84fSZbigniew Bodek 	ret = MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_DATA_MASK;
2503c71b84fSZbigniew Bodek 
2513c71b84fSZbigniew Bodek out:
2523c71b84fSZbigniew Bodek 	MGE_SMI_UNLOCK();
2533c71b84fSZbigniew Bodek 	return (ret);
2543c71b84fSZbigniew Bodek 
2553c71b84fSZbigniew Bodek }
2563c71b84fSZbigniew Bodek 
2573c71b84fSZbigniew Bodek static void
2583c71b84fSZbigniew Bodek mv_write_ge_smi(device_t dev, int phy, int reg, uint32_t value)
2593c71b84fSZbigniew Bodek {
2603c71b84fSZbigniew Bodek 	uint32_t timeout;
2613c71b84fSZbigniew Bodek 	struct mge_softc *sc;
2623c71b84fSZbigniew Bodek 
2633c71b84fSZbigniew Bodek 	sc = device_get_softc(dev);
2643c71b84fSZbigniew Bodek 	KASSERT(sc != NULL, ("NULL softc ptr!"));
2653c71b84fSZbigniew Bodek 
2663c71b84fSZbigniew Bodek 	MGE_SMI_LOCK();
2673c71b84fSZbigniew Bodek 	timeout = MGE_SMI_READ_RETRIES;
2683c71b84fSZbigniew Bodek 	while (--timeout &&
2693c71b84fSZbigniew Bodek 	    (MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_BUSY))
2703c71b84fSZbigniew Bodek 		MGE_DELAY(MGE_SMI_READ_DELAY);
2713c71b84fSZbigniew Bodek 
2723c71b84fSZbigniew Bodek 	if (timeout == 0) {
2733c71b84fSZbigniew Bodek 		device_printf(dev, "SMI read timeout.\n");
2743c71b84fSZbigniew Bodek 		goto out;
2753c71b84fSZbigniew Bodek 	}
2763c71b84fSZbigniew Bodek 
2773c71b84fSZbigniew Bodek 	MGE_WRITE(sc, MGE_REG_SMI, MGE_SMI_MASK &
2783c71b84fSZbigniew Bodek 	    (MGE_SMI_WRITE | (reg << 21) | (phy << 16) |
2793c71b84fSZbigniew Bodek 	    (value & MGE_SMI_DATA_MASK)));
2803c71b84fSZbigniew Bodek 
2813c71b84fSZbigniew Bodek out:
2823c71b84fSZbigniew Bodek 	MGE_SMI_UNLOCK();
2833c71b84fSZbigniew Bodek }
2843c71b84fSZbigniew Bodek 
2853c71b84fSZbigniew Bodek static int
2863c71b84fSZbigniew Bodek mv_read_ext_phy(device_t dev, int phy, int reg)
2873c71b84fSZbigniew Bodek {
2883c71b84fSZbigniew Bodek 	uint32_t retries;
2893c71b84fSZbigniew Bodek 	struct mge_softc *sc;
2903c71b84fSZbigniew Bodek 	uint32_t ret;
2913c71b84fSZbigniew Bodek 
2923c71b84fSZbigniew Bodek 	sc = device_get_softc(dev);
2933c71b84fSZbigniew Bodek 
2943c71b84fSZbigniew Bodek 	MGE_SMI_LOCK();
2953c71b84fSZbigniew Bodek 	MGE_WRITE(sc->phy_sc, MGE_REG_SMI, MGE_SMI_MASK &
2963c71b84fSZbigniew Bodek 	    (MGE_SMI_READ | (reg << 21) | (phy << 16)));
2973c71b84fSZbigniew Bodek 
2983c71b84fSZbigniew Bodek 	retries = MGE_SMI_READ_RETRIES;
2993c71b84fSZbigniew Bodek 	while (--retries &&
3003c71b84fSZbigniew Bodek 	    !(MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_READVALID))
3013c71b84fSZbigniew Bodek 		DELAY(MGE_SMI_READ_DELAY);
3023c71b84fSZbigniew Bodek 
3033c71b84fSZbigniew Bodek 	if (retries == 0)
3043c71b84fSZbigniew Bodek 		device_printf(dev, "Timeout while reading from PHY\n");
3053c71b84fSZbigniew Bodek 
3063c71b84fSZbigniew Bodek 	ret = MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_DATA_MASK;
3073c71b84fSZbigniew Bodek 	MGE_SMI_UNLOCK();
3083c71b84fSZbigniew Bodek 
3093c71b84fSZbigniew Bodek 	return (ret);
3103c71b84fSZbigniew Bodek }
3113c71b84fSZbigniew Bodek 
3123c71b84fSZbigniew Bodek static void
3133c71b84fSZbigniew Bodek mv_write_ext_phy(device_t dev, int phy, int reg, int value)
3143c71b84fSZbigniew Bodek {
3153c71b84fSZbigniew Bodek 	uint32_t retries;
3163c71b84fSZbigniew Bodek 	struct mge_softc *sc;
3173c71b84fSZbigniew Bodek 
3183c71b84fSZbigniew Bodek 	sc = device_get_softc(dev);
3193c71b84fSZbigniew Bodek 
3203c71b84fSZbigniew Bodek 	MGE_SMI_LOCK();
3213c71b84fSZbigniew Bodek 	MGE_WRITE(sc->phy_sc, MGE_REG_SMI, MGE_SMI_MASK &
3223c71b84fSZbigniew Bodek 	    (MGE_SMI_WRITE | (reg << 21) | (phy << 16) |
3233c71b84fSZbigniew Bodek 	    (value & MGE_SMI_DATA_MASK)));
3243c71b84fSZbigniew Bodek 
3253c71b84fSZbigniew Bodek 	retries = MGE_SMI_WRITE_RETRIES;
3263c71b84fSZbigniew Bodek 	while (--retries && MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_BUSY)
3273c71b84fSZbigniew Bodek 		DELAY(MGE_SMI_WRITE_DELAY);
3283c71b84fSZbigniew Bodek 
3293c71b84fSZbigniew Bodek 	if (retries == 0)
3303c71b84fSZbigniew Bodek 		device_printf(dev, "Timeout while writing to PHY\n");
3313c71b84fSZbigniew Bodek 	MGE_SMI_UNLOCK();
3323c71b84fSZbigniew Bodek }
3333c71b84fSZbigniew Bodek 
3349f55f5f5SRafal Jaworowski static void
3359f55f5f5SRafal Jaworowski mge_get_mac_address(struct mge_softc *sc, uint8_t *addr)
3369f55f5f5SRafal Jaworowski {
3379f55f5f5SRafal Jaworowski 	uint32_t mac_l, mac_h;
338db5ef4fcSRafal Jaworowski 	uint8_t lmac[6];
339db5ef4fcSRafal Jaworowski 	int i, valid;
3409f55f5f5SRafal Jaworowski 
341db5ef4fcSRafal Jaworowski 	/*
342db5ef4fcSRafal Jaworowski 	 * Retrieve hw address from the device tree.
343db5ef4fcSRafal Jaworowski 	 */
344db5ef4fcSRafal Jaworowski 	i = OF_getprop(sc->node, "local-mac-address", (void *)lmac, 6);
345db5ef4fcSRafal Jaworowski 	if (i == 6) {
346db5ef4fcSRafal Jaworowski 		valid = 0;
347db5ef4fcSRafal Jaworowski 		for (i = 0; i < 6; i++)
348db5ef4fcSRafal Jaworowski 			if (lmac[i] != 0) {
349db5ef4fcSRafal Jaworowski 				valid = 1;
350db5ef4fcSRafal Jaworowski 				break;
351db5ef4fcSRafal Jaworowski 			}
3529f55f5f5SRafal Jaworowski 
353db5ef4fcSRafal Jaworowski 		if (valid) {
354db5ef4fcSRafal Jaworowski 			bcopy(lmac, addr, 6);
355db5ef4fcSRafal Jaworowski 			return;
356db5ef4fcSRafal Jaworowski 		}
357db5ef4fcSRafal Jaworowski 	}
358db5ef4fcSRafal Jaworowski 
359db5ef4fcSRafal Jaworowski 	/*
360db5ef4fcSRafal Jaworowski 	 * Fall back -- use the currently programmed address.
361db5ef4fcSRafal Jaworowski 	 */
3629f55f5f5SRafal Jaworowski 	mac_l = MGE_READ(sc, MGE_MAC_ADDR_L);
3639f55f5f5SRafal Jaworowski 	mac_h = MGE_READ(sc, MGE_MAC_ADDR_H);
3649f55f5f5SRafal Jaworowski 
3659f55f5f5SRafal Jaworowski 	addr[0] = (mac_h & 0xff000000) >> 24;
3669f55f5f5SRafal Jaworowski 	addr[1] = (mac_h & 0x00ff0000) >> 16;
3679f55f5f5SRafal Jaworowski 	addr[2] = (mac_h & 0x0000ff00) >> 8;
3689f55f5f5SRafal Jaworowski 	addr[3] = (mac_h & 0x000000ff);
3699f55f5f5SRafal Jaworowski 	addr[4] = (mac_l & 0x0000ff00) >> 8;
3709f55f5f5SRafal Jaworowski 	addr[5] = (mac_l & 0x000000ff);
3719f55f5f5SRafal Jaworowski }
3729f55f5f5SRafal Jaworowski 
3738e1dc58eSRafal Jaworowski static uint32_t
3748e1dc58eSRafal Jaworowski mge_tfut_ipg(uint32_t val, int ver)
3758e1dc58eSRafal Jaworowski {
3768e1dc58eSRafal Jaworowski 
3778e1dc58eSRafal Jaworowski 	switch (ver) {
3788e1dc58eSRafal Jaworowski 	case 1:
3798e1dc58eSRafal Jaworowski 		return ((val & 0x3fff) << 4);
3808e1dc58eSRafal Jaworowski 	case 2:
3818e1dc58eSRafal Jaworowski 	default:
3828e1dc58eSRafal Jaworowski 		return ((val & 0xffff) << 4);
3838e1dc58eSRafal Jaworowski 	}
3848e1dc58eSRafal Jaworowski }
3858e1dc58eSRafal Jaworowski 
3868e1dc58eSRafal Jaworowski static uint32_t
3878e1dc58eSRafal Jaworowski mge_rx_ipg(uint32_t val, int ver)
3888e1dc58eSRafal Jaworowski {
3898e1dc58eSRafal Jaworowski 
3908e1dc58eSRafal Jaworowski 	switch (ver) {
3918e1dc58eSRafal Jaworowski 	case 1:
3928e1dc58eSRafal Jaworowski 		return ((val & 0x3fff) << 8);
3938e1dc58eSRafal Jaworowski 	case 2:
3948e1dc58eSRafal Jaworowski 	default:
3958e1dc58eSRafal Jaworowski 		return (((val & 0x8000) << 10) | ((val & 0x7fff) << 7));
3968e1dc58eSRafal Jaworowski 	}
3978e1dc58eSRafal Jaworowski }
3988e1dc58eSRafal Jaworowski 
3998e1dc58eSRafal Jaworowski static void
4008e1dc58eSRafal Jaworowski mge_ver_params(struct mge_softc *sc)
4018e1dc58eSRafal Jaworowski {
4028e1dc58eSRafal Jaworowski 	uint32_t d, r;
4038e1dc58eSRafal Jaworowski 
4048e1dc58eSRafal Jaworowski 	soc_id(&d, &r);
40575f1438bSOleksandr Tymoshenko 	if (d == MV_DEV_88F6281 || d == MV_DEV_88F6781 ||
406c8953e12SHiroki Sato 	    d == MV_DEV_88F6282 ||
407c8953e12SHiroki Sato 	    d == MV_DEV_MV78100 ||
40875f1438bSOleksandr Tymoshenko 	    d == MV_DEV_MV78100_Z0 ||
40975f1438bSOleksandr Tymoshenko 	    (d & MV_DEV_FAMILY_MASK) == MV_DEV_DISCOVERY) {
4108e1dc58eSRafal Jaworowski 		sc->mge_ver = 2;
4118e1dc58eSRafal Jaworowski 		sc->mge_mtu = 0x4e8;
4128e1dc58eSRafal Jaworowski 		sc->mge_tfut_ipg_max = 0xFFFF;
4138e1dc58eSRafal Jaworowski 		sc->mge_rx_ipg_max = 0xFFFF;
4148e1dc58eSRafal Jaworowski 		sc->mge_tx_arb_cfg = 0xFC0000FF;
4158e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cfg = 0xFFFF7FFF;
4168e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cnt = 0x3FFFFFFF;
4178e1dc58eSRafal Jaworowski 	} else {
4188e1dc58eSRafal Jaworowski 		sc->mge_ver = 1;
4198e1dc58eSRafal Jaworowski 		sc->mge_mtu = 0x458;
4208e1dc58eSRafal Jaworowski 		sc->mge_tfut_ipg_max = 0x3FFF;
4218e1dc58eSRafal Jaworowski 		sc->mge_rx_ipg_max = 0x3FFF;
4228e1dc58eSRafal Jaworowski 		sc->mge_tx_arb_cfg = 0x000000FF;
4238e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cfg = 0x3FFFFFFF;
4248e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cnt = 0x3FFFFFFF;
4258e1dc58eSRafal Jaworowski 	}
42675f1438bSOleksandr Tymoshenko 	if (d == MV_DEV_88RC8180)
42775f1438bSOleksandr Tymoshenko 		sc->mge_intr_cnt = 1;
42875f1438bSOleksandr Tymoshenko 	else
42975f1438bSOleksandr Tymoshenko 		sc->mge_intr_cnt = 2;
43075f1438bSOleksandr Tymoshenko 
43175f1438bSOleksandr Tymoshenko 	if (d == MV_DEV_MV78160 || d == MV_DEV_MV78260 || d == MV_DEV_MV78460)
43275f1438bSOleksandr Tymoshenko 		sc->mge_hw_csum = 0;
43375f1438bSOleksandr Tymoshenko 	else
43475f1438bSOleksandr Tymoshenko 		sc->mge_hw_csum = 1;
4358e1dc58eSRafal Jaworowski }
4368e1dc58eSRafal Jaworowski 
4379f55f5f5SRafal Jaworowski static void
4389f55f5f5SRafal Jaworowski mge_set_mac_address(struct mge_softc *sc)
4399f55f5f5SRafal Jaworowski {
4409f55f5f5SRafal Jaworowski 	char *if_mac;
4419f55f5f5SRafal Jaworowski 	uint32_t mac_l, mac_h;
4429f55f5f5SRafal Jaworowski 
4439f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK_ASSERT(sc);
4449f55f5f5SRafal Jaworowski 
4459f55f5f5SRafal Jaworowski 	if_mac = (char *)IF_LLADDR(sc->ifp);
4469f55f5f5SRafal Jaworowski 
4479f55f5f5SRafal Jaworowski 	mac_l = (if_mac[4] << 8) | (if_mac[5]);
4489f55f5f5SRafal Jaworowski 	mac_h = (if_mac[0] << 24)| (if_mac[1] << 16) |
4499f55f5f5SRafal Jaworowski 	    (if_mac[2] << 8) | (if_mac[3] << 0);
4509f55f5f5SRafal Jaworowski 
4519f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_MAC_ADDR_L, mac_l);
4529f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_MAC_ADDR_H, mac_h);
4539f55f5f5SRafal Jaworowski 
4549f55f5f5SRafal Jaworowski 	mge_set_ucast_address(sc, if_mac[5], MGE_RX_DEFAULT_QUEUE);
4559f55f5f5SRafal Jaworowski }
4569f55f5f5SRafal Jaworowski 
4579f55f5f5SRafal Jaworowski static void
4589f55f5f5SRafal Jaworowski mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte, uint8_t queue)
4599f55f5f5SRafal Jaworowski {
4609f55f5f5SRafal Jaworowski 	uint32_t reg_idx, reg_off, reg_val, i;
4619f55f5f5SRafal Jaworowski 
4629f55f5f5SRafal Jaworowski 	last_byte &= 0xf;
4639f55f5f5SRafal Jaworowski 	reg_idx = last_byte / MGE_UCAST_REG_NUMBER;
4649f55f5f5SRafal Jaworowski 	reg_off = (last_byte % MGE_UCAST_REG_NUMBER) * 8;
4659f55f5f5SRafal Jaworowski 	reg_val = (1 | (queue << 1)) << reg_off;
4669f55f5f5SRafal Jaworowski 
4679f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_UCAST_REG_NUMBER; i++) {
4689f55f5f5SRafal Jaworowski 		if ( i == reg_idx)
4699f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val);
4709f55f5f5SRafal Jaworowski 		else
4719f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), 0);
4729f55f5f5SRafal Jaworowski 	}
4739f55f5f5SRafal Jaworowski }
4749f55f5f5SRafal Jaworowski 
4759f55f5f5SRafal Jaworowski static void
4769f55f5f5SRafal Jaworowski mge_set_prom_mode(struct mge_softc *sc, uint8_t queue)
4779f55f5f5SRafal Jaworowski {
4789f55f5f5SRafal Jaworowski 	uint32_t port_config;
4799f55f5f5SRafal Jaworowski 	uint32_t reg_val, i;
4809f55f5f5SRafal Jaworowski 
4819f55f5f5SRafal Jaworowski 	/* Enable or disable promiscuous mode as needed */
4829f55f5f5SRafal Jaworowski 	if (sc->ifp->if_flags & IFF_PROMISC) {
4839f55f5f5SRafal Jaworowski 		port_config = MGE_READ(sc, MGE_PORT_CONFIG);
4849f55f5f5SRafal Jaworowski 		port_config |= PORT_CONFIG_UPM;
4859f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_CONFIG, port_config);
4869f55f5f5SRafal Jaworowski 
4879f55f5f5SRafal Jaworowski 		reg_val = ((1 | (queue << 1)) | (1 | (queue << 1)) << 8 |
4889f55f5f5SRafal Jaworowski 		   (1 | (queue << 1)) << 16 | (1 | (queue << 1)) << 24);
4899f55f5f5SRafal Jaworowski 
4909f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
4919f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), reg_val);
4929f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), reg_val);
4939f55f5f5SRafal Jaworowski 		}
4949f55f5f5SRafal Jaworowski 
4959f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_UCAST_REG_NUMBER; i++)
4969f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val);
4979f55f5f5SRafal Jaworowski 
4989f55f5f5SRafal Jaworowski 	} else {
4999f55f5f5SRafal Jaworowski 		port_config = MGE_READ(sc, MGE_PORT_CONFIG);
5009f55f5f5SRafal Jaworowski 		port_config &= ~PORT_CONFIG_UPM;
5019f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_CONFIG, port_config);
5029f55f5f5SRafal Jaworowski 
5039f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
5049f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), 0);
5059f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), 0);
5069f55f5f5SRafal Jaworowski 		}
5079f55f5f5SRafal Jaworowski 
5089f55f5f5SRafal Jaworowski 		mge_set_mac_address(sc);
5099f55f5f5SRafal Jaworowski 	}
5109f55f5f5SRafal Jaworowski }
5119f55f5f5SRafal Jaworowski 
5129f55f5f5SRafal Jaworowski static void
5139f55f5f5SRafal Jaworowski mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
5149f55f5f5SRafal Jaworowski {
5159f55f5f5SRafal Jaworowski 	u_int32_t *paddr;
5169f55f5f5SRafal Jaworowski 
5179f55f5f5SRafal Jaworowski 	KASSERT(nseg == 1, ("wrong number of segments, should be 1"));
5189f55f5f5SRafal Jaworowski 	paddr = arg;
5199f55f5f5SRafal Jaworowski 
5209f55f5f5SRafal Jaworowski 	*paddr = segs->ds_addr;
5219f55f5f5SRafal Jaworowski }
5229f55f5f5SRafal Jaworowski 
5239f55f5f5SRafal Jaworowski static int
5249f55f5f5SRafal Jaworowski mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf **mbufp,
5259f55f5f5SRafal Jaworowski     bus_addr_t *paddr)
5269f55f5f5SRafal Jaworowski {
5279f55f5f5SRafal Jaworowski 	struct mbuf *new_mbuf;
5289f55f5f5SRafal Jaworowski 	bus_dma_segment_t seg[1];
5299f55f5f5SRafal Jaworowski 	int error;
5309f55f5f5SRafal Jaworowski 	int nsegs;
5319f55f5f5SRafal Jaworowski 
5329f55f5f5SRafal Jaworowski 	KASSERT(mbufp != NULL, ("NULL mbuf pointer!"));
5339f55f5f5SRafal Jaworowski 
534c6499eccSGleb Smirnoff 	new_mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
5359f55f5f5SRafal Jaworowski 	if (new_mbuf == NULL)
5369f55f5f5SRafal Jaworowski 		return (ENOBUFS);
5379f55f5f5SRafal Jaworowski 	new_mbuf->m_len = new_mbuf->m_pkthdr.len = new_mbuf->m_ext.ext_size;
5389f55f5f5SRafal Jaworowski 
5399f55f5f5SRafal Jaworowski 	if (*mbufp) {
5409f55f5f5SRafal Jaworowski 		bus_dmamap_sync(tag, map, BUS_DMASYNC_POSTREAD);
5419f55f5f5SRafal Jaworowski 		bus_dmamap_unload(tag, map);
5429f55f5f5SRafal Jaworowski 	}
5439f55f5f5SRafal Jaworowski 
5449f55f5f5SRafal Jaworowski 	error = bus_dmamap_load_mbuf_sg(tag, map, new_mbuf, seg, &nsegs,
5459f55f5f5SRafal Jaworowski 	    BUS_DMA_NOWAIT);
5469f55f5f5SRafal Jaworowski 	KASSERT(nsegs == 1, ("Too many segments returned!"));
5479f55f5f5SRafal Jaworowski 	if (nsegs != 1 || error)
5489f55f5f5SRafal Jaworowski 		panic("mge_new_rxbuf(): nsegs(%d), error(%d)", nsegs, error);
5499f55f5f5SRafal Jaworowski 
5509f55f5f5SRafal Jaworowski 	bus_dmamap_sync(tag, map, BUS_DMASYNC_PREREAD);
5519f55f5f5SRafal Jaworowski 
5529f55f5f5SRafal Jaworowski 	(*mbufp) = new_mbuf;
5539f55f5f5SRafal Jaworowski 	(*paddr) = seg->ds_addr;
5549f55f5f5SRafal Jaworowski 	return (0);
5559f55f5f5SRafal Jaworowski }
5569f55f5f5SRafal Jaworowski 
5579f55f5f5SRafal Jaworowski static int
5589f55f5f5SRafal Jaworowski mge_alloc_desc_dma(struct mge_softc *sc, struct mge_desc_wrapper* tab,
5599f55f5f5SRafal Jaworowski     uint32_t size, bus_dma_tag_t *buffer_tag)
5609f55f5f5SRafal Jaworowski {
5619f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
5629f55f5f5SRafal Jaworowski 	bus_addr_t desc_paddr;
5639f55f5f5SRafal Jaworowski 	int i, error;
5649f55f5f5SRafal Jaworowski 
5659f55f5f5SRafal Jaworowski 	desc_paddr = 0;
5669f55f5f5SRafal Jaworowski 	for (i = size - 1; i >= 0; i--) {
5679f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
5689f55f5f5SRafal Jaworowski 		error = bus_dmamem_alloc(sc->mge_desc_dtag,
5699f55f5f5SRafal Jaworowski 		    (void**)&(dw->mge_desc),
5709f55f5f5SRafal Jaworowski 		    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
5719f55f5f5SRafal Jaworowski 		    &(dw->desc_dmap));
5729f55f5f5SRafal Jaworowski 
5739f55f5f5SRafal Jaworowski 		if (error) {
5749f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "failed to allocate DMA memory\n");
5759f55f5f5SRafal Jaworowski 			dw->mge_desc = NULL;
5769f55f5f5SRafal Jaworowski 			return (ENXIO);
5779f55f5f5SRafal Jaworowski 		}
5789f55f5f5SRafal Jaworowski 
5799f55f5f5SRafal Jaworowski 		error = bus_dmamap_load(sc->mge_desc_dtag, dw->desc_dmap,
5809f55f5f5SRafal Jaworowski 		    dw->mge_desc, sizeof(struct mge_desc), mge_get_dma_addr,
5819f55f5f5SRafal Jaworowski 		    &(dw->mge_desc_paddr), BUS_DMA_NOWAIT);
5829f55f5f5SRafal Jaworowski 
5839f55f5f5SRafal Jaworowski 		if (error) {
5849f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "can't load descriptor\n");
5859f55f5f5SRafal Jaworowski 			bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc,
5869f55f5f5SRafal Jaworowski 			    dw->desc_dmap);
5879f55f5f5SRafal Jaworowski 			dw->mge_desc = NULL;
5889f55f5f5SRafal Jaworowski 			return (ENXIO);
5899f55f5f5SRafal Jaworowski 		}
5909f55f5f5SRafal Jaworowski 
5919f55f5f5SRafal Jaworowski 		/* Chain descriptors */
5929f55f5f5SRafal Jaworowski 		dw->mge_desc->next_desc = desc_paddr;
5939f55f5f5SRafal Jaworowski 		desc_paddr = dw->mge_desc_paddr;
5949f55f5f5SRafal Jaworowski 	}
5959f55f5f5SRafal Jaworowski 	tab[size - 1].mge_desc->next_desc = desc_paddr;
5969f55f5f5SRafal Jaworowski 
5979f55f5f5SRafal Jaworowski 	/* Allocate a busdma tag for mbufs. */
59862ce43ccSScott Long 	error = bus_dma_tag_create(bus_get_dma_tag(sc->dev),	/* parent */
59975f1438bSOleksandr Tymoshenko 	    1, 0,				/* alignment, boundary */
6009f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
6019f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR,			/* highaddr */
6029f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* filtfunc, filtfuncarg */
6039f55f5f5SRafal Jaworowski 	    MCLBYTES, 1,			/* maxsize, nsegments */
6049f55f5f5SRafal Jaworowski 	    MCLBYTES, 0,			/* maxsegsz, flags */
6059f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* lockfunc, lockfuncarg */
6069f55f5f5SRafal Jaworowski 	    buffer_tag);			/* dmat */
6079f55f5f5SRafal Jaworowski 	if (error) {
6089f55f5f5SRafal Jaworowski 		if_printf(sc->ifp, "failed to create busdma tag for mbufs\n");
6099f55f5f5SRafal Jaworowski 		return (ENXIO);
6109f55f5f5SRafal Jaworowski 	}
6119f55f5f5SRafal Jaworowski 
6129f55f5f5SRafal Jaworowski 	/* Create TX busdma maps */
6139f55f5f5SRafal Jaworowski 	for (i = 0; i < size; i++) {
6149f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
6159f55f5f5SRafal Jaworowski 		error = bus_dmamap_create(*buffer_tag, 0, &dw->buffer_dmap);
6169f55f5f5SRafal Jaworowski 		if (error) {
6179f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "failed to create map for mbuf\n");
6189f55f5f5SRafal Jaworowski 			return (ENXIO);
6199f55f5f5SRafal Jaworowski 		}
6209f55f5f5SRafal Jaworowski 
6219f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
6229f55f5f5SRafal Jaworowski 		dw->mge_desc->buffer = (bus_addr_t)NULL;
6239f55f5f5SRafal Jaworowski 	}
6249f55f5f5SRafal Jaworowski 
6259f55f5f5SRafal Jaworowski 	return (0);
6269f55f5f5SRafal Jaworowski }
6279f55f5f5SRafal Jaworowski 
6289f55f5f5SRafal Jaworowski static int
6299f55f5f5SRafal Jaworowski mge_allocate_dma(struct mge_softc *sc)
6309f55f5f5SRafal Jaworowski {
6319f55f5f5SRafal Jaworowski 	int error;
6329f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
633d6bdd318SRafal Jaworowski 	int i;
6349f55f5f5SRafal Jaworowski 
6359f55f5f5SRafal Jaworowski 	/* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
63662ce43ccSScott Long 	error = bus_dma_tag_create(bus_get_dma_tag(sc->dev),	/* parent */
6379f55f5f5SRafal Jaworowski 	    16, 0,				/* alignment, boundary */
6389f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
6399f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR,			/* highaddr */
6409f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* filtfunc, filtfuncarg */
6419f55f5f5SRafal Jaworowski 	    sizeof(struct mge_desc), 1,		/* maxsize, nsegments */
6429f55f5f5SRafal Jaworowski 	    sizeof(struct mge_desc), 0,		/* maxsegsz, flags */
6439f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* lockfunc, lockfuncarg */
6449f55f5f5SRafal Jaworowski 	    &sc->mge_desc_dtag);		/* dmat */
6459f55f5f5SRafal Jaworowski 
6469f55f5f5SRafal Jaworowski 
6479f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM,
6489f55f5f5SRafal Jaworowski 	    &sc->mge_tx_dtag);
6499f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM,
6509f55f5f5SRafal Jaworowski 	    &sc->mge_rx_dtag);
6519f55f5f5SRafal Jaworowski 
6529f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
6539f55f5f5SRafal Jaworowski 		dw = &(sc->mge_rx_desc[i]);
6549f55f5f5SRafal Jaworowski 		mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer,
6559f55f5f5SRafal Jaworowski 		    &dw->mge_desc->buffer);
6569f55f5f5SRafal Jaworowski 	}
6579f55f5f5SRafal Jaworowski 
6589f55f5f5SRafal Jaworowski 	sc->tx_desc_start = sc->mge_tx_desc[0].mge_desc_paddr;
6599f55f5f5SRafal Jaworowski 	sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr;
6609f55f5f5SRafal Jaworowski 
6619f55f5f5SRafal Jaworowski 	return (0);
6629f55f5f5SRafal Jaworowski }
6639f55f5f5SRafal Jaworowski 
6649f55f5f5SRafal Jaworowski static void
6659f55f5f5SRafal Jaworowski mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab,
6669f55f5f5SRafal Jaworowski     uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs)
6679f55f5f5SRafal Jaworowski {
6689f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
6699f55f5f5SRafal Jaworowski 	int i;
6709f55f5f5SRafal Jaworowski 
6719f55f5f5SRafal Jaworowski 	for (i = 0; i < size; i++) {
6729f55f5f5SRafal Jaworowski 		/* Free RX mbuf */
6739f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
6749f55f5f5SRafal Jaworowski 
6759f55f5f5SRafal Jaworowski 		if (dw->buffer_dmap) {
6769f55f5f5SRafal Jaworowski 			if (free_mbufs) {
6779f55f5f5SRafal Jaworowski 				bus_dmamap_sync(buffer_tag, dw->buffer_dmap,
6789f55f5f5SRafal Jaworowski 				    BUS_DMASYNC_POSTREAD);
6799f55f5f5SRafal Jaworowski 				bus_dmamap_unload(buffer_tag, dw->buffer_dmap);
6809f55f5f5SRafal Jaworowski 			}
6819f55f5f5SRafal Jaworowski 			bus_dmamap_destroy(buffer_tag, dw->buffer_dmap);
6829f55f5f5SRafal Jaworowski 			if (free_mbufs)
6839f55f5f5SRafal Jaworowski 				m_freem(dw->buffer);
6849f55f5f5SRafal Jaworowski 		}
6859f55f5f5SRafal Jaworowski 		/* Free RX descriptors */
6869f55f5f5SRafal Jaworowski 		if (dw->desc_dmap) {
6879f55f5f5SRafal Jaworowski 			bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
6889f55f5f5SRafal Jaworowski 			    BUS_DMASYNC_POSTREAD);
6899f55f5f5SRafal Jaworowski 			bus_dmamap_unload(sc->mge_desc_dtag, dw->desc_dmap);
6909f55f5f5SRafal Jaworowski 			bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc,
6919f55f5f5SRafal Jaworowski 			    dw->desc_dmap);
6929f55f5f5SRafal Jaworowski 		}
6939f55f5f5SRafal Jaworowski 	}
6949f55f5f5SRafal Jaworowski }
6959f55f5f5SRafal Jaworowski 
6969f55f5f5SRafal Jaworowski static void
6979f55f5f5SRafal Jaworowski mge_free_dma(struct mge_softc *sc)
6989f55f5f5SRafal Jaworowski {
6994ac30cc1SZbigniew Bodek 
700*b1603638SGordon Bergling 	/* Free descriptors and mbufs */
7019f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1);
7029f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM, sc->mge_tx_dtag, 0);
7039f55f5f5SRafal Jaworowski 
7049f55f5f5SRafal Jaworowski 	/* Destroy mbuf dma tag */
7059f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_tx_dtag);
7069f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_rx_dtag);
7079f55f5f5SRafal Jaworowski 	/* Destroy descriptors tag */
7089f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_desc_dtag);
7099f55f5f5SRafal Jaworowski }
7109f55f5f5SRafal Jaworowski 
7119f55f5f5SRafal Jaworowski static void
7129f55f5f5SRafal Jaworowski mge_reinit_rx(struct mge_softc *sc)
7139f55f5f5SRafal Jaworowski {
7149f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
7159f55f5f5SRafal Jaworowski 	int i;
7169f55f5f5SRafal Jaworowski 
717d6bdd318SRafal Jaworowski 	MGE_RECEIVE_LOCK_ASSERT(sc);
7189f55f5f5SRafal Jaworowski 
7199f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1);
7209f55f5f5SRafal Jaworowski 
7219f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM,
7229f55f5f5SRafal Jaworowski 	    &sc->mge_rx_dtag);
7239f55f5f5SRafal Jaworowski 
7249f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
7259f55f5f5SRafal Jaworowski 		dw = &(sc->mge_rx_desc[i]);
7269f55f5f5SRafal Jaworowski 		mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer,
7279f55f5f5SRafal Jaworowski 		&dw->mge_desc->buffer);
7289f55f5f5SRafal Jaworowski 	}
7299f55f5f5SRafal Jaworowski 
7309f55f5f5SRafal Jaworowski 	sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr;
7319f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
7329f55f5f5SRafal Jaworowski 
7339f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE),
7349f55f5f5SRafal Jaworowski 	    sc->rx_desc_start);
7359f55f5f5SRafal Jaworowski 
7369f55f5f5SRafal Jaworowski 	/* Enable RX queue */
7379f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE));
7389f55f5f5SRafal Jaworowski }
7399f55f5f5SRafal Jaworowski 
7409f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
7419f55f5f5SRafal Jaworowski static poll_handler_t mge_poll;
7429f55f5f5SRafal Jaworowski 
7431abcdbd1SAttilio Rao static int
7449f55f5f5SRafal Jaworowski mge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
7459f55f5f5SRafal Jaworowski {
7469f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
7479f55f5f5SRafal Jaworowski 	uint32_t int_cause, int_cause_ext;
7481abcdbd1SAttilio Rao 	int rx_npkts = 0;
7499f55f5f5SRafal Jaworowski 
7503c71b84fSZbigniew Bodek 	MGE_RECEIVE_LOCK(sc);
7519f55f5f5SRafal Jaworowski 
7529f55f5f5SRafal Jaworowski 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
7533c71b84fSZbigniew Bodek 		MGE_RECEIVE_UNLOCK(sc);
7541abcdbd1SAttilio Rao 		return (rx_npkts);
7559f55f5f5SRafal Jaworowski 	}
7569f55f5f5SRafal Jaworowski 
7579f55f5f5SRafal Jaworowski 	if (cmd == POLL_AND_CHECK_STATUS) {
7589f55f5f5SRafal Jaworowski 		int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
7599f55f5f5SRafal Jaworowski 		int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
7609f55f5f5SRafal Jaworowski 
7619f55f5f5SRafal Jaworowski 		/* Check for resource error */
7629f55f5f5SRafal Jaworowski 		if (int_cause & MGE_PORT_INT_RXERRQ0)
7639f55f5f5SRafal Jaworowski 			mge_reinit_rx(sc);
7649f55f5f5SRafal Jaworowski 
7659f55f5f5SRafal Jaworowski 		if (int_cause || int_cause_ext) {
7669f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause);
7679f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext);
7689f55f5f5SRafal Jaworowski 		}
7699f55f5f5SRafal Jaworowski 	}
7709f55f5f5SRafal Jaworowski 
7713c71b84fSZbigniew Bodek 
7721abcdbd1SAttilio Rao 	rx_npkts = mge_intr_rx_locked(sc, count);
7739f55f5f5SRafal Jaworowski 
7743c71b84fSZbigniew Bodek 	MGE_RECEIVE_UNLOCK(sc);
7753c71b84fSZbigniew Bodek 	MGE_TRANSMIT_LOCK(sc);
7763c71b84fSZbigniew Bodek 	mge_intr_tx_locked(sc);
7773c71b84fSZbigniew Bodek 	MGE_TRANSMIT_UNLOCK(sc);
7781abcdbd1SAttilio Rao 	return (rx_npkts);
7799f55f5f5SRafal Jaworowski }
7809f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */
7819f55f5f5SRafal Jaworowski 
7829f55f5f5SRafal Jaworowski static int
7839f55f5f5SRafal Jaworowski mge_attach(device_t dev)
7849f55f5f5SRafal Jaworowski {
7859f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
786a6eb469dSPhilip Paeps 	struct mii_softc *miisc;
7879f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
7889f55f5f5SRafal Jaworowski 	uint8_t hwaddr[ETHER_ADDR_LEN];
7898e5d93dbSMarius Strobl 	int i, error, phy;
7909f55f5f5SRafal Jaworowski 
7919f55f5f5SRafal Jaworowski 	sc = device_get_softc(dev);
7929f55f5f5SRafal Jaworowski 	sc->dev = dev;
793db5ef4fcSRafal Jaworowski 	sc->node = ofw_bus_get_node(dev);
7943c71b84fSZbigniew Bodek 	phy = 0;
7953c71b84fSZbigniew Bodek 
7963c71b84fSZbigniew Bodek 	if (fdt_get_phyaddr(sc->node, sc->dev, &phy, (void **)&sc->phy_sc) == 0) {
7973c71b84fSZbigniew Bodek 		device_printf(dev, "PHY%i attached, phy_sc points to %s\n", phy,
7983c71b84fSZbigniew Bodek 		    device_get_nameunit(sc->phy_sc->dev));
7993c71b84fSZbigniew Bodek 		sc->phy_attached = 1;
8003c71b84fSZbigniew Bodek 	} else {
8013c71b84fSZbigniew Bodek 		device_printf(dev, "PHY not attached.\n");
8023c71b84fSZbigniew Bodek 		sc->phy_attached = 0;
8033c71b84fSZbigniew Bodek 		sc->phy_sc = sc;
8043c71b84fSZbigniew Bodek 	}
8053c71b84fSZbigniew Bodek 
8063c71b84fSZbigniew Bodek 	if (fdt_find_compatible(sc->node, "mrvl,sw", 1) != 0) {
8073c71b84fSZbigniew Bodek 		device_printf(dev, "Switch attached.\n");
8083c71b84fSZbigniew Bodek 		sc->switch_attached = 1;
8093c71b84fSZbigniew Bodek 		/* additional variable available across instances */
8103c71b84fSZbigniew Bodek 		switch_attached = 1;
8113c71b84fSZbigniew Bodek 	} else {
8123c71b84fSZbigniew Bodek 		sc->switch_attached = 0;
8133c71b84fSZbigniew Bodek 	}
8143c71b84fSZbigniew Bodek 
8153c71b84fSZbigniew Bodek 	if (device_get_unit(dev) == 0) {
8163c71b84fSZbigniew Bodek 		sx_init(&sx_smi, "mge_tick() SMI access threads interlock");
8173c71b84fSZbigniew Bodek 	}
8189f55f5f5SRafal Jaworowski 
8198e1dc58eSRafal Jaworowski 	/* Set chip version-dependent parameters */
8208e1dc58eSRafal Jaworowski 	mge_ver_params(sc);
8218e1dc58eSRafal Jaworowski 
8229f55f5f5SRafal Jaworowski 	/* Initialize mutexes */
8234ac30cc1SZbigniew Bodek 	mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "mge TX lock",
8244ac30cc1SZbigniew Bodek 	    MTX_DEF);
8254ac30cc1SZbigniew Bodek 	mtx_init(&sc->receive_lock, device_get_nameunit(dev), "mge RX lock",
8264ac30cc1SZbigniew Bodek 	    MTX_DEF);
8279f55f5f5SRafal Jaworowski 
8289f55f5f5SRafal Jaworowski 	/* Allocate IO and IRQ resources */
8299f55f5f5SRafal Jaworowski 	error = bus_alloc_resources(dev, res_spec, sc->res);
8309f55f5f5SRafal Jaworowski 	if (error) {
8319f55f5f5SRafal Jaworowski 		device_printf(dev, "could not allocate resources\n");
8329f55f5f5SRafal Jaworowski 		mge_detach(dev);
8339f55f5f5SRafal Jaworowski 		return (ENXIO);
8349f55f5f5SRafal Jaworowski 	}
8359f55f5f5SRafal Jaworowski 
8369f55f5f5SRafal Jaworowski 	/* Allocate DMA, buffers, buffer descriptors */
8379f55f5f5SRafal Jaworowski 	error = mge_allocate_dma(sc);
8389f55f5f5SRafal Jaworowski 	if (error) {
8399f55f5f5SRafal Jaworowski 		mge_detach(dev);
8409f55f5f5SRafal Jaworowski 		return (ENXIO);
8419f55f5f5SRafal Jaworowski 	}
8429f55f5f5SRafal Jaworowski 
8439f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = 0;
8449f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
8459f55f5f5SRafal Jaworowski 	sc->tx_desc_used_idx = 0;
8465817716fSRafal Jaworowski 	sc->tx_desc_used_count = 0;
8479f55f5f5SRafal Jaworowski 
8489f55f5f5SRafal Jaworowski 	/* Configure defaults for interrupts coalescing */
8499f55f5f5SRafal Jaworowski 	sc->rx_ic_time = 768;
8509f55f5f5SRafal Jaworowski 	sc->tx_ic_time = 768;
8519f55f5f5SRafal Jaworowski 	mge_add_sysctls(sc);
8529f55f5f5SRafal Jaworowski 
8539f55f5f5SRafal Jaworowski 	/* Allocate network interface */
8549f55f5f5SRafal Jaworowski 	ifp = sc->ifp = if_alloc(IFT_ETHER);
8559f55f5f5SRafal Jaworowski 	if (ifp == NULL) {
8569f55f5f5SRafal Jaworowski 		device_printf(dev, "if_alloc() failed\n");
8579f55f5f5SRafal Jaworowski 		mge_detach(dev);
8589f55f5f5SRafal Jaworowski 		return (ENOMEM);
8599f55f5f5SRafal Jaworowski 	}
8609f55f5f5SRafal Jaworowski 
8619f55f5f5SRafal Jaworowski 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
8629f55f5f5SRafal Jaworowski 	ifp->if_softc = sc;
8639f55f5f5SRafal Jaworowski 	ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST;
86475f1438bSOleksandr Tymoshenko 	ifp->if_capabilities = IFCAP_VLAN_MTU;
86575f1438bSOleksandr Tymoshenko 	if (sc->mge_hw_csum) {
86675f1438bSOleksandr Tymoshenko 		ifp->if_capabilities |= IFCAP_HWCSUM;
8679f55f5f5SRafal Jaworowski 		ifp->if_hwassist = MGE_CHECKSUM_FEATURES;
86875f1438bSOleksandr Tymoshenko 	}
86975f1438bSOleksandr Tymoshenko 	ifp->if_capenable = ifp->if_capabilities;
8709f55f5f5SRafal Jaworowski 
8719f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
8729f55f5f5SRafal Jaworowski 	/* Advertise that polling is supported */
8739f55f5f5SRafal Jaworowski 	ifp->if_capabilities |= IFCAP_POLLING;
8749f55f5f5SRafal Jaworowski #endif
8759f55f5f5SRafal Jaworowski 
8769f55f5f5SRafal Jaworowski 	ifp->if_init = mge_init;
8779f55f5f5SRafal Jaworowski 	ifp->if_start = mge_start;
8789f55f5f5SRafal Jaworowski 	ifp->if_ioctl = mge_ioctl;
8799f55f5f5SRafal Jaworowski 
8809f55f5f5SRafal Jaworowski 	ifp->if_snd.ifq_drv_maxlen = MGE_TX_DESC_NUM - 1;
8819f55f5f5SRafal Jaworowski 	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
8829f55f5f5SRafal Jaworowski 	IFQ_SET_READY(&ifp->if_snd);
8839f55f5f5SRafal Jaworowski 
8849f55f5f5SRafal Jaworowski 	mge_get_mac_address(sc, hwaddr);
8859f55f5f5SRafal Jaworowski 	ether_ifattach(ifp, hwaddr);
8869f55f5f5SRafal Jaworowski 	callout_init(&sc->wd_callout, 0);
8879f55f5f5SRafal Jaworowski 
8888e5d93dbSMarius Strobl 	/* Attach PHY(s) */
8893c71b84fSZbigniew Bodek 	if (sc->phy_attached) {
8908e5d93dbSMarius Strobl 		error = mii_attach(dev, &sc->miibus, ifp, mge_ifmedia_upd,
8918e5d93dbSMarius Strobl 		    mge_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
8929f55f5f5SRafal Jaworowski 		if (error) {
8933c71b84fSZbigniew Bodek 			device_printf(dev, "MII failed to find PHY\n");
8943c71b84fSZbigniew Bodek 			if_free(ifp);
8953c71b84fSZbigniew Bodek 			sc->ifp = NULL;
8969f55f5f5SRafal Jaworowski 			mge_detach(dev);
8979f55f5f5SRafal Jaworowski 			return (error);
8989f55f5f5SRafal Jaworowski 		}
8999f55f5f5SRafal Jaworowski 		sc->mii = device_get_softc(sc->miibus);
9009f55f5f5SRafal Jaworowski 
901a6eb469dSPhilip Paeps 		/* Tell the MAC where to find the PHY so autoneg works */
902a6eb469dSPhilip Paeps 		miisc = LIST_FIRST(&sc->mii->mii_phys);
903a6eb469dSPhilip Paeps 		MGE_WRITE(sc, MGE_REG_PHYDEV, miisc->mii_phy);
9043c71b84fSZbigniew Bodek 	} else {
9053c71b84fSZbigniew Bodek 		/* no PHY, so use hard-coded values */
9063c71b84fSZbigniew Bodek 		ifmedia_init(&sc->mge_ifmedia, 0,
9073c71b84fSZbigniew Bodek 		    mge_ifmedia_upd,
9083c71b84fSZbigniew Bodek 		    mge_ifmedia_sts);
9093c71b84fSZbigniew Bodek 		ifmedia_add(&sc->mge_ifmedia,
9103c71b84fSZbigniew Bodek 		    IFM_ETHER | IFM_1000_T | IFM_FDX,
9113c71b84fSZbigniew Bodek 		    0, NULL);
9123c71b84fSZbigniew Bodek 		ifmedia_set(&sc->mge_ifmedia,
9133c71b84fSZbigniew Bodek 		    IFM_ETHER | IFM_1000_T | IFM_FDX);
9143c71b84fSZbigniew Bodek 	}
915a6eb469dSPhilip Paeps 
9169f55f5f5SRafal Jaworowski 	/* Attach interrupt handlers */
91775f1438bSOleksandr Tymoshenko 	/* TODO: review flags, in part. mark RX as INTR_ENTROPY ? */
91875f1438bSOleksandr Tymoshenko 	for (i = 1; i <= sc->mge_intr_cnt; ++i) {
91975f1438bSOleksandr Tymoshenko 		error = bus_setup_intr(dev, sc->res[i],
92075f1438bSOleksandr Tymoshenko 		    INTR_TYPE_NET | INTR_MPSAFE,
92175f1438bSOleksandr Tymoshenko 		    NULL, *mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].handler,
92275f1438bSOleksandr Tymoshenko 		    sc, &sc->ih_cookie[i - 1]);
9239f55f5f5SRafal Jaworowski 		if (error) {
9249f55f5f5SRafal Jaworowski 			device_printf(dev, "could not setup %s\n",
92575f1438bSOleksandr Tymoshenko 			    mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].description);
926a6eb469dSPhilip Paeps 			mge_detach(dev);
9279f55f5f5SRafal Jaworowski 			return (error);
9289f55f5f5SRafal Jaworowski 		}
9299f55f5f5SRafal Jaworowski 	}
9309f55f5f5SRafal Jaworowski 
9313c71b84fSZbigniew Bodek 	if (sc->switch_attached) {
9323c71b84fSZbigniew Bodek 		device_t child;
9333c71b84fSZbigniew Bodek 		MGE_WRITE(sc, MGE_REG_PHYDEV, MGE_SWITCH_PHYDEV);
9343c71b84fSZbigniew Bodek 		child = device_add_child(dev, "mdio", -1);
9353c71b84fSZbigniew Bodek 		bus_generic_attach(dev);
9363c71b84fSZbigniew Bodek 	}
9373c71b84fSZbigniew Bodek 
9389f55f5f5SRafal Jaworowski 	return (0);
9399f55f5f5SRafal Jaworowski }
9409f55f5f5SRafal Jaworowski 
9419f55f5f5SRafal Jaworowski static int
9429f55f5f5SRafal Jaworowski mge_detach(device_t dev)
9439f55f5f5SRafal Jaworowski {
9449f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
9459f55f5f5SRafal Jaworowski 	int error,i;
9469f55f5f5SRafal Jaworowski 
9479f55f5f5SRafal Jaworowski 	sc = device_get_softc(dev);
9489f55f5f5SRafal Jaworowski 
9499f55f5f5SRafal Jaworowski 	/* Stop controller and free TX queue */
9509f55f5f5SRafal Jaworowski 	if (sc->ifp)
9519f55f5f5SRafal Jaworowski 		mge_shutdown(dev);
9529f55f5f5SRafal Jaworowski 
9539f55f5f5SRafal Jaworowski 	/* Wait for stopping ticks */
9549f55f5f5SRafal Jaworowski         callout_drain(&sc->wd_callout);
9559f55f5f5SRafal Jaworowski 
9569f55f5f5SRafal Jaworowski 	/* Stop and release all interrupts */
95775f1438bSOleksandr Tymoshenko 	for (i = 0; i < sc->mge_intr_cnt; ++i) {
958a6eb469dSPhilip Paeps 		if (!sc->ih_cookie[i])
959a6eb469dSPhilip Paeps 			continue;
960a6eb469dSPhilip Paeps 
9614ac30cc1SZbigniew Bodek 		error = bus_teardown_intr(dev, sc->res[1 + i],
9624ac30cc1SZbigniew Bodek 		    sc->ih_cookie[i]);
9639f55f5f5SRafal Jaworowski 		if (error)
9649f55f5f5SRafal Jaworowski 			device_printf(dev, "could not release %s\n",
96575f1438bSOleksandr Tymoshenko 			    mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i + 1)].description);
9669f55f5f5SRafal Jaworowski 	}
9679f55f5f5SRafal Jaworowski 
9689f55f5f5SRafal Jaworowski 	/* Detach network interface */
9699f55f5f5SRafal Jaworowski 	if (sc->ifp) {
9709f55f5f5SRafal Jaworowski 		ether_ifdetach(sc->ifp);
9719f55f5f5SRafal Jaworowski 		if_free(sc->ifp);
9729f55f5f5SRafal Jaworowski 	}
9739f55f5f5SRafal Jaworowski 
9749f55f5f5SRafal Jaworowski 	/* Free DMA resources */
9759f55f5f5SRafal Jaworowski 	mge_free_dma(sc);
9769f55f5f5SRafal Jaworowski 
9779f55f5f5SRafal Jaworowski 	/* Free IO memory handler */
9789f55f5f5SRafal Jaworowski 	bus_release_resources(dev, res_spec, sc->res);
9799f55f5f5SRafal Jaworowski 
9809f55f5f5SRafal Jaworowski 	/* Destroy mutexes */
9819f55f5f5SRafal Jaworowski 	mtx_destroy(&sc->receive_lock);
9829f55f5f5SRafal Jaworowski 	mtx_destroy(&sc->transmit_lock);
9839f55f5f5SRafal Jaworowski 
9843c71b84fSZbigniew Bodek 	if (device_get_unit(dev) == 0)
9853c71b84fSZbigniew Bodek 		sx_destroy(&sx_smi);
9863c71b84fSZbigniew Bodek 
9879f55f5f5SRafal Jaworowski 	return (0);
9889f55f5f5SRafal Jaworowski }
9899f55f5f5SRafal Jaworowski 
9909f55f5f5SRafal Jaworowski static void
9919f55f5f5SRafal Jaworowski mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
9929f55f5f5SRafal Jaworowski {
9934ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
9949f55f5f5SRafal Jaworowski 	struct mii_data *mii;
9959f55f5f5SRafal Jaworowski 
9964ac30cc1SZbigniew Bodek 	sc = ifp->if_softc;
9973c71b84fSZbigniew Bodek 	MGE_GLOBAL_LOCK(sc);
9983c71b84fSZbigniew Bodek 
9993c71b84fSZbigniew Bodek 	if (!sc->phy_attached) {
10003c71b84fSZbigniew Bodek 		ifmr->ifm_active = IFM_1000_T | IFM_FDX | IFM_ETHER;
10013c71b84fSZbigniew Bodek 		ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
10023c71b84fSZbigniew Bodek 		goto out_unlock;
10033c71b84fSZbigniew Bodek 	}
10049f55f5f5SRafal Jaworowski 
10059f55f5f5SRafal Jaworowski 	mii = sc->mii;
10069f55f5f5SRafal Jaworowski 	mii_pollstat(mii);
10079f55f5f5SRafal Jaworowski 
10089f55f5f5SRafal Jaworowski 	ifmr->ifm_active = mii->mii_media_active;
10099f55f5f5SRafal Jaworowski 	ifmr->ifm_status = mii->mii_media_status;
10109f55f5f5SRafal Jaworowski 
10113c71b84fSZbigniew Bodek out_unlock:
10123c71b84fSZbigniew Bodek 	MGE_GLOBAL_UNLOCK(sc);
10139f55f5f5SRafal Jaworowski }
10149f55f5f5SRafal Jaworowski 
10159f55f5f5SRafal Jaworowski static uint32_t
10169f55f5f5SRafal Jaworowski mge_set_port_serial_control(uint32_t media)
10179f55f5f5SRafal Jaworowski {
10189f55f5f5SRafal Jaworowski 	uint32_t port_config;
10199f55f5f5SRafal Jaworowski 
10209f55f5f5SRafal Jaworowski 	port_config = PORT_SERIAL_RES_BIT9 | PORT_SERIAL_FORCE_LINK_FAIL |
10219f55f5f5SRafal Jaworowski 	    PORT_SERIAL_MRU(PORT_SERIAL_MRU_1552);
10229f55f5f5SRafal Jaworowski 
10239f55f5f5SRafal Jaworowski 	if (IFM_TYPE(media) == IFM_ETHER) {
10249f55f5f5SRafal Jaworowski 		switch(IFM_SUBTYPE(media)) {
10259f55f5f5SRafal Jaworowski 			case IFM_AUTO:
10269f55f5f5SRafal Jaworowski 				break;
10279f55f5f5SRafal Jaworowski 			case IFM_1000_T:
10289f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_GMII_SPEED_1000 |
10293c71b84fSZbigniew Bodek 				    PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC
10303c71b84fSZbigniew Bodek 				    | PORT_SERIAL_SPEED_AUTONEG);
10319f55f5f5SRafal Jaworowski 				break;
10329f55f5f5SRafal Jaworowski 			case IFM_100_TX:
10339f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_MII_SPEED_100 |
10343c71b84fSZbigniew Bodek 				    PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC
10353c71b84fSZbigniew Bodek 				    | PORT_SERIAL_SPEED_AUTONEG);
10369f55f5f5SRafal Jaworowski 				break;
10379f55f5f5SRafal Jaworowski 			case IFM_10_T:
10389f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_AUTONEG |
10399f55f5f5SRafal Jaworowski 				    PORT_SERIAL_AUTONEG_FC |
10409f55f5f5SRafal Jaworowski 				    PORT_SERIAL_SPEED_AUTONEG);
10419f55f5f5SRafal Jaworowski 				break;
10429f55f5f5SRafal Jaworowski 		}
10439f55f5f5SRafal Jaworowski 		if (media & IFM_FDX)
10449f55f5f5SRafal Jaworowski 			port_config |= PORT_SERIAL_FULL_DUPLEX;
10459f55f5f5SRafal Jaworowski 	}
10469f55f5f5SRafal Jaworowski 	return (port_config);
10479f55f5f5SRafal Jaworowski }
10489f55f5f5SRafal Jaworowski 
10499f55f5f5SRafal Jaworowski static int
10509f55f5f5SRafal Jaworowski mge_ifmedia_upd(struct ifnet *ifp)
10519f55f5f5SRafal Jaworowski {
10529f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
10539f55f5f5SRafal Jaworowski 
10543c71b84fSZbigniew Bodek 	/*
10553c71b84fSZbigniew Bodek 	 * Do not do anything for switch here, as updating media between
10563c71b84fSZbigniew Bodek 	 * MGE MAC and switch MAC is hardcoded in PCB. Changing it here would
10573c71b84fSZbigniew Bodek 	 * break the link.
10583c71b84fSZbigniew Bodek 	 */
10593c71b84fSZbigniew Bodek 	if (sc->phy_attached) {
10609f55f5f5SRafal Jaworowski 		MGE_GLOBAL_LOCK(sc);
10613c71b84fSZbigniew Bodek 		if (ifp->if_flags & IFF_UP) {
10629f55f5f5SRafal Jaworowski 			sc->mge_media_status = sc->mii->mii_media.ifm_media;
10639f55f5f5SRafal Jaworowski 			mii_mediachg(sc->mii);
10643c71b84fSZbigniew Bodek 
10653c71b84fSZbigniew Bodek 			/* MGE MAC needs to be reinitialized. */
10669f55f5f5SRafal Jaworowski 			mge_init_locked(sc);
10679f55f5f5SRafal Jaworowski 
10683c71b84fSZbigniew Bodek 		}
10699f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
10709f55f5f5SRafal Jaworowski 	}
10719f55f5f5SRafal Jaworowski 
10729f55f5f5SRafal Jaworowski 	return (0);
10739f55f5f5SRafal Jaworowski }
10749f55f5f5SRafal Jaworowski 
10759f55f5f5SRafal Jaworowski static void
10769f55f5f5SRafal Jaworowski mge_init(void *arg)
10779f55f5f5SRafal Jaworowski {
10784ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
10799f55f5f5SRafal Jaworowski 
10804ac30cc1SZbigniew Bodek 	sc = arg;
10819f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
10829f55f5f5SRafal Jaworowski 
10839f55f5f5SRafal Jaworowski 	mge_init_locked(arg);
10849f55f5f5SRafal Jaworowski 
10859f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
10869f55f5f5SRafal Jaworowski }
10879f55f5f5SRafal Jaworowski 
10889f55f5f5SRafal Jaworowski static void
10899f55f5f5SRafal Jaworowski mge_init_locked(void *arg)
10909f55f5f5SRafal Jaworowski {
10919f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
10929f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
10939f55f5f5SRafal Jaworowski 	volatile uint32_t reg_val;
10949f55f5f5SRafal Jaworowski 	int i, count;
10953c71b84fSZbigniew Bodek 	uint32_t media_status;
10969f55f5f5SRafal Jaworowski 
10979f55f5f5SRafal Jaworowski 
10989f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK_ASSERT(sc);
10999f55f5f5SRafal Jaworowski 
11009f55f5f5SRafal Jaworowski 	/* Stop interface */
11019f55f5f5SRafal Jaworowski 	mge_stop(sc);
11029f55f5f5SRafal Jaworowski 
11039f55f5f5SRafal Jaworowski 	/* Disable interrupts */
11049f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 0);
11059f55f5f5SRafal Jaworowski 
11069f55f5f5SRafal Jaworowski 	/* Set MAC address */
11079f55f5f5SRafal Jaworowski 	mge_set_mac_address(sc);
11089f55f5f5SRafal Jaworowski 
11099f55f5f5SRafal Jaworowski 	/* Setup multicast filters */
11109f55f5f5SRafal Jaworowski 	mge_setup_multicast(sc);
11119f55f5f5SRafal Jaworowski 
11128e1dc58eSRafal Jaworowski 	if (sc->mge_ver == 2) {
11139f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL1, MGE_RGMII_EN);
11149f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_FIXED_PRIO_CONF, MGE_FIXED_PRIO_EN(0));
11158e1dc58eSRafal Jaworowski 	}
11169f55f5f5SRafal Jaworowski 
11178e1dc58eSRafal Jaworowski 	/* Initialize TX queue configuration registers */
11188e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(0), sc->mge_tx_tok_cnt);
11198e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_TOKEN_CONF(0), sc->mge_tx_tok_cfg);
11208e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_ARBITER_CONF(0), sc->mge_tx_arb_cfg);
11218e1dc58eSRafal Jaworowski 
11228e1dc58eSRafal Jaworowski 	/* Clear TX queue configuration registers for unused queues */
11239f55f5f5SRafal Jaworowski 	for (i = 1; i < 7; i++) {
11248e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(i), 0);
11258e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_TOKEN_CONF(i), 0);
11268e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_ARBITER_CONF(i), 0);
11279f55f5f5SRafal Jaworowski 	}
11289f55f5f5SRafal Jaworowski 
11299f55f5f5SRafal Jaworowski 	/* Set default MTU */
11308e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, sc->mge_mtu, 0);
11319f55f5f5SRafal Jaworowski 
11329f55f5f5SRafal Jaworowski 	/* Port configuration */
11339f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_CONFIG,
11349f55f5f5SRafal Jaworowski 	    PORT_CONFIG_RXCS | PORT_CONFIG_DFLT_RXQ(0) |
11359f55f5f5SRafal Jaworowski 	    PORT_CONFIG_ARO_RXQ(0));
11369f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_EXT_CONFIG , 0x0);
11379f55f5f5SRafal Jaworowski 
11383c71b84fSZbigniew Bodek 	/* Configure promisc mode */
11393c71b84fSZbigniew Bodek 	mge_set_prom_mode(sc, MGE_RX_DEFAULT_QUEUE);
11403c71b84fSZbigniew Bodek 
11413c71b84fSZbigniew Bodek 	media_status = sc->mge_media_status;
11423c71b84fSZbigniew Bodek 	if (sc->switch_attached) {
11433c71b84fSZbigniew Bodek 		media_status &= ~IFM_TMASK;
11443c71b84fSZbigniew Bodek 		media_status |= IFM_1000_T;
11453c71b84fSZbigniew Bodek 	}
11463c71b84fSZbigniew Bodek 
11479f55f5f5SRafal Jaworowski 	/* Setup port configuration */
11483c71b84fSZbigniew Bodek 	reg_val = mge_set_port_serial_control(media_status);
11499f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
11509f55f5f5SRafal Jaworowski 
11519f55f5f5SRafal Jaworowski 	/* Setup SDMA configuration */
11529f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_SDMA_CONFIG , MGE_SDMA_RX_BYTE_SWAP |
11539f55f5f5SRafal Jaworowski 	    MGE_SDMA_TX_BYTE_SWAP |
11549f55f5f5SRafal Jaworowski 	    MGE_SDMA_RX_BURST_SIZE(MGE_SDMA_BURST_16_WORD) |
11559f55f5f5SRafal Jaworowski 	    MGE_SDMA_TX_BURST_SIZE(MGE_SDMA_BURST_16_WORD));
11569f55f5f5SRafal Jaworowski 
11579f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, 0x0);
11589f55f5f5SRafal Jaworowski 
11599f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_CUR_DESC_PTR, sc->tx_desc_start);
11609f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE),
11619f55f5f5SRafal Jaworowski 	    sc->rx_desc_start);
11629f55f5f5SRafal Jaworowski 
11639f55f5f5SRafal Jaworowski 	/* Reset descriptor indexes */
11649f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = 0;
11659f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
11669f55f5f5SRafal Jaworowski 	sc->tx_desc_used_idx = 0;
11675817716fSRafal Jaworowski 	sc->tx_desc_used_count = 0;
11689f55f5f5SRafal Jaworowski 
11699f55f5f5SRafal Jaworowski 	/* Enable RX descriptors */
11709f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
11719f55f5f5SRafal Jaworowski 		dw = &sc->mge_rx_desc[i];
11729f55f5f5SRafal Jaworowski 		dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
11739f55f5f5SRafal Jaworowski 		dw->mge_desc->buff_size = MCLBYTES;
11749f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
11759f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
11769f55f5f5SRafal Jaworowski 	}
11779f55f5f5SRafal Jaworowski 
11789f55f5f5SRafal Jaworowski 	/* Enable RX queue */
11799f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE));
11809f55f5f5SRafal Jaworowski 
11819f55f5f5SRafal Jaworowski 	/* Enable port */
11829f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL);
11839f55f5f5SRafal Jaworowski 	reg_val |= PORT_SERIAL_ENABLE;
11849f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
11859f55f5f5SRafal Jaworowski 	count = 0x100000;
11869f55f5f5SRafal Jaworowski 	for (;;) {
11879f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_PORT_STATUS);
11889f55f5f5SRafal Jaworowski 		if (reg_val & MGE_STATUS_LINKUP)
11899f55f5f5SRafal Jaworowski 			break;
11909f55f5f5SRafal Jaworowski 		DELAY(100);
11919f55f5f5SRafal Jaworowski 		if (--count == 0) {
11929f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "Timeout on link-up\n");
11939f55f5f5SRafal Jaworowski 			break;
11949f55f5f5SRafal Jaworowski 		}
11959f55f5f5SRafal Jaworowski 	}
11969f55f5f5SRafal Jaworowski 
11979f55f5f5SRafal Jaworowski 	/* Setup interrupts coalescing */
11989f55f5f5SRafal Jaworowski 	mge_set_rxic(sc);
11999f55f5f5SRafal Jaworowski 	mge_set_txic(sc);
12009f55f5f5SRafal Jaworowski 
12019f55f5f5SRafal Jaworowski 	/* Enable interrupts */
12029f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
12039f55f5f5SRafal Jaworowski         /*
12049f55f5f5SRafal Jaworowski 	 * * ...only if polling is not turned on. Disable interrupts explicitly
12059f55f5f5SRafal Jaworowski 	 * if polling is enabled.
12069f55f5f5SRafal Jaworowski 	 */
12079f55f5f5SRafal Jaworowski 	if (sc->ifp->if_capenable & IFCAP_POLLING)
12089f55f5f5SRafal Jaworowski 		mge_intrs_ctrl(sc, 0);
12099f55f5f5SRafal Jaworowski 	else
12109f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */
12119f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 1);
12129f55f5f5SRafal Jaworowski 
12139f55f5f5SRafal Jaworowski 	/* Activate network interface */
12149f55f5f5SRafal Jaworowski 	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
12159f55f5f5SRafal Jaworowski 	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
12169f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
12179f55f5f5SRafal Jaworowski 
12189f55f5f5SRafal Jaworowski 	/* Schedule watchdog timeout */
12193c71b84fSZbigniew Bodek 	if (sc->phy_attached)
12209f55f5f5SRafal Jaworowski 		callout_reset(&sc->wd_callout, hz, mge_tick, sc);
12219f55f5f5SRafal Jaworowski }
12229f55f5f5SRafal Jaworowski 
12239f55f5f5SRafal Jaworowski static void
122475f1438bSOleksandr Tymoshenko mge_intr_rxtx(void *arg)
122575f1438bSOleksandr Tymoshenko {
12264ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
122775f1438bSOleksandr Tymoshenko 	uint32_t int_cause, int_cause_ext;
122875f1438bSOleksandr Tymoshenko 
12294ac30cc1SZbigniew Bodek 	sc = arg;
123075f1438bSOleksandr Tymoshenko 	MGE_GLOBAL_LOCK(sc);
123175f1438bSOleksandr Tymoshenko 
123275f1438bSOleksandr Tymoshenko #ifdef DEVICE_POLLING
123375f1438bSOleksandr Tymoshenko 	if (sc->ifp->if_capenable & IFCAP_POLLING) {
123475f1438bSOleksandr Tymoshenko 		MGE_GLOBAL_UNLOCK(sc);
123575f1438bSOleksandr Tymoshenko 		return;
123675f1438bSOleksandr Tymoshenko 	}
123775f1438bSOleksandr Tymoshenko #endif
123875f1438bSOleksandr Tymoshenko 
123975f1438bSOleksandr Tymoshenko 	/* Get interrupt cause */
124075f1438bSOleksandr Tymoshenko 	int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
124175f1438bSOleksandr Tymoshenko 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
124275f1438bSOleksandr Tymoshenko 
124375f1438bSOleksandr Tymoshenko 	/* Check for Transmit interrupt */
124475f1438bSOleksandr Tymoshenko 	if (int_cause_ext & (MGE_PORT_INT_EXT_TXBUF0 |
124575f1438bSOleksandr Tymoshenko 	    MGE_PORT_INT_EXT_TXUR)) {
124675f1438bSOleksandr Tymoshenko 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext &
124775f1438bSOleksandr Tymoshenko 		    (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR)));
124875f1438bSOleksandr Tymoshenko 		mge_intr_tx_locked(sc);
124975f1438bSOleksandr Tymoshenko 	}
125075f1438bSOleksandr Tymoshenko 
125175f1438bSOleksandr Tymoshenko 	MGE_TRANSMIT_UNLOCK(sc);
125275f1438bSOleksandr Tymoshenko 
125375f1438bSOleksandr Tymoshenko 	/* Check for Receive interrupt */
125475f1438bSOleksandr Tymoshenko 	mge_intr_rx_check(sc, int_cause, int_cause_ext);
125575f1438bSOleksandr Tymoshenko 
125675f1438bSOleksandr Tymoshenko 	MGE_RECEIVE_UNLOCK(sc);
125775f1438bSOleksandr Tymoshenko }
125875f1438bSOleksandr Tymoshenko 
125975f1438bSOleksandr Tymoshenko static void
12609f55f5f5SRafal Jaworowski mge_intr_err(void *arg)
12619f55f5f5SRafal Jaworowski {
12624ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
12639f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
12649f55f5f5SRafal Jaworowski 
12654ac30cc1SZbigniew Bodek 	sc = arg;
12669f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
12679f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
12689f55f5f5SRafal Jaworowski }
12699f55f5f5SRafal Jaworowski 
12709f55f5f5SRafal Jaworowski static void
12719f55f5f5SRafal Jaworowski mge_intr_misc(void *arg)
12729f55f5f5SRafal Jaworowski {
12734ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
12749f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
12759f55f5f5SRafal Jaworowski 
12764ac30cc1SZbigniew Bodek 	sc = arg;
12779f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
12789f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
12799f55f5f5SRafal Jaworowski }
12809f55f5f5SRafal Jaworowski 
12819f55f5f5SRafal Jaworowski static void
12829f55f5f5SRafal Jaworowski mge_intr_rx(void *arg) {
12834ac30cc1SZbigniew Bodek 	struct mge_softc *sc;
12849f55f5f5SRafal Jaworowski 	uint32_t int_cause, int_cause_ext;
12859f55f5f5SRafal Jaworowski 
12864ac30cc1SZbigniew Bodek 	sc = arg;
12879f55f5f5SRafal Jaworowski 	MGE_RECEIVE_LOCK(sc);
12889f55f5f5SRafal Jaworowski 
12899f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
12909f55f5f5SRafal Jaworowski 	if (sc->ifp->if_capenable & IFCAP_POLLING) {
12919f55f5f5SRafal Jaworowski 		MGE_RECEIVE_UNLOCK(sc);
12929f55f5f5SRafal Jaworowski 		return;
12939f55f5f5SRafal Jaworowski 	}
12949f55f5f5SRafal Jaworowski #endif
12959f55f5f5SRafal Jaworowski 
12969f55f5f5SRafal Jaworowski 	/* Get interrupt cause */
12979f55f5f5SRafal Jaworowski 	int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
12989f55f5f5SRafal Jaworowski 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
12999f55f5f5SRafal Jaworowski 
130075f1438bSOleksandr Tymoshenko 	mge_intr_rx_check(sc, int_cause, int_cause_ext);
130175f1438bSOleksandr Tymoshenko 
130275f1438bSOleksandr Tymoshenko 	MGE_RECEIVE_UNLOCK(sc);
130375f1438bSOleksandr Tymoshenko }
130475f1438bSOleksandr Tymoshenko 
130575f1438bSOleksandr Tymoshenko static void
130675f1438bSOleksandr Tymoshenko mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause,
130775f1438bSOleksandr Tymoshenko     uint32_t int_cause_ext)
130875f1438bSOleksandr Tymoshenko {
13099f55f5f5SRafal Jaworowski 	/* Check for resource error */
13109f55f5f5SRafal Jaworowski 	if (int_cause & MGE_PORT_INT_RXERRQ0) {
13119f55f5f5SRafal Jaworowski 		mge_reinit_rx(sc);
13129f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE,
131375f1438bSOleksandr Tymoshenko 		    ~(int_cause & MGE_PORT_INT_RXERRQ0));
13149f55f5f5SRafal Jaworowski 	}
13159f55f5f5SRafal Jaworowski 
13169f55f5f5SRafal Jaworowski 	int_cause &= MGE_PORT_INT_RXQ0;
13179f55f5f5SRafal Jaworowski 	int_cause_ext &= MGE_PORT_INT_EXT_RXOR;
13189f55f5f5SRafal Jaworowski 
13199f55f5f5SRafal Jaworowski 	if (int_cause || int_cause_ext) {
13209f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause);
13219f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext);
13229f55f5f5SRafal Jaworowski 		mge_intr_rx_locked(sc, -1);
13239f55f5f5SRafal Jaworowski 	}
13249f55f5f5SRafal Jaworowski }
13259f55f5f5SRafal Jaworowski 
13261abcdbd1SAttilio Rao static int
13279f55f5f5SRafal Jaworowski mge_intr_rx_locked(struct mge_softc *sc, int count)
13289f55f5f5SRafal Jaworowski {
13299f55f5f5SRafal Jaworowski 	struct ifnet *ifp = sc->ifp;
13309f55f5f5SRafal Jaworowski 	uint32_t status;
13319f55f5f5SRafal Jaworowski 	uint16_t bufsize;
13329f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper* dw;
13339f55f5f5SRafal Jaworowski 	struct mbuf *mb;
13341abcdbd1SAttilio Rao 	int rx_npkts = 0;
13359f55f5f5SRafal Jaworowski 
13369f55f5f5SRafal Jaworowski 	MGE_RECEIVE_LOCK_ASSERT(sc);
13379f55f5f5SRafal Jaworowski 
13389f55f5f5SRafal Jaworowski 	while (count != 0) {
13399f55f5f5SRafal Jaworowski 		dw = &sc->mge_rx_desc[sc->rx_desc_curr];
13409f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
13419f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
13429f55f5f5SRafal Jaworowski 
13439f55f5f5SRafal Jaworowski 		/* Get status */
13449f55f5f5SRafal Jaworowski 		status = dw->mge_desc->cmd_status;
13459f55f5f5SRafal Jaworowski 		bufsize = dw->mge_desc->buff_size;
13469f55f5f5SRafal Jaworowski 		if ((status & MGE_DMA_OWNED) != 0)
13479f55f5f5SRafal Jaworowski 			break;
13489f55f5f5SRafal Jaworowski 
13499f55f5f5SRafal Jaworowski 		if (dw->mge_desc->byte_count &&
13509f55f5f5SRafal Jaworowski 		    ~(status & MGE_ERR_SUMMARY)) {
13519f55f5f5SRafal Jaworowski 
13529f55f5f5SRafal Jaworowski 			bus_dmamap_sync(sc->mge_rx_dtag, dw->buffer_dmap,
13539f55f5f5SRafal Jaworowski 			    BUS_DMASYNC_POSTREAD);
13549f55f5f5SRafal Jaworowski 
13559f55f5f5SRafal Jaworowski 			mb = m_devget(dw->buffer->m_data,
13569f55f5f5SRafal Jaworowski 			    dw->mge_desc->byte_count - ETHER_CRC_LEN,
13579f55f5f5SRafal Jaworowski 			    0, ifp, NULL);
13589f55f5f5SRafal Jaworowski 
13595817716fSRafal Jaworowski 			if (mb == NULL)
13605817716fSRafal Jaworowski 				/* Give up if no mbufs */
13615817716fSRafal Jaworowski 				break;
13625817716fSRafal Jaworowski 
13639f55f5f5SRafal Jaworowski 			mb->m_len -= 2;
13649f55f5f5SRafal Jaworowski 			mb->m_pkthdr.len -= 2;
13659f55f5f5SRafal Jaworowski 			mb->m_data += 2;
13669f55f5f5SRafal Jaworowski 
1367b8fad6c0SFabien Thomas 			mb->m_pkthdr.rcvif = ifp;
1368b8fad6c0SFabien Thomas 
13699f55f5f5SRafal Jaworowski 			mge_offload_process_frame(ifp, mb, status,
13709f55f5f5SRafal Jaworowski 			    bufsize);
13719f55f5f5SRafal Jaworowski 
13729f55f5f5SRafal Jaworowski 			MGE_RECEIVE_UNLOCK(sc);
13739f55f5f5SRafal Jaworowski 			(*ifp->if_input)(ifp, mb);
13749f55f5f5SRafal Jaworowski 			MGE_RECEIVE_LOCK(sc);
13751abcdbd1SAttilio Rao 			rx_npkts++;
13769f55f5f5SRafal Jaworowski 		}
13779f55f5f5SRafal Jaworowski 
13789f55f5f5SRafal Jaworowski 		dw->mge_desc->byte_count = 0;
13799f55f5f5SRafal Jaworowski 		dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
13805817716fSRafal Jaworowski 		sc->rx_desc_curr = (++sc->rx_desc_curr % MGE_RX_DESC_NUM);
13819f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
13829f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
13839f55f5f5SRafal Jaworowski 
13849f55f5f5SRafal Jaworowski 		if (count > 0)
13859f55f5f5SRafal Jaworowski 			count -= 1;
13869f55f5f5SRafal Jaworowski 	}
13879f55f5f5SRafal Jaworowski 
1388c8dfaf38SGleb Smirnoff 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_npkts);
1389b8fad6c0SFabien Thomas 
13901abcdbd1SAttilio Rao 	return (rx_npkts);
13919f55f5f5SRafal Jaworowski }
13929f55f5f5SRafal Jaworowski 
13939f55f5f5SRafal Jaworowski static void
13949f55f5f5SRafal Jaworowski mge_intr_sum(void *arg)
13959f55f5f5SRafal Jaworowski {
13969f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
13979f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
13989f55f5f5SRafal Jaworowski 
13999f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
14009f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
14019f55f5f5SRafal Jaworowski }
14029f55f5f5SRafal Jaworowski 
14039f55f5f5SRafal Jaworowski static void
14049f55f5f5SRafal Jaworowski mge_intr_tx(void *arg)
14059f55f5f5SRafal Jaworowski {
14069f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
14079f55f5f5SRafal Jaworowski 	uint32_t int_cause_ext;
14089f55f5f5SRafal Jaworowski 
14099f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK(sc);
14109f55f5f5SRafal Jaworowski 
14119f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
14129f55f5f5SRafal Jaworowski 	if (sc->ifp->if_capenable & IFCAP_POLLING) {
14139f55f5f5SRafal Jaworowski 		MGE_TRANSMIT_UNLOCK(sc);
14149f55f5f5SRafal Jaworowski 		return;
14159f55f5f5SRafal Jaworowski 	}
14169f55f5f5SRafal Jaworowski #endif
14179f55f5f5SRafal Jaworowski 
14189f55f5f5SRafal Jaworowski 	/* Ack the interrupt */
14199f55f5f5SRafal Jaworowski 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
142075f1438bSOleksandr Tymoshenko 	MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext &
142175f1438bSOleksandr Tymoshenko 	    (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR)));
14229f55f5f5SRafal Jaworowski 
14239f55f5f5SRafal Jaworowski 	mge_intr_tx_locked(sc);
14249f55f5f5SRafal Jaworowski 
14259f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_UNLOCK(sc);
14269f55f5f5SRafal Jaworowski }
14279f55f5f5SRafal Jaworowski 
14289f55f5f5SRafal Jaworowski static void
14299f55f5f5SRafal Jaworowski mge_intr_tx_locked(struct mge_softc *sc)
14309f55f5f5SRafal Jaworowski {
14319f55f5f5SRafal Jaworowski 	struct ifnet *ifp = sc->ifp;
14329f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
14339f55f5f5SRafal Jaworowski 	struct mge_desc *desc;
14349f55f5f5SRafal Jaworowski 	uint32_t status;
14359f55f5f5SRafal Jaworowski 	int send = 0;
14369f55f5f5SRafal Jaworowski 
14379f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK_ASSERT(sc);
14389f55f5f5SRafal Jaworowski 
14399f55f5f5SRafal Jaworowski 	/* Disable watchdog */
14409f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
14419f55f5f5SRafal Jaworowski 
14429f55f5f5SRafal Jaworowski 	while (sc->tx_desc_used_count) {
14439f55f5f5SRafal Jaworowski 		/* Get the descriptor */
14449f55f5f5SRafal Jaworowski 		dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
14459f55f5f5SRafal Jaworowski 		desc = dw->mge_desc;
14469f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
14479f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
14489f55f5f5SRafal Jaworowski 
14499f55f5f5SRafal Jaworowski 		/* Get descriptor status */
14509f55f5f5SRafal Jaworowski 		status = desc->cmd_status;
14519f55f5f5SRafal Jaworowski 
14529f55f5f5SRafal Jaworowski 		if (status & MGE_DMA_OWNED)
14539f55f5f5SRafal Jaworowski 			break;
14549f55f5f5SRafal Jaworowski 
14559f55f5f5SRafal Jaworowski 		sc->tx_desc_used_idx =
1456c2ede4b3SMartin Blapp 			(++sc->tx_desc_used_idx) % MGE_TX_DESC_NUM;
14579f55f5f5SRafal Jaworowski 		sc->tx_desc_used_count--;
14589f55f5f5SRafal Jaworowski 
14599f55f5f5SRafal Jaworowski 		/* Update collision statistics */
14609f55f5f5SRafal Jaworowski 		if (status & MGE_ERR_SUMMARY) {
14619f55f5f5SRafal Jaworowski 			if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_LC)
1462c8dfaf38SGleb Smirnoff 				if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1);
14639f55f5f5SRafal Jaworowski 			if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_RL)
1464c8dfaf38SGleb Smirnoff 				if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 16);
14659f55f5f5SRafal Jaworowski 		}
14669f55f5f5SRafal Jaworowski 
14679f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
14689f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTWRITE);
14699f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap);
14709f55f5f5SRafal Jaworowski 		m_freem(dw->buffer);
14719f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
14729f55f5f5SRafal Jaworowski 		send++;
14739f55f5f5SRafal Jaworowski 
1474c8dfaf38SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
14759f55f5f5SRafal Jaworowski 	}
14769f55f5f5SRafal Jaworowski 
14779f55f5f5SRafal Jaworowski 	if (send) {
14789f55f5f5SRafal Jaworowski 		/* Now send anything that was pending */
14799f55f5f5SRafal Jaworowski 		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
14809f55f5f5SRafal Jaworowski 		mge_start_locked(ifp);
14819f55f5f5SRafal Jaworowski 	}
14829f55f5f5SRafal Jaworowski }
14839f55f5f5SRafal Jaworowski static int
14849f55f5f5SRafal Jaworowski mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
14859f55f5f5SRafal Jaworowski {
14869f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
14879f55f5f5SRafal Jaworowski 	struct ifreq *ifr = (struct ifreq *)data;
14889f55f5f5SRafal Jaworowski 	int mask, error;
14899f55f5f5SRafal Jaworowski 	uint32_t flags;
14909f55f5f5SRafal Jaworowski 
14919f55f5f5SRafal Jaworowski 	error = 0;
14929f55f5f5SRafal Jaworowski 
14939f55f5f5SRafal Jaworowski 	switch (command) {
14949f55f5f5SRafal Jaworowski 	case SIOCSIFFLAGS:
14959f55f5f5SRafal Jaworowski 		MGE_GLOBAL_LOCK(sc);
14969f55f5f5SRafal Jaworowski 
14979f55f5f5SRafal Jaworowski 		if (ifp->if_flags & IFF_UP) {
14989f55f5f5SRafal Jaworowski 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
14999f55f5f5SRafal Jaworowski 				flags = ifp->if_flags ^ sc->mge_if_flags;
15009f55f5f5SRafal Jaworowski 				if (flags & IFF_PROMISC)
15019f55f5f5SRafal Jaworowski 					mge_set_prom_mode(sc,
15029f55f5f5SRafal Jaworowski 					    MGE_RX_DEFAULT_QUEUE);
15039f55f5f5SRafal Jaworowski 
15049f55f5f5SRafal Jaworowski 				if (flags & IFF_ALLMULTI)
15059f55f5f5SRafal Jaworowski 					mge_setup_multicast(sc);
15069f55f5f5SRafal Jaworowski 			} else
15079f55f5f5SRafal Jaworowski 				mge_init_locked(sc);
15089f55f5f5SRafal Jaworowski 		}
15099f55f5f5SRafal Jaworowski 		else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
15109f55f5f5SRafal Jaworowski 			mge_stop(sc);
15119f55f5f5SRafal Jaworowski 
15129f55f5f5SRafal Jaworowski 		sc->mge_if_flags = ifp->if_flags;
15139f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
15149f55f5f5SRafal Jaworowski 		break;
15159f55f5f5SRafal Jaworowski 	case SIOCADDMULTI:
15169f55f5f5SRafal Jaworowski 	case SIOCDELMULTI:
15179f55f5f5SRafal Jaworowski 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
15189f55f5f5SRafal Jaworowski 			MGE_GLOBAL_LOCK(sc);
15199f55f5f5SRafal Jaworowski 			mge_setup_multicast(sc);
15209f55f5f5SRafal Jaworowski 			MGE_GLOBAL_UNLOCK(sc);
15219f55f5f5SRafal Jaworowski 		}
15229f55f5f5SRafal Jaworowski 		break;
15239f55f5f5SRafal Jaworowski 	case SIOCSIFCAP:
15249f55f5f5SRafal Jaworowski 		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
15259f55f5f5SRafal Jaworowski 		if (mask & IFCAP_HWCSUM) {
15269f55f5f5SRafal Jaworowski 			ifp->if_capenable &= ~IFCAP_HWCSUM;
15279f55f5f5SRafal Jaworowski 			ifp->if_capenable |= IFCAP_HWCSUM & ifr->ifr_reqcap;
15289f55f5f5SRafal Jaworowski 			if (ifp->if_capenable & IFCAP_TXCSUM)
15299f55f5f5SRafal Jaworowski 				ifp->if_hwassist = MGE_CHECKSUM_FEATURES;
15309f55f5f5SRafal Jaworowski 			else
15319f55f5f5SRafal Jaworowski 				ifp->if_hwassist = 0;
15329f55f5f5SRafal Jaworowski 		}
15339f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
15349f55f5f5SRafal Jaworowski 		if (mask & IFCAP_POLLING) {
15359f55f5f5SRafal Jaworowski 			if (ifr->ifr_reqcap & IFCAP_POLLING) {
15369f55f5f5SRafal Jaworowski 				error = ether_poll_register(mge_poll, ifp);
15379f55f5f5SRafal Jaworowski 				if (error)
15389f55f5f5SRafal Jaworowski 					return(error);
15399f55f5f5SRafal Jaworowski 
15409f55f5f5SRafal Jaworowski 				MGE_GLOBAL_LOCK(sc);
15419f55f5f5SRafal Jaworowski 				mge_intrs_ctrl(sc, 0);
15429f55f5f5SRafal Jaworowski 				ifp->if_capenable |= IFCAP_POLLING;
15439f55f5f5SRafal Jaworowski 				MGE_GLOBAL_UNLOCK(sc);
15449f55f5f5SRafal Jaworowski 			} else {
15459f55f5f5SRafal Jaworowski 				error = ether_poll_deregister(ifp);
15469f55f5f5SRafal Jaworowski 				MGE_GLOBAL_LOCK(sc);
15479f55f5f5SRafal Jaworowski 				mge_intrs_ctrl(sc, 1);
15489f55f5f5SRafal Jaworowski 				ifp->if_capenable &= ~IFCAP_POLLING;
15499f55f5f5SRafal Jaworowski 				MGE_GLOBAL_UNLOCK(sc);
15509f55f5f5SRafal Jaworowski 			}
15519f55f5f5SRafal Jaworowski 		}
15529f55f5f5SRafal Jaworowski #endif
15539f55f5f5SRafal Jaworowski 		break;
15549f55f5f5SRafal Jaworowski 	case SIOCGIFMEDIA: /* fall through */
15559f55f5f5SRafal Jaworowski 	case SIOCSIFMEDIA:
15563c71b84fSZbigniew Bodek 		/*
15573c71b84fSZbigniew Bodek 		 * Setting up media type via ioctls is *not* supported for MAC
15583c71b84fSZbigniew Bodek 		 * which is connected to switch. Use etherswitchcfg.
15593c71b84fSZbigniew Bodek 		 */
15603c71b84fSZbigniew Bodek 		if (!sc->phy_attached && (command == SIOCSIFMEDIA))
15613c71b84fSZbigniew Bodek 			return (0);
15623c71b84fSZbigniew Bodek 		else if (!sc->phy_attached) {
15633c71b84fSZbigniew Bodek 			error = ifmedia_ioctl(ifp, ifr, &sc->mge_ifmedia,
15643c71b84fSZbigniew Bodek 			    command);
15653c71b84fSZbigniew Bodek 			break;
15663c71b84fSZbigniew Bodek 		}
15673c71b84fSZbigniew Bodek 
15689f55f5f5SRafal Jaworowski 		if (IFM_SUBTYPE(ifr->ifr_media) == IFM_1000_T
15699f55f5f5SRafal Jaworowski 		    && !(ifr->ifr_media & IFM_FDX)) {
15709f55f5f5SRafal Jaworowski 			device_printf(sc->dev,
15719f55f5f5SRafal Jaworowski 			    "1000baseTX half-duplex unsupported\n");
15729f55f5f5SRafal Jaworowski 			return 0;
15739f55f5f5SRafal Jaworowski 		}
15749f55f5f5SRafal Jaworowski 		error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command);
15759f55f5f5SRafal Jaworowski 		break;
15769f55f5f5SRafal Jaworowski 	default:
15779f55f5f5SRafal Jaworowski 		error = ether_ioctl(ifp, command, data);
15789f55f5f5SRafal Jaworowski 	}
15799f55f5f5SRafal Jaworowski 	return (error);
15809f55f5f5SRafal Jaworowski }
15819f55f5f5SRafal Jaworowski 
15829f55f5f5SRafal Jaworowski static int
15839f55f5f5SRafal Jaworowski mge_miibus_readreg(device_t dev, int phy, int reg)
15849f55f5f5SRafal Jaworowski {
1585db5ef4fcSRafal Jaworowski 	struct mge_softc *sc;
1586db5ef4fcSRafal Jaworowski 	sc = device_get_softc(dev);
15879f55f5f5SRafal Jaworowski 
15883c71b84fSZbigniew Bodek 	KASSERT(!switch_attached, ("miibus used with switch attached"));
15899f55f5f5SRafal Jaworowski 
15903c71b84fSZbigniew Bodek 	return (mv_read_ext_phy(dev, phy, reg));
15919f55f5f5SRafal Jaworowski }
15929f55f5f5SRafal Jaworowski 
15938e45f0b7SAndriy Gapon static int
15949f55f5f5SRafal Jaworowski mge_miibus_writereg(device_t dev, int phy, int reg, int value)
15959f55f5f5SRafal Jaworowski {
1596db5ef4fcSRafal Jaworowski 	struct mge_softc *sc;
1597db5ef4fcSRafal Jaworowski 	sc = device_get_softc(dev);
1598db5ef4fcSRafal Jaworowski 
15993c71b84fSZbigniew Bodek 	KASSERT(!switch_attached, ("miibus used with switch attached"));
16009f55f5f5SRafal Jaworowski 
16013c71b84fSZbigniew Bodek 	mv_write_ext_phy(dev, phy, reg, value);
16029f55f5f5SRafal Jaworowski 
16038e45f0b7SAndriy Gapon 	return (0);
16049f55f5f5SRafal Jaworowski }
16059f55f5f5SRafal Jaworowski 
16069f55f5f5SRafal Jaworowski static int
16079f55f5f5SRafal Jaworowski mge_probe(device_t dev)
16089f55f5f5SRafal Jaworowski {
16099f55f5f5SRafal Jaworowski 
1610add35ed5SIan Lepore 	if (!ofw_bus_status_okay(dev))
1611add35ed5SIan Lepore 		return (ENXIO);
1612add35ed5SIan Lepore 
1613db5ef4fcSRafal Jaworowski 	if (!ofw_bus_is_compatible(dev, "mrvl,ge"))
1614db5ef4fcSRafal Jaworowski 		return (ENXIO);
1615db5ef4fcSRafal Jaworowski 
16169f55f5f5SRafal Jaworowski 	device_set_desc(dev, "Marvell Gigabit Ethernet controller");
16179f55f5f5SRafal Jaworowski 	return (BUS_PROBE_DEFAULT);
16189f55f5f5SRafal Jaworowski }
16199f55f5f5SRafal Jaworowski 
16209f55f5f5SRafal Jaworowski static int
16219f55f5f5SRafal Jaworowski mge_resume(device_t dev)
16229f55f5f5SRafal Jaworowski {
16239f55f5f5SRafal Jaworowski 
16249f55f5f5SRafal Jaworowski 	device_printf(dev, "%s\n", __FUNCTION__);
16259f55f5f5SRafal Jaworowski 	return (0);
16269f55f5f5SRafal Jaworowski }
16279f55f5f5SRafal Jaworowski 
16289f55f5f5SRafal Jaworowski static int
16299f55f5f5SRafal Jaworowski mge_shutdown(device_t dev)
16309f55f5f5SRafal Jaworowski {
16319f55f5f5SRafal Jaworowski 	struct mge_softc *sc = device_get_softc(dev);
16329f55f5f5SRafal Jaworowski 
16339f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
16349f55f5f5SRafal Jaworowski 
16359f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
16369f55f5f5SRafal Jaworowski         if (sc->ifp->if_capenable & IFCAP_POLLING)
16379f55f5f5SRafal Jaworowski 		ether_poll_deregister(sc->ifp);
16389f55f5f5SRafal Jaworowski #endif
16399f55f5f5SRafal Jaworowski 
16409f55f5f5SRafal Jaworowski 	mge_stop(sc);
16419f55f5f5SRafal Jaworowski 
16429f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
16439f55f5f5SRafal Jaworowski 
16449f55f5f5SRafal Jaworowski 	return (0);
16459f55f5f5SRafal Jaworowski }
16469f55f5f5SRafal Jaworowski 
16479f55f5f5SRafal Jaworowski static int
16489f55f5f5SRafal Jaworowski mge_encap(struct mge_softc *sc, struct mbuf *m0)
16499f55f5f5SRafal Jaworowski {
16509f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw = NULL;
16519f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
16529f55f5f5SRafal Jaworowski 	bus_dma_segment_t segs[MGE_TX_DESC_NUM];
16539f55f5f5SRafal Jaworowski 	bus_dmamap_t mapp;
16549f55f5f5SRafal Jaworowski 	int error;
16559f55f5f5SRafal Jaworowski 	int seg, nsegs;
16569f55f5f5SRafal Jaworowski 	int desc_no;
16579f55f5f5SRafal Jaworowski 
16589f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
16599f55f5f5SRafal Jaworowski 
16609f55f5f5SRafal Jaworowski 	/* Fetch unused map */
16619f55f5f5SRafal Jaworowski 	desc_no = sc->tx_desc_curr;
16629f55f5f5SRafal Jaworowski 	dw = &sc->mge_tx_desc[desc_no];
16639f55f5f5SRafal Jaworowski 	mapp = dw->buffer_dmap;
16649f55f5f5SRafal Jaworowski 
16659f55f5f5SRafal Jaworowski 	/* Create mapping in DMA memory */
16669f55f5f5SRafal Jaworowski 	error = bus_dmamap_load_mbuf_sg(sc->mge_tx_dtag, mapp, m0, segs, &nsegs,
16679f55f5f5SRafal Jaworowski 	    BUS_DMA_NOWAIT);
1668b8fad6c0SFabien Thomas 	if (error != 0) {
1669b8fad6c0SFabien Thomas 		m_freem(m0);
1670b8fad6c0SFabien Thomas 		return (error);
1671b8fad6c0SFabien Thomas 	}
1672b8fad6c0SFabien Thomas 
1673b8fad6c0SFabien Thomas 	/* Only one segment is supported. */
1674b8fad6c0SFabien Thomas 	if (nsegs != 1) {
16759f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, mapp);
1676b8fad6c0SFabien Thomas 		m_freem(m0);
1677b8fad6c0SFabien Thomas 		return (-1);
16789f55f5f5SRafal Jaworowski 	}
16799f55f5f5SRafal Jaworowski 
16809f55f5f5SRafal Jaworowski 	bus_dmamap_sync(sc->mge_tx_dtag, mapp, BUS_DMASYNC_PREWRITE);
16819f55f5f5SRafal Jaworowski 
16829f55f5f5SRafal Jaworowski 	/* Everything is ok, now we can send buffers */
16839f55f5f5SRafal Jaworowski 	for (seg = 0; seg < nsegs; seg++) {
16849f55f5f5SRafal Jaworowski 		dw->mge_desc->byte_count = segs[seg].ds_len;
16859f55f5f5SRafal Jaworowski 		dw->mge_desc->buffer = segs[seg].ds_addr;
16869f55f5f5SRafal Jaworowski 		dw->buffer = m0;
168775f1438bSOleksandr Tymoshenko 		dw->mge_desc->cmd_status = 0;
16889f55f5f5SRafal Jaworowski 		if (seg == 0)
16899f55f5f5SRafal Jaworowski 			mge_offload_setup_descriptor(sc, dw);
169075f1438bSOleksandr Tymoshenko 		dw->mge_desc->cmd_status |= MGE_TX_LAST | MGE_TX_FIRST |
169175f1438bSOleksandr Tymoshenko 		    MGE_TX_ETH_CRC | MGE_TX_EN_INT | MGE_TX_PADDING |
169275f1438bSOleksandr Tymoshenko 		    MGE_DMA_OWNED;
16939f55f5f5SRafal Jaworowski 	}
16949f55f5f5SRafal Jaworowski 
1695d6bdd318SRafal Jaworowski 	bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
16969f55f5f5SRafal Jaworowski 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
16979f55f5f5SRafal Jaworowski 
16989f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = (++sc->tx_desc_curr) % MGE_TX_DESC_NUM;
16999f55f5f5SRafal Jaworowski 	sc->tx_desc_used_count++;
17009f55f5f5SRafal Jaworowski 	return (0);
17019f55f5f5SRafal Jaworowski }
17029f55f5f5SRafal Jaworowski 
17039f55f5f5SRafal Jaworowski static void
17049f55f5f5SRafal Jaworowski mge_tick(void *msc)
17059f55f5f5SRafal Jaworowski {
17069f55f5f5SRafal Jaworowski 	struct mge_softc *sc = msc;
17079f55f5f5SRafal Jaworowski 
17083c71b84fSZbigniew Bodek 	KASSERT(sc->phy_attached == 1, ("mge_tick while PHY not attached"));
17093c71b84fSZbigniew Bodek 
17103c71b84fSZbigniew Bodek 	MGE_GLOBAL_LOCK(sc);
17113c71b84fSZbigniew Bodek 
17129f55f5f5SRafal Jaworowski 	/* Check for TX timeout */
17139f55f5f5SRafal Jaworowski 	mge_watchdog(sc);
17149f55f5f5SRafal Jaworowski 
17159f55f5f5SRafal Jaworowski 	mii_tick(sc->mii);
17169f55f5f5SRafal Jaworowski 
17179f55f5f5SRafal Jaworowski 	/* Check for media type change */
17189f55f5f5SRafal Jaworowski 	if(sc->mge_media_status != sc->mii->mii_media.ifm_media)
17199f55f5f5SRafal Jaworowski 		mge_ifmedia_upd(sc->ifp);
17209f55f5f5SRafal Jaworowski 
17213c71b84fSZbigniew Bodek 	MGE_GLOBAL_UNLOCK(sc);
17223c71b84fSZbigniew Bodek 
17239f55f5f5SRafal Jaworowski 	/* Schedule another timeout one second from now */
17249f55f5f5SRafal Jaworowski 	callout_reset(&sc->wd_callout, hz, mge_tick, sc);
17253c71b84fSZbigniew Bodek 
17263c71b84fSZbigniew Bodek 	return;
17279f55f5f5SRafal Jaworowski }
17289f55f5f5SRafal Jaworowski 
17299f55f5f5SRafal Jaworowski static void
17309f55f5f5SRafal Jaworowski mge_watchdog(struct mge_softc *sc)
17319f55f5f5SRafal Jaworowski {
17329f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
17339f55f5f5SRafal Jaworowski 
17349f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
17359f55f5f5SRafal Jaworowski 
17369f55f5f5SRafal Jaworowski 	if (sc->wd_timer == 0 || --sc->wd_timer) {
17379f55f5f5SRafal Jaworowski 		return;
17389f55f5f5SRafal Jaworowski 	}
17399f55f5f5SRafal Jaworowski 
1740c8dfaf38SGleb Smirnoff 	if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
17419f55f5f5SRafal Jaworowski 	if_printf(ifp, "watchdog timeout\n");
17429f55f5f5SRafal Jaworowski 
17439f55f5f5SRafal Jaworowski 	mge_stop(sc);
17449f55f5f5SRafal Jaworowski 	mge_init_locked(sc);
17459f55f5f5SRafal Jaworowski }
17469f55f5f5SRafal Jaworowski 
17479f55f5f5SRafal Jaworowski static void
17489f55f5f5SRafal Jaworowski mge_start(struct ifnet *ifp)
17499f55f5f5SRafal Jaworowski {
17509f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
17519f55f5f5SRafal Jaworowski 
17529f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK(sc);
17539f55f5f5SRafal Jaworowski 
17549f55f5f5SRafal Jaworowski 	mge_start_locked(ifp);
17559f55f5f5SRafal Jaworowski 
17569f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_UNLOCK(sc);
17579f55f5f5SRafal Jaworowski }
17589f55f5f5SRafal Jaworowski 
17599f55f5f5SRafal Jaworowski static void
17609f55f5f5SRafal Jaworowski mge_start_locked(struct ifnet *ifp)
17619f55f5f5SRafal Jaworowski {
17629f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
17639f55f5f5SRafal Jaworowski 	struct mbuf *m0, *mtmp;
17649f55f5f5SRafal Jaworowski 	uint32_t reg_val, queued = 0;
17659f55f5f5SRafal Jaworowski 
17669f55f5f5SRafal Jaworowski 	sc = ifp->if_softc;
17679f55f5f5SRafal Jaworowski 
17689f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK_ASSERT(sc);
17699f55f5f5SRafal Jaworowski 
17709f55f5f5SRafal Jaworowski 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
17719f55f5f5SRafal Jaworowski 	    IFF_DRV_RUNNING)
17729f55f5f5SRafal Jaworowski 		return;
17739f55f5f5SRafal Jaworowski 
17749f55f5f5SRafal Jaworowski 	for (;;) {
17759f55f5f5SRafal Jaworowski 		/* Get packet from the queue */
17769f55f5f5SRafal Jaworowski 		IF_DEQUEUE(&ifp->if_snd, m0);
17779f55f5f5SRafal Jaworowski 		if (m0 == NULL)
17789f55f5f5SRafal Jaworowski 			break;
17799f55f5f5SRafal Jaworowski 
1780b8fad6c0SFabien Thomas 		if (m0->m_pkthdr.csum_flags & (CSUM_IP|CSUM_TCP|CSUM_UDP) ||
1781b8fad6c0SFabien Thomas 		    m0->m_flags & M_VLANTAG) {
1782b8fad6c0SFabien Thomas 			if (M_WRITABLE(m0) == 0) {
1783b8fad6c0SFabien Thomas 				mtmp = m_dup(m0, M_NOWAIT);
1784b8fad6c0SFabien Thomas 				m_freem(m0);
1785b8fad6c0SFabien Thomas 				if (mtmp == NULL)
1786b8fad6c0SFabien Thomas 					continue;
1787b8fad6c0SFabien Thomas 				m0 = mtmp;
1788b8fad6c0SFabien Thomas 			}
1789b8fad6c0SFabien Thomas 		}
1790b8fad6c0SFabien Thomas 		/* The driver support only one DMA fragment. */
1791b8fad6c0SFabien Thomas 		if (m0->m_next != NULL) {
1792c6499eccSGleb Smirnoff 			mtmp = m_defrag(m0, M_NOWAIT);
17934ac30cc1SZbigniew Bodek 			if (mtmp != NULL)
17949f55f5f5SRafal Jaworowski 				m0 = mtmp;
1795b8fad6c0SFabien Thomas 		}
17969f55f5f5SRafal Jaworowski 
1797b8fad6c0SFabien Thomas 		/* Check for free descriptors */
1798b8fad6c0SFabien Thomas 		if (sc->tx_desc_used_count + 1 >= MGE_TX_DESC_NUM) {
17999f55f5f5SRafal Jaworowski 			IF_PREPEND(&ifp->if_snd, m0);
18009f55f5f5SRafal Jaworowski 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
18019f55f5f5SRafal Jaworowski 			break;
18029f55f5f5SRafal Jaworowski 		}
1803b8fad6c0SFabien Thomas 
1804b8fad6c0SFabien Thomas 		if (mge_encap(sc, m0) != 0)
1805b8fad6c0SFabien Thomas 			break;
1806b8fad6c0SFabien Thomas 
18079f55f5f5SRafal Jaworowski 		queued++;
18089f55f5f5SRafal Jaworowski 		BPF_MTAP(ifp, m0);
18099f55f5f5SRafal Jaworowski 	}
18109f55f5f5SRafal Jaworowski 
18119f55f5f5SRafal Jaworowski 	if (queued) {
18129f55f5f5SRafal Jaworowski 		/* Enable transmitter and watchdog timer */
18139f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD);
18149f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_ENABLE_TXQ);
18159f55f5f5SRafal Jaworowski 		sc->wd_timer = 5;
18169f55f5f5SRafal Jaworowski 	}
18179f55f5f5SRafal Jaworowski }
18189f55f5f5SRafal Jaworowski 
18199f55f5f5SRafal Jaworowski static void
18209f55f5f5SRafal Jaworowski mge_stop(struct mge_softc *sc)
18219f55f5f5SRafal Jaworowski {
18229f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
18239f55f5f5SRafal Jaworowski 	volatile uint32_t reg_val, status;
18249f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
18259f55f5f5SRafal Jaworowski 	struct mge_desc *desc;
18269f55f5f5SRafal Jaworowski 	int count;
18279f55f5f5SRafal Jaworowski 
18289f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
18299f55f5f5SRafal Jaworowski 
18309f55f5f5SRafal Jaworowski 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
18319f55f5f5SRafal Jaworowski 		return;
18329f55f5f5SRafal Jaworowski 
18339f55f5f5SRafal Jaworowski 	/* Stop tick engine */
18349f55f5f5SRafal Jaworowski 	callout_stop(&sc->wd_callout);
18359f55f5f5SRafal Jaworowski 
18369f55f5f5SRafal Jaworowski 	/* Disable interface */
18379f55f5f5SRafal Jaworowski 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
18389f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
18399f55f5f5SRafal Jaworowski 
18409f55f5f5SRafal Jaworowski 	/* Disable interrupts */
18419f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 0);
18429f55f5f5SRafal Jaworowski 
18439f55f5f5SRafal Jaworowski 	/* Disable Rx and Tx */
18449f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD);
18459f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_DISABLE_TXQ);
18469f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_DISABLE_RXQ_ALL);
18479f55f5f5SRafal Jaworowski 
18489f55f5f5SRafal Jaworowski 	/* Remove pending data from TX queue */
18495817716fSRafal Jaworowski 	while (sc->tx_desc_used_idx != sc->tx_desc_curr &&
18505817716fSRafal Jaworowski 	    sc->tx_desc_used_count) {
18519f55f5f5SRafal Jaworowski 		/* Get the descriptor */
18529f55f5f5SRafal Jaworowski 		dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
18539f55f5f5SRafal Jaworowski 		desc = dw->mge_desc;
18549f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
18559f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
18569f55f5f5SRafal Jaworowski 
18579f55f5f5SRafal Jaworowski 		/* Get descriptor status */
18589f55f5f5SRafal Jaworowski 		status = desc->cmd_status;
18599f55f5f5SRafal Jaworowski 
18609f55f5f5SRafal Jaworowski 		if (status & MGE_DMA_OWNED)
18619f55f5f5SRafal Jaworowski 			break;
18629f55f5f5SRafal Jaworowski 
18639f55f5f5SRafal Jaworowski 		sc->tx_desc_used_idx = (++sc->tx_desc_used_idx) %
18649f55f5f5SRafal Jaworowski 		    MGE_TX_DESC_NUM;
18655817716fSRafal Jaworowski 		sc->tx_desc_used_count--;
18669f55f5f5SRafal Jaworowski 
18679f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
18689f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTWRITE);
18699f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap);
18709f55f5f5SRafal Jaworowski 
18719f55f5f5SRafal Jaworowski 		m_freem(dw->buffer);
18729f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
18739f55f5f5SRafal Jaworowski 	}
18749f55f5f5SRafal Jaworowski 
18759f55f5f5SRafal Jaworowski 	/* Wait for end of transmission */
18769f55f5f5SRafal Jaworowski 	count = 0x100000;
18779f55f5f5SRafal Jaworowski 	while (count--) {
18789f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_PORT_STATUS);
18799f55f5f5SRafal Jaworowski 		if ( !(reg_val & MGE_STATUS_TX_IN_PROG) &&
18809f55f5f5SRafal Jaworowski 		    (reg_val & MGE_STATUS_TX_FIFO_EMPTY))
18819f55f5f5SRafal Jaworowski 			break;
18829f55f5f5SRafal Jaworowski 		DELAY(100);
18839f55f5f5SRafal Jaworowski 	}
18849f55f5f5SRafal Jaworowski 
18854ac30cc1SZbigniew Bodek 	if (count == 0)
18864ac30cc1SZbigniew Bodek 		if_printf(ifp,
18874ac30cc1SZbigniew Bodek 		    "%s: timeout while waiting for end of transmission\n",
18889f55f5f5SRafal Jaworowski 		    __FUNCTION__);
18899f55f5f5SRafal Jaworowski 
18909f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL);
18919f55f5f5SRafal Jaworowski 	reg_val &= ~(PORT_SERIAL_ENABLE);
18929f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL ,reg_val);
18939f55f5f5SRafal Jaworowski }
18949f55f5f5SRafal Jaworowski 
18959f55f5f5SRafal Jaworowski static int
18969f55f5f5SRafal Jaworowski mge_suspend(device_t dev)
18979f55f5f5SRafal Jaworowski {
18989f55f5f5SRafal Jaworowski 
18999f55f5f5SRafal Jaworowski 	device_printf(dev, "%s\n", __FUNCTION__);
19009f55f5f5SRafal Jaworowski 	return (0);
19019f55f5f5SRafal Jaworowski }
19029f55f5f5SRafal Jaworowski 
19039f55f5f5SRafal Jaworowski static void
19049f55f5f5SRafal Jaworowski mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame,
19059f55f5f5SRafal Jaworowski     uint32_t status, uint16_t bufsize)
19069f55f5f5SRafal Jaworowski {
19079f55f5f5SRafal Jaworowski 	int csum_flags = 0;
19089f55f5f5SRafal Jaworowski 
19099f55f5f5SRafal Jaworowski 	if (ifp->if_capenable & IFCAP_RXCSUM) {
19109f55f5f5SRafal Jaworowski 		if ((status & MGE_RX_L3_IS_IP) && (status & MGE_RX_IP_OK))
19119f55f5f5SRafal Jaworowski 			csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID;
19129f55f5f5SRafal Jaworowski 
19139f55f5f5SRafal Jaworowski 		if ((bufsize & MGE_RX_IP_FRAGMENT) == 0 &&
19149f55f5f5SRafal Jaworowski 		    (MGE_RX_L4_IS_TCP(status) || MGE_RX_L4_IS_UDP(status)) &&
19159f55f5f5SRafal Jaworowski 		    (status & MGE_RX_L4_CSUM_OK)) {
19169f55f5f5SRafal Jaworowski 			csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
19179f55f5f5SRafal Jaworowski 			frame->m_pkthdr.csum_data = 0xFFFF;
19189f55f5f5SRafal Jaworowski 		}
19199f55f5f5SRafal Jaworowski 
19209f55f5f5SRafal Jaworowski 		frame->m_pkthdr.csum_flags = csum_flags;
19219f55f5f5SRafal Jaworowski 	}
19229f55f5f5SRafal Jaworowski }
19239f55f5f5SRafal Jaworowski 
19249f55f5f5SRafal Jaworowski static void
19259f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(struct mge_softc *sc, struct mge_desc_wrapper *dw)
19269f55f5f5SRafal Jaworowski {
19279f55f5f5SRafal Jaworowski 	struct mbuf *m0 = dw->buffer;
19289f55f5f5SRafal Jaworowski 	struct ether_vlan_header *eh = mtod(m0, struct ether_vlan_header *);
19299f55f5f5SRafal Jaworowski 	int csum_flags = m0->m_pkthdr.csum_flags;
19309f55f5f5SRafal Jaworowski 	int cmd_status = 0;
19319f55f5f5SRafal Jaworowski 	struct ip *ip;
19329f55f5f5SRafal Jaworowski 	int ehlen, etype;
19339f55f5f5SRafal Jaworowski 
19344ac30cc1SZbigniew Bodek 	if (csum_flags != 0) {
19359f55f5f5SRafal Jaworowski 		if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
19369f55f5f5SRafal Jaworowski 			etype = ntohs(eh->evl_proto);
19379f55f5f5SRafal Jaworowski 			ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
19389f55f5f5SRafal Jaworowski 			csum_flags |= MGE_TX_VLAN_TAGGED;
19399f55f5f5SRafal Jaworowski 		} else {
19409f55f5f5SRafal Jaworowski 			etype = ntohs(eh->evl_encap_proto);
19419f55f5f5SRafal Jaworowski 			ehlen = ETHER_HDR_LEN;
19429f55f5f5SRafal Jaworowski 		}
19439f55f5f5SRafal Jaworowski 
19449f55f5f5SRafal Jaworowski 		if (etype != ETHERTYPE_IP) {
19459f55f5f5SRafal Jaworowski 			if_printf(sc->ifp,
19469f55f5f5SRafal Jaworowski 			    "TCP/IP Offload enabled for unsupported "
19479f55f5f5SRafal Jaworowski 			    "protocol!\n");
19489f55f5f5SRafal Jaworowski 			return;
19499f55f5f5SRafal Jaworowski 		}
19509f55f5f5SRafal Jaworowski 
19519f55f5f5SRafal Jaworowski 		ip = (struct ip *)(m0->m_data + ehlen);
19529f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_IP_HDR_SIZE(ip->ip_hl);
19539f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_NOT_FRAGMENT;
19549f55f5f5SRafal Jaworowski 	}
19559f55f5f5SRafal Jaworowski 
19569f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_IP)
19579f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_IP_CSUM;
19589f55f5f5SRafal Jaworowski 
19599f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_TCP)
19609f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_L4_CSUM;
19619f55f5f5SRafal Jaworowski 
19629f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_UDP)
19639f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_L4_CSUM | MGE_TX_UDP;
19649f55f5f5SRafal Jaworowski 
19659f55f5f5SRafal Jaworowski 	dw->mge_desc->cmd_status |= cmd_status;
19669f55f5f5SRafal Jaworowski }
19679f55f5f5SRafal Jaworowski 
19689f55f5f5SRafal Jaworowski static void
19699f55f5f5SRafal Jaworowski mge_intrs_ctrl(struct mge_softc *sc, int enable)
19709f55f5f5SRafal Jaworowski {
19719f55f5f5SRafal Jaworowski 
19729f55f5f5SRafal Jaworowski 	if (enable) {
19739f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK , MGE_PORT_INT_RXQ0 |
19749f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXTEND | MGE_PORT_INT_RXERRQ0);
19759f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT , MGE_PORT_INT_EXT_TXERR0 |
19769f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXT_RXOR | MGE_PORT_INT_EXT_TXUR |
19779f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXT_TXBUF0);
19789f55f5f5SRafal Jaworowski 	} else {
19799f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_INT_CAUSE, 0x0);
19809f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_INT_MASK, 0x0);
19819f55f5f5SRafal Jaworowski 
19829f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE, 0x0);
19839f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, 0x0);
19849f55f5f5SRafal Jaworowski 
19859f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK, 0x0);
19869f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT, 0x0);
19879f55f5f5SRafal Jaworowski 	}
19889f55f5f5SRafal Jaworowski }
19899f55f5f5SRafal Jaworowski 
19909f55f5f5SRafal Jaworowski static uint8_t
19919f55f5f5SRafal Jaworowski mge_crc8(uint8_t *data, int size)
19929f55f5f5SRafal Jaworowski {
19939f55f5f5SRafal Jaworowski 	uint8_t crc = 0;
19949f55f5f5SRafal Jaworowski 	static const uint8_t ct[256] = {
19959f55f5f5SRafal Jaworowski 		0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
19969f55f5f5SRafal Jaworowski 		0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
19979f55f5f5SRafal Jaworowski 		0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
19989f55f5f5SRafal Jaworowski 		0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
19999f55f5f5SRafal Jaworowski 		0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
20009f55f5f5SRafal Jaworowski 		0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
20019f55f5f5SRafal Jaworowski 		0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
20029f55f5f5SRafal Jaworowski 		0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
20039f55f5f5SRafal Jaworowski 		0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
20049f55f5f5SRafal Jaworowski 		0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
20059f55f5f5SRafal Jaworowski 		0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
20069f55f5f5SRafal Jaworowski 		0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
20079f55f5f5SRafal Jaworowski 		0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
20089f55f5f5SRafal Jaworowski 		0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
20099f55f5f5SRafal Jaworowski 		0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
20109f55f5f5SRafal Jaworowski 		0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
20119f55f5f5SRafal Jaworowski 		0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
20129f55f5f5SRafal Jaworowski 		0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
20139f55f5f5SRafal Jaworowski 		0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
20149f55f5f5SRafal Jaworowski 		0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
20159f55f5f5SRafal Jaworowski 		0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
20169f55f5f5SRafal Jaworowski 		0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
20179f55f5f5SRafal Jaworowski 		0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
20189f55f5f5SRafal Jaworowski 		0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
20199f55f5f5SRafal Jaworowski 		0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
20209f55f5f5SRafal Jaworowski 		0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
20219f55f5f5SRafal Jaworowski 		0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
20229f55f5f5SRafal Jaworowski 		0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
20239f55f5f5SRafal Jaworowski 		0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
20249f55f5f5SRafal Jaworowski 		0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
20259f55f5f5SRafal Jaworowski 		0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
20269f55f5f5SRafal Jaworowski 		0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
20279f55f5f5SRafal Jaworowski 	};
20289f55f5f5SRafal Jaworowski 
20299f55f5f5SRafal Jaworowski 	while(size--)
20309f55f5f5SRafal Jaworowski 		crc = ct[crc ^ *(data++)];
20319f55f5f5SRafal Jaworowski 
20329f55f5f5SRafal Jaworowski 	return(crc);
20339f55f5f5SRafal Jaworowski }
20349f55f5f5SRafal Jaworowski 
203553dc8c23SGleb Smirnoff struct mge_hash_maddr_ctx {
203653dc8c23SGleb Smirnoff 	uint32_t smt[MGE_MCAST_REG_NUMBER];
203753dc8c23SGleb Smirnoff 	uint32_t omt[MGE_MCAST_REG_NUMBER];
203853dc8c23SGleb Smirnoff };
203953dc8c23SGleb Smirnoff 
204053dc8c23SGleb Smirnoff static u_int
204153dc8c23SGleb Smirnoff mge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
204253dc8c23SGleb Smirnoff {
204353dc8c23SGleb Smirnoff 	static const uint8_t special[5] = { 0x01, 0x00, 0x5E, 0x00, 0x00 };
204453dc8c23SGleb Smirnoff 	struct mge_hash_maddr_ctx *ctx = arg;
204553dc8c23SGleb Smirnoff 	static const uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1;
204653dc8c23SGleb Smirnoff 	uint8_t *mac;
204753dc8c23SGleb Smirnoff 	int i;
204853dc8c23SGleb Smirnoff 
204953dc8c23SGleb Smirnoff 	mac = LLADDR(sdl);
205053dc8c23SGleb Smirnoff 	if (memcmp(mac, special, sizeof(special)) == 0) {
205153dc8c23SGleb Smirnoff 		i = mac[5];
205253dc8c23SGleb Smirnoff 		ctx->smt[i >> 2] |= v << ((i & 0x03) << 3);
205353dc8c23SGleb Smirnoff 	} else {
205453dc8c23SGleb Smirnoff 		i = mge_crc8(mac, ETHER_ADDR_LEN);
205553dc8c23SGleb Smirnoff 		ctx->omt[i >> 2] |= v << ((i & 0x03) << 3);
205653dc8c23SGleb Smirnoff 	}
205753dc8c23SGleb Smirnoff 	return (1);
205853dc8c23SGleb Smirnoff }
205953dc8c23SGleb Smirnoff 
20609f55f5f5SRafal Jaworowski static void
20619f55f5f5SRafal Jaworowski mge_setup_multicast(struct mge_softc *sc)
20629f55f5f5SRafal Jaworowski {
206353dc8c23SGleb Smirnoff 	struct mge_hash_maddr_ctx ctx;
20649f55f5f5SRafal Jaworowski 	struct ifnet *ifp = sc->ifp;
206553dc8c23SGleb Smirnoff 	static const uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1;
20669f55f5f5SRafal Jaworowski 	int i;
20679f55f5f5SRafal Jaworowski 
20689f55f5f5SRafal Jaworowski 	if (ifp->if_flags & IFF_ALLMULTI) {
20699f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++)
207053dc8c23SGleb Smirnoff 			ctx.smt[i] = ctx.omt[i] =
207153dc8c23SGleb Smirnoff 			    (v << 24) | (v << 16) | (v << 8) | v;
20729f55f5f5SRafal Jaworowski 	} else {
207353dc8c23SGleb Smirnoff 		memset(&ctx, 0, sizeof(ctx));
207453dc8c23SGleb Smirnoff 		if_foreach_llmaddr(ifp, mge_hash_maddr, &ctx);
20759f55f5f5SRafal Jaworowski 	}
20769f55f5f5SRafal Jaworowski 
20779f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
207853dc8c23SGleb Smirnoff 		MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), ctx.smt[i]);
207953dc8c23SGleb Smirnoff 		MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), ctx.omt[i]);
20809f55f5f5SRafal Jaworowski 	}
20819f55f5f5SRafal Jaworowski }
20829f55f5f5SRafal Jaworowski 
20839f55f5f5SRafal Jaworowski static void
20849f55f5f5SRafal Jaworowski mge_set_rxic(struct mge_softc *sc)
20859f55f5f5SRafal Jaworowski {
20869f55f5f5SRafal Jaworowski 	uint32_t reg;
20879f55f5f5SRafal Jaworowski 
20888e1dc58eSRafal Jaworowski 	if (sc->rx_ic_time > sc->mge_rx_ipg_max)
20898e1dc58eSRafal Jaworowski 		sc->rx_ic_time = sc->mge_rx_ipg_max;
20909f55f5f5SRafal Jaworowski 
20919f55f5f5SRafal Jaworowski 	reg = MGE_READ(sc, MGE_SDMA_CONFIG);
20928e1dc58eSRafal Jaworowski 	reg &= ~mge_rx_ipg(sc->mge_rx_ipg_max, sc->mge_ver);
20938e1dc58eSRafal Jaworowski 	reg |= mge_rx_ipg(sc->rx_ic_time, sc->mge_ver);
20949f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_SDMA_CONFIG, reg);
20959f55f5f5SRafal Jaworowski }
20969f55f5f5SRafal Jaworowski 
20979f55f5f5SRafal Jaworowski static void
20989f55f5f5SRafal Jaworowski mge_set_txic(struct mge_softc *sc)
20999f55f5f5SRafal Jaworowski {
21009f55f5f5SRafal Jaworowski 	uint32_t reg;
21019f55f5f5SRafal Jaworowski 
21028e1dc58eSRafal Jaworowski 	if (sc->tx_ic_time > sc->mge_tfut_ipg_max)
21038e1dc58eSRafal Jaworowski 		sc->tx_ic_time = sc->mge_tfut_ipg_max;
21049f55f5f5SRafal Jaworowski 
21059f55f5f5SRafal Jaworowski 	reg = MGE_READ(sc, MGE_TX_FIFO_URGENT_TRSH);
21068e1dc58eSRafal Jaworowski 	reg &= ~mge_tfut_ipg(sc->mge_tfut_ipg_max, sc->mge_ver);
21078e1dc58eSRafal Jaworowski 	reg |= mge_tfut_ipg(sc->tx_ic_time, sc->mge_ver);
21089f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, reg);
21099f55f5f5SRafal Jaworowski }
21109f55f5f5SRafal Jaworowski 
21119f55f5f5SRafal Jaworowski static int
21129f55f5f5SRafal Jaworowski mge_sysctl_ic(SYSCTL_HANDLER_ARGS)
21139f55f5f5SRafal Jaworowski {
21149f55f5f5SRafal Jaworowski 	struct mge_softc *sc = (struct mge_softc *)arg1;
21158e1dc58eSRafal Jaworowski 	uint32_t time;
21169f55f5f5SRafal Jaworowski 	int error;
21179f55f5f5SRafal Jaworowski 
21188e1dc58eSRafal Jaworowski 	time = (arg2 == MGE_IC_RX) ? sc->rx_ic_time : sc->tx_ic_time;
21199f55f5f5SRafal Jaworowski 	error = sysctl_handle_int(oidp, &time, 0, req);
21209f55f5f5SRafal Jaworowski 	if (error != 0)
21219f55f5f5SRafal Jaworowski 		return(error);
21229f55f5f5SRafal Jaworowski 
21239f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
21249f55f5f5SRafal Jaworowski 	if (arg2 == MGE_IC_RX) {
21259f55f5f5SRafal Jaworowski 		sc->rx_ic_time = time;
21269f55f5f5SRafal Jaworowski 		mge_set_rxic(sc);
21279f55f5f5SRafal Jaworowski 	} else {
21289f55f5f5SRafal Jaworowski 		sc->tx_ic_time = time;
21299f55f5f5SRafal Jaworowski 		mge_set_txic(sc);
21309f55f5f5SRafal Jaworowski 	}
21319f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
21329f55f5f5SRafal Jaworowski 
21339f55f5f5SRafal Jaworowski 	return(0);
21349f55f5f5SRafal Jaworowski }
21359f55f5f5SRafal Jaworowski 
21369f55f5f5SRafal Jaworowski static void
21379f55f5f5SRafal Jaworowski mge_add_sysctls(struct mge_softc *sc)
21389f55f5f5SRafal Jaworowski {
21399f55f5f5SRafal Jaworowski 	struct sysctl_ctx_list *ctx;
21409f55f5f5SRafal Jaworowski 	struct sysctl_oid_list *children;
21419f55f5f5SRafal Jaworowski 	struct sysctl_oid *tree;
21429f55f5f5SRafal Jaworowski 
21439f55f5f5SRafal Jaworowski 	ctx = device_get_sysctl_ctx(sc->dev);
21449f55f5f5SRafal Jaworowski 	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
21459f55f5f5SRafal Jaworowski 	tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "int_coal",
21467029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "MGE Interrupts coalescing");
21479f55f5f5SRafal Jaworowski 	children = SYSCTL_CHILDREN(tree);
21489f55f5f5SRafal Jaworowski 
21499f55f5f5SRafal Jaworowski 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_time",
21507029da5cSPawel Biernacki 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, MGE_IC_RX,
21517029da5cSPawel Biernacki 	    mge_sysctl_ic, "I", "IC RX time threshold");
21529f55f5f5SRafal Jaworowski 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_time",
21537029da5cSPawel Biernacki 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, MGE_IC_TX,
21547029da5cSPawel Biernacki 	    mge_sysctl_ic, "I", "IC TX time threshold");
21559f55f5f5SRafal Jaworowski }
21563c71b84fSZbigniew Bodek 
21573c71b84fSZbigniew Bodek static int
21583c71b84fSZbigniew Bodek mge_mdio_writereg(device_t dev, int phy, int reg, int value)
21593c71b84fSZbigniew Bodek {
21603c71b84fSZbigniew Bodek 
21613c71b84fSZbigniew Bodek 	mv_write_ge_smi(dev, phy, reg, value);
21623c71b84fSZbigniew Bodek 
21633c71b84fSZbigniew Bodek 	return (0);
21643c71b84fSZbigniew Bodek }
21653c71b84fSZbigniew Bodek 
21663c71b84fSZbigniew Bodek 
21673c71b84fSZbigniew Bodek static int
21683c71b84fSZbigniew Bodek mge_mdio_readreg(device_t dev, int phy, int reg)
21693c71b84fSZbigniew Bodek {
21703c71b84fSZbigniew Bodek 	int ret;
21713c71b84fSZbigniew Bodek 
21723c71b84fSZbigniew Bodek 	ret = mv_read_ge_smi(dev, phy, reg);
21733c71b84fSZbigniew Bodek 
21743c71b84fSZbigniew Bodek 	return (ret);
21753c71b84fSZbigniew Bodek }
2176