xref: /freebsd/sys/dev/mge/if_mge.c (revision 5817716faf019277a20643475b18865d965b5bbf)
19f55f5f5SRafal Jaworowski /*-
29f55f5f5SRafal Jaworowski  * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
39f55f5f5SRafal Jaworowski  * All rights reserved.
49f55f5f5SRafal Jaworowski  *
59f55f5f5SRafal Jaworowski  * Developed by Semihalf.
69f55f5f5SRafal Jaworowski  *
79f55f5f5SRafal Jaworowski  * Redistribution and use in source and binary forms, with or without
89f55f5f5SRafal Jaworowski  * modification, are permitted provided that the following conditions
99f55f5f5SRafal Jaworowski  * are met:
109f55f5f5SRafal Jaworowski  * 1. Redistributions of source code must retain the above copyright
119f55f5f5SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer.
129f55f5f5SRafal Jaworowski  * 2. Redistributions in binary form must reproduce the above copyright
139f55f5f5SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer in the
149f55f5f5SRafal Jaworowski  *    documentation and/or other materials provided with the distribution.
159f55f5f5SRafal Jaworowski  * 3. Neither the name of MARVELL nor the names of contributors
169f55f5f5SRafal Jaworowski  *    may be used to endorse or promote products derived from this software
179f55f5f5SRafal Jaworowski  *    without specific prior written permission.
189f55f5f5SRafal Jaworowski  *
199f55f5f5SRafal Jaworowski  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
209f55f5f5SRafal Jaworowski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219f55f5f5SRafal Jaworowski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229f55f5f5SRafal Jaworowski  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
239f55f5f5SRafal Jaworowski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249f55f5f5SRafal Jaworowski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259f55f5f5SRafal Jaworowski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269f55f5f5SRafal Jaworowski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279f55f5f5SRafal Jaworowski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289f55f5f5SRafal Jaworowski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299f55f5f5SRafal Jaworowski  * SUCH DAMAGE.
309f55f5f5SRafal Jaworowski  */
319f55f5f5SRafal Jaworowski 
329f55f5f5SRafal Jaworowski #ifdef HAVE_KERNEL_OPTION_HEADERS
339f55f5f5SRafal Jaworowski #include "opt_device_polling.h"
349f55f5f5SRafal Jaworowski #endif
359f55f5f5SRafal Jaworowski 
369f55f5f5SRafal Jaworowski #include <sys/cdefs.h>
379f55f5f5SRafal Jaworowski __FBSDID("$FreeBSD$");
389f55f5f5SRafal Jaworowski 
399f55f5f5SRafal Jaworowski #include <sys/param.h>
409f55f5f5SRafal Jaworowski #include <sys/systm.h>
419f55f5f5SRafal Jaworowski #include <sys/endian.h>
429f55f5f5SRafal Jaworowski #include <sys/mbuf.h>
439f55f5f5SRafal Jaworowski #include <sys/lock.h>
449f55f5f5SRafal Jaworowski #include <sys/mutex.h>
459f55f5f5SRafal Jaworowski #include <sys/kernel.h>
469f55f5f5SRafal Jaworowski #include <sys/module.h>
479f55f5f5SRafal Jaworowski #include <sys/socket.h>
489f55f5f5SRafal Jaworowski #include <sys/sysctl.h>
499f55f5f5SRafal Jaworowski 
509f55f5f5SRafal Jaworowski #include <net/ethernet.h>
519f55f5f5SRafal Jaworowski #include <net/bpf.h>
529f55f5f5SRafal Jaworowski #include <net/if.h>
539f55f5f5SRafal Jaworowski #include <net/if_arp.h>
549f55f5f5SRafal Jaworowski #include <net/if_dl.h>
559f55f5f5SRafal Jaworowski #include <net/if_media.h>
569f55f5f5SRafal Jaworowski #include <net/if_types.h>
579f55f5f5SRafal Jaworowski #include <net/if_vlan_var.h>
589f55f5f5SRafal Jaworowski 
599f55f5f5SRafal Jaworowski #include <netinet/in_systm.h>
609f55f5f5SRafal Jaworowski #include <netinet/in.h>
619f55f5f5SRafal Jaworowski #include <netinet/ip.h>
629f55f5f5SRafal Jaworowski 
639f55f5f5SRafal Jaworowski #include <sys/sockio.h>
649f55f5f5SRafal Jaworowski #include <sys/bus.h>
659f55f5f5SRafal Jaworowski #include <machine/bus.h>
669f55f5f5SRafal Jaworowski #include <sys/rman.h>
679f55f5f5SRafal Jaworowski #include <machine/resource.h>
689f55f5f5SRafal Jaworowski 
699f55f5f5SRafal Jaworowski #include <dev/mii/mii.h>
709f55f5f5SRafal Jaworowski #include <dev/mii/miivar.h>
719f55f5f5SRafal Jaworowski 
729f55f5f5SRafal Jaworowski #define	MV_PHY_ADDR_BASE	8
739f55f5f5SRafal Jaworowski 
749f55f5f5SRafal Jaworowski #include <dev/mge/if_mgevar.h>
759f55f5f5SRafal Jaworowski #include <arm/mv/mvreg.h>
768e1dc58eSRafal Jaworowski #include <arm/mv/mvvar.h>
779f55f5f5SRafal Jaworowski 
789f55f5f5SRafal Jaworowski #include "miibus_if.h"
799f55f5f5SRafal Jaworowski 
809f55f5f5SRafal Jaworowski /* PHY registers are in the address space of the first mge unit */
819f55f5f5SRafal Jaworowski static struct mge_softc *sc_mge0 = NULL;
829f55f5f5SRafal Jaworowski 
839f55f5f5SRafal Jaworowski static int mge_probe(device_t dev);
849f55f5f5SRafal Jaworowski static int mge_attach(device_t dev);
859f55f5f5SRafal Jaworowski static int mge_detach(device_t dev);
869f55f5f5SRafal Jaworowski static int mge_shutdown(device_t dev);
879f55f5f5SRafal Jaworowski static int mge_suspend(device_t dev);
889f55f5f5SRafal Jaworowski static int mge_resume(device_t dev);
899f55f5f5SRafal Jaworowski 
909f55f5f5SRafal Jaworowski static int mge_miibus_readreg(device_t dev, int phy, int reg);
919f55f5f5SRafal Jaworowski static void mge_miibus_writereg(device_t dev, int phy, int reg, int value);
929f55f5f5SRafal Jaworowski 
939f55f5f5SRafal Jaworowski static int mge_ifmedia_upd(struct ifnet *ifp);
949f55f5f5SRafal Jaworowski static void mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
959f55f5f5SRafal Jaworowski 
969f55f5f5SRafal Jaworowski static void mge_init(void *arg);
979f55f5f5SRafal Jaworowski static void mge_init_locked(void *arg);
989f55f5f5SRafal Jaworowski static void mge_start(struct ifnet *ifp);
999f55f5f5SRafal Jaworowski static void mge_start_locked(struct ifnet *ifp);
1009f55f5f5SRafal Jaworowski static void mge_watchdog(struct mge_softc *sc);
1019f55f5f5SRafal Jaworowski static int mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
1029f55f5f5SRafal Jaworowski 
1038e1dc58eSRafal Jaworowski static uint32_t mge_tfut_ipg(uint32_t val, int ver);
1048e1dc58eSRafal Jaworowski static uint32_t mge_rx_ipg(uint32_t val, int ver);
1058e1dc58eSRafal Jaworowski static void mge_ver_params(struct mge_softc *sc);
1068e1dc58eSRafal Jaworowski 
1079f55f5f5SRafal Jaworowski static void mge_intrs_ctrl(struct mge_softc *sc, int enable);
1089f55f5f5SRafal Jaworowski static void mge_intr_rx(void *arg);
1099f55f5f5SRafal Jaworowski static void mge_intr_rx_locked(struct mge_softc *sc, int count);
1109f55f5f5SRafal Jaworowski static void mge_intr_tx(void *arg);
1119f55f5f5SRafal Jaworowski static void mge_intr_tx_locked(struct mge_softc *sc);
1129f55f5f5SRafal Jaworowski static void mge_intr_misc(void *arg);
1139f55f5f5SRafal Jaworowski static void mge_intr_sum(void *arg);
1149f55f5f5SRafal Jaworowski static void mge_intr_err(void *arg);
1159f55f5f5SRafal Jaworowski static void mge_stop(struct mge_softc *sc);
1169f55f5f5SRafal Jaworowski static void mge_tick(void *msc);
1179f55f5f5SRafal Jaworowski static uint32_t mge_set_port_serial_control(uint32_t media);
1189f55f5f5SRafal Jaworowski static void mge_get_mac_address(struct mge_softc *sc, uint8_t *addr);
1199f55f5f5SRafal Jaworowski static void mge_set_mac_address(struct mge_softc *sc);
1209f55f5f5SRafal Jaworowski static void mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte,
1219f55f5f5SRafal Jaworowski     uint8_t queue);
1229f55f5f5SRafal Jaworowski static void mge_set_prom_mode(struct mge_softc *sc, uint8_t queue);
1239f55f5f5SRafal Jaworowski static int mge_allocate_dma(struct mge_softc *sc);
1249f55f5f5SRafal Jaworowski static int mge_alloc_desc_dma(struct mge_softc *sc,
1259f55f5f5SRafal Jaworowski     struct mge_desc_wrapper* desc_tab, uint32_t size, bus_dma_tag_t *buffer_tag);
1269f55f5f5SRafal Jaworowski static int mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map,
1279f55f5f5SRafal Jaworowski     struct mbuf **mbufp, bus_addr_t *paddr);
1289f55f5f5SRafal Jaworowski static void mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error);
1299f55f5f5SRafal Jaworowski static void mge_free_dma(struct mge_softc *sc);
1309f55f5f5SRafal Jaworowski static void mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab, uint32_t size,
1319f55f5f5SRafal Jaworowski     bus_dma_tag_t buffer_tag, uint8_t free_mbufs);
1329f55f5f5SRafal Jaworowski static void mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame,
1339f55f5f5SRafal Jaworowski     uint32_t status, uint16_t bufsize);
1349f55f5f5SRafal Jaworowski static void mge_offload_setup_descriptor(struct mge_softc *sc,
1359f55f5f5SRafal Jaworowski     struct mge_desc_wrapper *dw);
1369f55f5f5SRafal Jaworowski static uint8_t mge_crc8(uint8_t *data, int size);
1379f55f5f5SRafal Jaworowski static void mge_setup_multicast(struct mge_softc *sc);
1389f55f5f5SRafal Jaworowski static void mge_set_rxic(struct mge_softc *sc);
1399f55f5f5SRafal Jaworowski static void mge_set_txic(struct mge_softc *sc);
1409f55f5f5SRafal Jaworowski static void mge_add_sysctls(struct mge_softc *sc);
1419f55f5f5SRafal Jaworowski static int mge_sysctl_ic(SYSCTL_HANDLER_ARGS);
1429f55f5f5SRafal Jaworowski 
1439f55f5f5SRafal Jaworowski static device_method_t mge_methods[] = {
1449f55f5f5SRafal Jaworowski 	/* Device interface */
1459f55f5f5SRafal Jaworowski 	DEVMETHOD(device_probe,		mge_probe),
1469f55f5f5SRafal Jaworowski 	DEVMETHOD(device_attach,	mge_attach),
1479f55f5f5SRafal Jaworowski 	DEVMETHOD(device_detach,	mge_detach),
1489f55f5f5SRafal Jaworowski 	DEVMETHOD(device_shutdown,	mge_shutdown),
1499f55f5f5SRafal Jaworowski 	DEVMETHOD(device_suspend,	mge_suspend),
1509f55f5f5SRafal Jaworowski 	DEVMETHOD(device_resume,	mge_resume),
1519f55f5f5SRafal Jaworowski 	/* MII interface */
1529f55f5f5SRafal Jaworowski 	DEVMETHOD(miibus_readreg,	mge_miibus_readreg),
1539f55f5f5SRafal Jaworowski 	DEVMETHOD(miibus_writereg,	mge_miibus_writereg),
1549f55f5f5SRafal Jaworowski 	{ 0, 0 }
1559f55f5f5SRafal Jaworowski };
1569f55f5f5SRafal Jaworowski 
1579f55f5f5SRafal Jaworowski static driver_t mge_driver = {
1589f55f5f5SRafal Jaworowski 	"mge",
1599f55f5f5SRafal Jaworowski 	mge_methods,
1609f55f5f5SRafal Jaworowski 	sizeof(struct mge_softc),
1619f55f5f5SRafal Jaworowski };
1629f55f5f5SRafal Jaworowski 
1639f55f5f5SRafal Jaworowski static devclass_t mge_devclass;
1649f55f5f5SRafal Jaworowski 
1659f55f5f5SRafal Jaworowski DRIVER_MODULE(mge, mbus, mge_driver, mge_devclass, 0, 0);
1669f55f5f5SRafal Jaworowski DRIVER_MODULE(miibus, mge, miibus_driver, miibus_devclass, 0, 0);
1679f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, ether, 1, 1, 1);
1689f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, miibus, 1, 1, 1);
1699f55f5f5SRafal Jaworowski 
1709f55f5f5SRafal Jaworowski static struct resource_spec res_spec[] = {
1719f55f5f5SRafal Jaworowski 	{ SYS_RES_MEMORY, 0, RF_ACTIVE },
1729f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
1739f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE },
1749f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE },
1759f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 3, RF_ACTIVE | RF_SHAREABLE },
1769f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 4, RF_ACTIVE | RF_SHAREABLE },
1779f55f5f5SRafal Jaworowski 	{ -1, 0 }
1789f55f5f5SRafal Jaworowski };
1799f55f5f5SRafal Jaworowski 
1809f55f5f5SRafal Jaworowski static struct {
1819f55f5f5SRafal Jaworowski 	driver_intr_t *handler;
1829f55f5f5SRafal Jaworowski 	char * description;
1839f55f5f5SRafal Jaworowski } mge_intrs[MGE_INTR_COUNT] = {
1849f55f5f5SRafal Jaworowski 	{ mge_intr_rx,	"GbE receive interrupt" },
1859f55f5f5SRafal Jaworowski 	{ mge_intr_tx,	"GbE transmit interrupt" },
1869f55f5f5SRafal Jaworowski 	{ mge_intr_misc,"GbE misc interrupt" },
1879f55f5f5SRafal Jaworowski 	{ mge_intr_sum,	"GbE summary interrupt" },
1889f55f5f5SRafal Jaworowski 	{ mge_intr_err,	"GbE error interrupt" },
1899f55f5f5SRafal Jaworowski };
1909f55f5f5SRafal Jaworowski 
1919f55f5f5SRafal Jaworowski static void
1929f55f5f5SRafal Jaworowski mge_get_mac_address(struct mge_softc *sc, uint8_t *addr)
1939f55f5f5SRafal Jaworowski {
1949f55f5f5SRafal Jaworowski 	uint32_t mac_l, mac_h;
1959f55f5f5SRafal Jaworowski 
1969f55f5f5SRafal Jaworowski 	/* XXX use currently programmed MAC address; eventually this info will
1979f55f5f5SRafal Jaworowski 	 * be provided by the loader */
1989f55f5f5SRafal Jaworowski 
1999f55f5f5SRafal Jaworowski 	mac_l = MGE_READ(sc, MGE_MAC_ADDR_L);
2009f55f5f5SRafal Jaworowski 	mac_h = MGE_READ(sc, MGE_MAC_ADDR_H);
2019f55f5f5SRafal Jaworowski 
2029f55f5f5SRafal Jaworowski 	addr[0] = (mac_h & 0xff000000) >> 24;
2039f55f5f5SRafal Jaworowski 	addr[1] = (mac_h & 0x00ff0000) >> 16;
2049f55f5f5SRafal Jaworowski 	addr[2] = (mac_h & 0x0000ff00) >> 8;
2059f55f5f5SRafal Jaworowski 	addr[3] = (mac_h & 0x000000ff);
2069f55f5f5SRafal Jaworowski 	addr[4] = (mac_l & 0x0000ff00) >> 8;
2079f55f5f5SRafal Jaworowski 	addr[5] = (mac_l & 0x000000ff);
2089f55f5f5SRafal Jaworowski }
2099f55f5f5SRafal Jaworowski 
2108e1dc58eSRafal Jaworowski static uint32_t
2118e1dc58eSRafal Jaworowski mge_tfut_ipg(uint32_t val, int ver)
2128e1dc58eSRafal Jaworowski {
2138e1dc58eSRafal Jaworowski 
2148e1dc58eSRafal Jaworowski 	switch (ver) {
2158e1dc58eSRafal Jaworowski 	case 1:
2168e1dc58eSRafal Jaworowski 		return ((val & 0x3fff) << 4);
2178e1dc58eSRafal Jaworowski 	case 2:
2188e1dc58eSRafal Jaworowski 	default:
2198e1dc58eSRafal Jaworowski 		return ((val & 0xffff) << 4);
2208e1dc58eSRafal Jaworowski 	}
2218e1dc58eSRafal Jaworowski }
2228e1dc58eSRafal Jaworowski 
2238e1dc58eSRafal Jaworowski static uint32_t
2248e1dc58eSRafal Jaworowski mge_rx_ipg(uint32_t val, int ver)
2258e1dc58eSRafal Jaworowski {
2268e1dc58eSRafal Jaworowski 
2278e1dc58eSRafal Jaworowski 	switch (ver) {
2288e1dc58eSRafal Jaworowski 	case 1:
2298e1dc58eSRafal Jaworowski 		return ((val & 0x3fff) << 8);
2308e1dc58eSRafal Jaworowski 	case 2:
2318e1dc58eSRafal Jaworowski 	default:
2328e1dc58eSRafal Jaworowski 		return (((val & 0x8000) << 10) | ((val & 0x7fff) << 7));
2338e1dc58eSRafal Jaworowski 	}
2348e1dc58eSRafal Jaworowski }
2358e1dc58eSRafal Jaworowski 
2368e1dc58eSRafal Jaworowski static void
2378e1dc58eSRafal Jaworowski mge_ver_params(struct mge_softc *sc)
2388e1dc58eSRafal Jaworowski {
2398e1dc58eSRafal Jaworowski 	uint32_t d, r;
2408e1dc58eSRafal Jaworowski 
2418e1dc58eSRafal Jaworowski 	soc_id(&d, &r);
242bc26e2e3SRafal Jaworowski 	if (d == MV_DEV_88F6281 || d == MV_DEV_MV78100 ||
243bc26e2e3SRafal Jaworowski 	    d == MV_DEV_MV78100_Z0) {
2448e1dc58eSRafal Jaworowski 		sc->mge_ver = 2;
2458e1dc58eSRafal Jaworowski 		sc->mge_mtu = 0x4e8;
2468e1dc58eSRafal Jaworowski 		sc->mge_tfut_ipg_max = 0xFFFF;
2478e1dc58eSRafal Jaworowski 		sc->mge_rx_ipg_max = 0xFFFF;
2488e1dc58eSRafal Jaworowski 		sc->mge_tx_arb_cfg = 0xFC0000FF;
2498e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cfg = 0xFFFF7FFF;
2508e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cnt = 0x3FFFFFFF;
2518e1dc58eSRafal Jaworowski 	} else {
2528e1dc58eSRafal Jaworowski 		sc->mge_ver = 1;
2538e1dc58eSRafal Jaworowski 		sc->mge_mtu = 0x458;
2548e1dc58eSRafal Jaworowski 		sc->mge_tfut_ipg_max = 0x3FFF;
2558e1dc58eSRafal Jaworowski 		sc->mge_rx_ipg_max = 0x3FFF;
2568e1dc58eSRafal Jaworowski 		sc->mge_tx_arb_cfg = 0x000000FF;
2578e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cfg = 0x3FFFFFFF;
2588e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cnt = 0x3FFFFFFF;
2598e1dc58eSRafal Jaworowski 	}
2608e1dc58eSRafal Jaworowski }
2618e1dc58eSRafal Jaworowski 
2629f55f5f5SRafal Jaworowski static void
2639f55f5f5SRafal Jaworowski mge_set_mac_address(struct mge_softc *sc)
2649f55f5f5SRafal Jaworowski {
2659f55f5f5SRafal Jaworowski 	char *if_mac;
2669f55f5f5SRafal Jaworowski 	uint32_t mac_l, mac_h;
2679f55f5f5SRafal Jaworowski 
2689f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK_ASSERT(sc);
2699f55f5f5SRafal Jaworowski 
2709f55f5f5SRafal Jaworowski 	if_mac = (char *)IF_LLADDR(sc->ifp);
2719f55f5f5SRafal Jaworowski 
2729f55f5f5SRafal Jaworowski 	mac_l = (if_mac[4] << 8) | (if_mac[5]);
2739f55f5f5SRafal Jaworowski 	mac_h = (if_mac[0] << 24)| (if_mac[1] << 16) |
2749f55f5f5SRafal Jaworowski 	    (if_mac[2] << 8) | (if_mac[3] << 0);
2759f55f5f5SRafal Jaworowski 
2769f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_MAC_ADDR_L, mac_l);
2779f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_MAC_ADDR_H, mac_h);
2789f55f5f5SRafal Jaworowski 
2799f55f5f5SRafal Jaworowski 	mge_set_ucast_address(sc, if_mac[5], MGE_RX_DEFAULT_QUEUE);
2809f55f5f5SRafal Jaworowski }
2819f55f5f5SRafal Jaworowski 
2829f55f5f5SRafal Jaworowski static void
2839f55f5f5SRafal Jaworowski mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte, uint8_t queue)
2849f55f5f5SRafal Jaworowski {
2859f55f5f5SRafal Jaworowski 	uint32_t reg_idx, reg_off, reg_val, i;
2869f55f5f5SRafal Jaworowski 
2879f55f5f5SRafal Jaworowski 	last_byte &= 0xf;
2889f55f5f5SRafal Jaworowski 	reg_idx = last_byte / MGE_UCAST_REG_NUMBER;
2899f55f5f5SRafal Jaworowski 	reg_off = (last_byte % MGE_UCAST_REG_NUMBER) * 8;
2909f55f5f5SRafal Jaworowski 	reg_val = (1 | (queue << 1)) << reg_off;
2919f55f5f5SRafal Jaworowski 
2929f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_UCAST_REG_NUMBER; i++) {
2939f55f5f5SRafal Jaworowski 		if ( i == reg_idx)
2949f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val);
2959f55f5f5SRafal Jaworowski 		else
2969f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), 0);
2979f55f5f5SRafal Jaworowski 	}
2989f55f5f5SRafal Jaworowski }
2999f55f5f5SRafal Jaworowski 
3009f55f5f5SRafal Jaworowski static void
3019f55f5f5SRafal Jaworowski mge_set_prom_mode(struct mge_softc *sc, uint8_t queue)
3029f55f5f5SRafal Jaworowski {
3039f55f5f5SRafal Jaworowski 	uint32_t port_config;
3049f55f5f5SRafal Jaworowski 	uint32_t reg_val, i;
3059f55f5f5SRafal Jaworowski 
3069f55f5f5SRafal Jaworowski 	/* Enable or disable promiscuous mode as needed */
3079f55f5f5SRafal Jaworowski 	if (sc->ifp->if_flags & IFF_PROMISC) {
3089f55f5f5SRafal Jaworowski 		port_config = MGE_READ(sc, MGE_PORT_CONFIG);
3099f55f5f5SRafal Jaworowski 		port_config |= PORT_CONFIG_UPM;
3109f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_CONFIG, port_config);
3119f55f5f5SRafal Jaworowski 
3129f55f5f5SRafal Jaworowski 		reg_val = ((1 | (queue << 1)) | (1 | (queue << 1)) << 8 |
3139f55f5f5SRafal Jaworowski 		   (1 | (queue << 1)) << 16 | (1 | (queue << 1)) << 24);
3149f55f5f5SRafal Jaworowski 
3159f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
3169f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), reg_val);
3179f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), reg_val);
3189f55f5f5SRafal Jaworowski 		}
3199f55f5f5SRafal Jaworowski 
3209f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_UCAST_REG_NUMBER; i++)
3219f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val);
3229f55f5f5SRafal Jaworowski 
3239f55f5f5SRafal Jaworowski 	} else {
3249f55f5f5SRafal Jaworowski 		port_config = MGE_READ(sc, MGE_PORT_CONFIG);
3259f55f5f5SRafal Jaworowski 		port_config &= ~PORT_CONFIG_UPM;
3269f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_CONFIG, port_config);
3279f55f5f5SRafal Jaworowski 
3289f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
3299f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), 0);
3309f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), 0);
3319f55f5f5SRafal Jaworowski 		}
3329f55f5f5SRafal Jaworowski 
3339f55f5f5SRafal Jaworowski 		mge_set_mac_address(sc);
3349f55f5f5SRafal Jaworowski 	}
3359f55f5f5SRafal Jaworowski }
3369f55f5f5SRafal Jaworowski 
3379f55f5f5SRafal Jaworowski static void
3389f55f5f5SRafal Jaworowski mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
3399f55f5f5SRafal Jaworowski {
3409f55f5f5SRafal Jaworowski 	u_int32_t *paddr;
3419f55f5f5SRafal Jaworowski 
3429f55f5f5SRafal Jaworowski 	KASSERT(nseg == 1, ("wrong number of segments, should be 1"));
3439f55f5f5SRafal Jaworowski 	paddr = arg;
3449f55f5f5SRafal Jaworowski 
3459f55f5f5SRafal Jaworowski 	*paddr = segs->ds_addr;
3469f55f5f5SRafal Jaworowski }
3479f55f5f5SRafal Jaworowski 
3489f55f5f5SRafal Jaworowski static int
3499f55f5f5SRafal Jaworowski mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf **mbufp,
3509f55f5f5SRafal Jaworowski     bus_addr_t *paddr)
3519f55f5f5SRafal Jaworowski {
3529f55f5f5SRafal Jaworowski 	struct mbuf *new_mbuf;
3539f55f5f5SRafal Jaworowski 	bus_dma_segment_t seg[1];
3549f55f5f5SRafal Jaworowski 	int error;
3559f55f5f5SRafal Jaworowski 	int nsegs;
3569f55f5f5SRafal Jaworowski 
3579f55f5f5SRafal Jaworowski 	KASSERT(mbufp != NULL, ("NULL mbuf pointer!"));
3589f55f5f5SRafal Jaworowski 
3599f55f5f5SRafal Jaworowski 	new_mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
3609f55f5f5SRafal Jaworowski 	if (new_mbuf == NULL)
3619f55f5f5SRafal Jaworowski 		return (ENOBUFS);
3629f55f5f5SRafal Jaworowski 	new_mbuf->m_len = new_mbuf->m_pkthdr.len = new_mbuf->m_ext.ext_size;
3639f55f5f5SRafal Jaworowski 
3649f55f5f5SRafal Jaworowski 	if (*mbufp) {
3659f55f5f5SRafal Jaworowski 		bus_dmamap_sync(tag, map, BUS_DMASYNC_POSTREAD);
3669f55f5f5SRafal Jaworowski 		bus_dmamap_unload(tag, map);
3679f55f5f5SRafal Jaworowski 	}
3689f55f5f5SRafal Jaworowski 
3699f55f5f5SRafal Jaworowski 	error = bus_dmamap_load_mbuf_sg(tag, map, new_mbuf, seg, &nsegs,
3709f55f5f5SRafal Jaworowski 	    BUS_DMA_NOWAIT);
3719f55f5f5SRafal Jaworowski 	KASSERT(nsegs == 1, ("Too many segments returned!"));
3729f55f5f5SRafal Jaworowski 	if (nsegs != 1 || error)
3739f55f5f5SRafal Jaworowski 		panic("mge_new_rxbuf(): nsegs(%d), error(%d)", nsegs, error);
3749f55f5f5SRafal Jaworowski 
3759f55f5f5SRafal Jaworowski 	bus_dmamap_sync(tag, map, BUS_DMASYNC_PREREAD);
3769f55f5f5SRafal Jaworowski 
3779f55f5f5SRafal Jaworowski 	(*mbufp) = new_mbuf;
3789f55f5f5SRafal Jaworowski 	(*paddr) = seg->ds_addr;
3799f55f5f5SRafal Jaworowski 	return (0);
3809f55f5f5SRafal Jaworowski }
3819f55f5f5SRafal Jaworowski 
3829f55f5f5SRafal Jaworowski static int
3839f55f5f5SRafal Jaworowski mge_alloc_desc_dma(struct mge_softc *sc, struct mge_desc_wrapper* tab,
3849f55f5f5SRafal Jaworowski     uint32_t size, bus_dma_tag_t *buffer_tag)
3859f55f5f5SRafal Jaworowski {
3869f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
3879f55f5f5SRafal Jaworowski 	bus_addr_t desc_paddr;
3889f55f5f5SRafal Jaworowski 	int i, error;
3899f55f5f5SRafal Jaworowski 
3909f55f5f5SRafal Jaworowski 	desc_paddr = 0;
3919f55f5f5SRafal Jaworowski 	for (i = size - 1; i >= 0; i--) {
3929f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
3939f55f5f5SRafal Jaworowski 		error = bus_dmamem_alloc(sc->mge_desc_dtag,
3949f55f5f5SRafal Jaworowski 		    (void**)&(dw->mge_desc),
3959f55f5f5SRafal Jaworowski 		    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
3969f55f5f5SRafal Jaworowski 		    &(dw->desc_dmap));
3979f55f5f5SRafal Jaworowski 
3989f55f5f5SRafal Jaworowski 		if (error) {
3999f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "failed to allocate DMA memory\n");
4009f55f5f5SRafal Jaworowski 			dw->mge_desc = NULL;
4019f55f5f5SRafal Jaworowski 			return (ENXIO);
4029f55f5f5SRafal Jaworowski 		}
4039f55f5f5SRafal Jaworowski 
4049f55f5f5SRafal Jaworowski 		error = bus_dmamap_load(sc->mge_desc_dtag, dw->desc_dmap,
4059f55f5f5SRafal Jaworowski 		    dw->mge_desc, sizeof(struct mge_desc), mge_get_dma_addr,
4069f55f5f5SRafal Jaworowski 		    &(dw->mge_desc_paddr), BUS_DMA_NOWAIT);
4079f55f5f5SRafal Jaworowski 
4089f55f5f5SRafal Jaworowski 		if (error) {
4099f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "can't load descriptor\n");
4109f55f5f5SRafal Jaworowski 			bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc,
4119f55f5f5SRafal Jaworowski 			    dw->desc_dmap);
4129f55f5f5SRafal Jaworowski 			dw->mge_desc = NULL;
4139f55f5f5SRafal Jaworowski 			return (ENXIO);
4149f55f5f5SRafal Jaworowski 		}
4159f55f5f5SRafal Jaworowski 
4169f55f5f5SRafal Jaworowski 		/* Chain descriptors */
4179f55f5f5SRafal Jaworowski 		dw->mge_desc->next_desc = desc_paddr;
4189f55f5f5SRafal Jaworowski 		desc_paddr = dw->mge_desc_paddr;
4199f55f5f5SRafal Jaworowski 	}
4209f55f5f5SRafal Jaworowski 	tab[size - 1].mge_desc->next_desc = desc_paddr;
4219f55f5f5SRafal Jaworowski 
4229f55f5f5SRafal Jaworowski 	/* Allocate a busdma tag for mbufs. */
4239f55f5f5SRafal Jaworowski 	error = bus_dma_tag_create(NULL,	/* parent */
4249f55f5f5SRafal Jaworowski 	    8, 0,				/* alignment, boundary */
4259f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
4269f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR,			/* highaddr */
4279f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* filtfunc, filtfuncarg */
4289f55f5f5SRafal Jaworowski 	    MCLBYTES, 1,			/* maxsize, nsegments */
4299f55f5f5SRafal Jaworowski 	    MCLBYTES, 0,			/* maxsegsz, flags */
4309f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* lockfunc, lockfuncarg */
4319f55f5f5SRafal Jaworowski 	    buffer_tag);			/* dmat */
4329f55f5f5SRafal Jaworowski 	if (error) {
4339f55f5f5SRafal Jaworowski 		if_printf(sc->ifp, "failed to create busdma tag for mbufs\n");
4349f55f5f5SRafal Jaworowski 		return (ENXIO);
4359f55f5f5SRafal Jaworowski 	}
4369f55f5f5SRafal Jaworowski 
4379f55f5f5SRafal Jaworowski 	/* Create TX busdma maps */
4389f55f5f5SRafal Jaworowski 	for (i = 0; i < size; i++) {
4399f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
4409f55f5f5SRafal Jaworowski 		error = bus_dmamap_create(*buffer_tag, 0, &dw->buffer_dmap);
4419f55f5f5SRafal Jaworowski 		if (error) {
4429f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "failed to create map for mbuf\n");
4439f55f5f5SRafal Jaworowski 			return (ENXIO);
4449f55f5f5SRafal Jaworowski 		}
4459f55f5f5SRafal Jaworowski 
4469f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
4479f55f5f5SRafal Jaworowski 		dw->mge_desc->buffer = (bus_addr_t)NULL;
4489f55f5f5SRafal Jaworowski 	}
4499f55f5f5SRafal Jaworowski 
4509f55f5f5SRafal Jaworowski 	return (0);
4519f55f5f5SRafal Jaworowski }
4529f55f5f5SRafal Jaworowski 
4539f55f5f5SRafal Jaworowski static int
4549f55f5f5SRafal Jaworowski mge_allocate_dma(struct mge_softc *sc)
4559f55f5f5SRafal Jaworowski {
4569f55f5f5SRafal Jaworowski 	int error;
4579f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
4589f55f5f5SRafal Jaworowski 	int num, i;
4599f55f5f5SRafal Jaworowski 
4609f55f5f5SRafal Jaworowski 
4619f55f5f5SRafal Jaworowski 	num = MGE_TX_DESC_NUM + MGE_RX_DESC_NUM;
4629f55f5f5SRafal Jaworowski 
4639f55f5f5SRafal Jaworowski 	/* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
4649f55f5f5SRafal Jaworowski 	error = bus_dma_tag_create(NULL,	/* parent */
4659f55f5f5SRafal Jaworowski 	    16, 0,				/* alignment, boundary */
4669f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
4679f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR,			/* highaddr */
4689f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* filtfunc, filtfuncarg */
4699f55f5f5SRafal Jaworowski 	    sizeof(struct mge_desc), 1,		/* maxsize, nsegments */
4709f55f5f5SRafal Jaworowski 	    sizeof(struct mge_desc), 0,		/* maxsegsz, flags */
4719f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* lockfunc, lockfuncarg */
4729f55f5f5SRafal Jaworowski 	    &sc->mge_desc_dtag);		/* dmat */
4739f55f5f5SRafal Jaworowski 
4749f55f5f5SRafal Jaworowski 
4759f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM,
4769f55f5f5SRafal Jaworowski 	    &sc->mge_tx_dtag);
4779f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM,
4789f55f5f5SRafal Jaworowski 	    &sc->mge_rx_dtag);
4799f55f5f5SRafal Jaworowski 
4809f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
4819f55f5f5SRafal Jaworowski 		dw = &(sc->mge_rx_desc[i]);
4829f55f5f5SRafal Jaworowski 		mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer,
4839f55f5f5SRafal Jaworowski 		    &dw->mge_desc->buffer);
4849f55f5f5SRafal Jaworowski 	}
4859f55f5f5SRafal Jaworowski 
4869f55f5f5SRafal Jaworowski 	sc->tx_desc_start = sc->mge_tx_desc[0].mge_desc_paddr;
4879f55f5f5SRafal Jaworowski 	sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr;
4889f55f5f5SRafal Jaworowski 
4899f55f5f5SRafal Jaworowski 	return (0);
4909f55f5f5SRafal Jaworowski }
4919f55f5f5SRafal Jaworowski 
4929f55f5f5SRafal Jaworowski static void
4939f55f5f5SRafal Jaworowski mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab,
4949f55f5f5SRafal Jaworowski     uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs)
4959f55f5f5SRafal Jaworowski {
4969f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
4979f55f5f5SRafal Jaworowski 	int i;
4989f55f5f5SRafal Jaworowski 
4999f55f5f5SRafal Jaworowski 	for (i = 0; i < size; i++) {
5009f55f5f5SRafal Jaworowski 		/* Free RX mbuf */
5019f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
5029f55f5f5SRafal Jaworowski 
5039f55f5f5SRafal Jaworowski 		if (dw->buffer_dmap) {
5049f55f5f5SRafal Jaworowski 			if (free_mbufs) {
5059f55f5f5SRafal Jaworowski 				bus_dmamap_sync(buffer_tag, dw->buffer_dmap,
5069f55f5f5SRafal Jaworowski 				    BUS_DMASYNC_POSTREAD);
5079f55f5f5SRafal Jaworowski 				bus_dmamap_unload(buffer_tag, dw->buffer_dmap);
5089f55f5f5SRafal Jaworowski 			}
5099f55f5f5SRafal Jaworowski 			bus_dmamap_destroy(buffer_tag, dw->buffer_dmap);
5109f55f5f5SRafal Jaworowski 			if (free_mbufs)
5119f55f5f5SRafal Jaworowski 				m_freem(dw->buffer);
5129f55f5f5SRafal Jaworowski 		}
5139f55f5f5SRafal Jaworowski 		/* Free RX descriptors */
5149f55f5f5SRafal Jaworowski 		if (dw->desc_dmap) {
5159f55f5f5SRafal Jaworowski 			bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
5169f55f5f5SRafal Jaworowski 			    BUS_DMASYNC_POSTREAD);
5179f55f5f5SRafal Jaworowski 			bus_dmamap_unload(sc->mge_desc_dtag, dw->desc_dmap);
5189f55f5f5SRafal Jaworowski 			bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc,
5199f55f5f5SRafal Jaworowski 			    dw->desc_dmap);
5209f55f5f5SRafal Jaworowski 		}
5219f55f5f5SRafal Jaworowski 	}
5229f55f5f5SRafal Jaworowski }
5239f55f5f5SRafal Jaworowski 
5249f55f5f5SRafal Jaworowski static void
5259f55f5f5SRafal Jaworowski mge_free_dma(struct mge_softc *sc)
5269f55f5f5SRafal Jaworowski {
5279f55f5f5SRafal Jaworowski 	/* Free desciptors and mbufs */
5289f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1);
5299f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM, sc->mge_tx_dtag, 0);
5309f55f5f5SRafal Jaworowski 
5319f55f5f5SRafal Jaworowski 	/* Destroy mbuf dma tag */
5329f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_tx_dtag);
5339f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_rx_dtag);
5349f55f5f5SRafal Jaworowski 	/* Destroy descriptors tag */
5359f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_desc_dtag);
5369f55f5f5SRafal Jaworowski }
5379f55f5f5SRafal Jaworowski 
5389f55f5f5SRafal Jaworowski static void
5399f55f5f5SRafal Jaworowski mge_reinit_rx(struct mge_softc *sc)
5409f55f5f5SRafal Jaworowski {
5419f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
5429f55f5f5SRafal Jaworowski 	int i;
5439f55f5f5SRafal Jaworowski 
5449f55f5f5SRafal Jaworowski 	MGE_RECEIVE_LOCK(sc);
5459f55f5f5SRafal Jaworowski 
5469f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1);
5479f55f5f5SRafal Jaworowski 
5489f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM,
5499f55f5f5SRafal Jaworowski 	    &sc->mge_rx_dtag);
5509f55f5f5SRafal Jaworowski 
5519f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
5529f55f5f5SRafal Jaworowski 		dw = &(sc->mge_rx_desc[i]);
5539f55f5f5SRafal Jaworowski 		mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer,
5549f55f5f5SRafal Jaworowski 		&dw->mge_desc->buffer);
5559f55f5f5SRafal Jaworowski 	}
5569f55f5f5SRafal Jaworowski 
5579f55f5f5SRafal Jaworowski 	sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr;
5589f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
5599f55f5f5SRafal Jaworowski 
5609f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE),
5619f55f5f5SRafal Jaworowski 	    sc->rx_desc_start);
5629f55f5f5SRafal Jaworowski 
5639f55f5f5SRafal Jaworowski 	/* Enable RX queue */
5649f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE));
5659f55f5f5SRafal Jaworowski 
5669f55f5f5SRafal Jaworowski 	MGE_RECEIVE_UNLOCK(sc);
5679f55f5f5SRafal Jaworowski }
5689f55f5f5SRafal Jaworowski 
5699f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
5709f55f5f5SRafal Jaworowski static poll_handler_t mge_poll;
5719f55f5f5SRafal Jaworowski 
5729f55f5f5SRafal Jaworowski static void
5739f55f5f5SRafal Jaworowski mge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
5749f55f5f5SRafal Jaworowski {
5759f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
5769f55f5f5SRafal Jaworowski 	uint32_t int_cause, int_cause_ext;
5779f55f5f5SRafal Jaworowski 
5789f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
5799f55f5f5SRafal Jaworowski 
5809f55f5f5SRafal Jaworowski 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
5819f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
5829f55f5f5SRafal Jaworowski 		return;
5839f55f5f5SRafal Jaworowski 	}
5849f55f5f5SRafal Jaworowski 
5859f55f5f5SRafal Jaworowski 	if (cmd == POLL_AND_CHECK_STATUS) {
5869f55f5f5SRafal Jaworowski 		int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
5879f55f5f5SRafal Jaworowski 		int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
5889f55f5f5SRafal Jaworowski 
5899f55f5f5SRafal Jaworowski 		/* Check for resource error */
5909f55f5f5SRafal Jaworowski 		if (int_cause & MGE_PORT_INT_RXERRQ0)
5919f55f5f5SRafal Jaworowski 			mge_reinit_rx(sc);
5929f55f5f5SRafal Jaworowski 
5939f55f5f5SRafal Jaworowski 		if (int_cause || int_cause_ext) {
5949f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause);
5959f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext);
5969f55f5f5SRafal Jaworowski 		}
5979f55f5f5SRafal Jaworowski 	}
5989f55f5f5SRafal Jaworowski 
5999f55f5f5SRafal Jaworowski 	mge_intr_tx_locked(sc);
6009f55f5f5SRafal Jaworowski 	mge_intr_rx_locked(sc, count);
6019f55f5f5SRafal Jaworowski 
6029f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
6039f55f5f5SRafal Jaworowski }
6049f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */
6059f55f5f5SRafal Jaworowski 
6069f55f5f5SRafal Jaworowski static int
6079f55f5f5SRafal Jaworowski mge_attach(device_t dev)
6089f55f5f5SRafal Jaworowski {
6099f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
6109f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
6119f55f5f5SRafal Jaworowski 	uint8_t hwaddr[ETHER_ADDR_LEN];
6129f55f5f5SRafal Jaworowski 	int i, error ;
6139f55f5f5SRafal Jaworowski 
6149f55f5f5SRafal Jaworowski 	sc = device_get_softc(dev);
6159f55f5f5SRafal Jaworowski 	sc->dev = dev;
6169f55f5f5SRafal Jaworowski 
6179f55f5f5SRafal Jaworowski 	if (device_get_unit(dev) == 0)
6189f55f5f5SRafal Jaworowski 		sc_mge0 = sc;
6199f55f5f5SRafal Jaworowski 
6208e1dc58eSRafal Jaworowski 	/* Set chip version-dependent parameters */
6218e1dc58eSRafal Jaworowski 	mge_ver_params(sc);
6228e1dc58eSRafal Jaworowski 
6239f55f5f5SRafal Jaworowski 	/* Initialize mutexes */
6249f55f5f5SRafal Jaworowski 	mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "mge TX lock", MTX_DEF);
6259f55f5f5SRafal Jaworowski 	mtx_init(&sc->receive_lock, device_get_nameunit(dev), "mge RX lock", MTX_DEF);
6269f55f5f5SRafal Jaworowski 
6279f55f5f5SRafal Jaworowski 	/* Allocate IO and IRQ resources */
6289f55f5f5SRafal Jaworowski 	error = bus_alloc_resources(dev, res_spec, sc->res);
6299f55f5f5SRafal Jaworowski 	if (error) {
6309f55f5f5SRafal Jaworowski 		device_printf(dev, "could not allocate resources\n");
6319f55f5f5SRafal Jaworowski 		mge_detach(dev);
6329f55f5f5SRafal Jaworowski 		return (ENXIO);
6339f55f5f5SRafal Jaworowski 	}
6349f55f5f5SRafal Jaworowski 
6359f55f5f5SRafal Jaworowski 	/* Allocate DMA, buffers, buffer descriptors */
6369f55f5f5SRafal Jaworowski 	error = mge_allocate_dma(sc);
6379f55f5f5SRafal Jaworowski 	if (error) {
6389f55f5f5SRafal Jaworowski 		mge_detach(dev);
6399f55f5f5SRafal Jaworowski 		return (ENXIO);
6409f55f5f5SRafal Jaworowski 	}
6419f55f5f5SRafal Jaworowski 
6429f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = 0;
6439f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
6449f55f5f5SRafal Jaworowski 	sc->tx_desc_used_idx = 0;
6455817716fSRafal Jaworowski 	sc->tx_desc_used_count = 0;
6469f55f5f5SRafal Jaworowski 
6479f55f5f5SRafal Jaworowski 	/* Configure defaults for interrupts coalescing */
6489f55f5f5SRafal Jaworowski 	sc->rx_ic_time = 768;
6499f55f5f5SRafal Jaworowski 	sc->tx_ic_time = 768;
6509f55f5f5SRafal Jaworowski 	mge_add_sysctls(sc);
6519f55f5f5SRafal Jaworowski 
6529f55f5f5SRafal Jaworowski 	/* Allocate network interface */
6539f55f5f5SRafal Jaworowski 	ifp = sc->ifp = if_alloc(IFT_ETHER);
6549f55f5f5SRafal Jaworowski 	if (ifp == NULL) {
6559f55f5f5SRafal Jaworowski 		device_printf(dev, "if_alloc() failed\n");
6569f55f5f5SRafal Jaworowski 		mge_detach(dev);
6579f55f5f5SRafal Jaworowski 		return (ENOMEM);
6589f55f5f5SRafal Jaworowski 	}
6599f55f5f5SRafal Jaworowski 
6609f55f5f5SRafal Jaworowski 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
6619f55f5f5SRafal Jaworowski 	ifp->if_softc = sc;
6629f55f5f5SRafal Jaworowski 	ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST;
6639f55f5f5SRafal Jaworowski 	ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_MTU;
6649f55f5f5SRafal Jaworowski 	ifp->if_capenable = ifp->if_capabilities;
6659f55f5f5SRafal Jaworowski 	ifp->if_hwassist = MGE_CHECKSUM_FEATURES;
6669f55f5f5SRafal Jaworowski 
6679f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
6689f55f5f5SRafal Jaworowski 	/* Advertise that polling is supported */
6699f55f5f5SRafal Jaworowski 	ifp->if_capabilities |= IFCAP_POLLING;
6709f55f5f5SRafal Jaworowski #endif
6719f55f5f5SRafal Jaworowski 
6729f55f5f5SRafal Jaworowski 	ifp->if_init = mge_init;
6739f55f5f5SRafal Jaworowski 	ifp->if_start = mge_start;
6749f55f5f5SRafal Jaworowski 	ifp->if_ioctl = mge_ioctl;
6759f55f5f5SRafal Jaworowski 
6769f55f5f5SRafal Jaworowski 	ifp->if_snd.ifq_drv_maxlen = MGE_TX_DESC_NUM - 1;
6779f55f5f5SRafal Jaworowski 	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
6789f55f5f5SRafal Jaworowski 	IFQ_SET_READY(&ifp->if_snd);
6799f55f5f5SRafal Jaworowski 
6809f55f5f5SRafal Jaworowski 	mge_get_mac_address(sc, hwaddr);
6819f55f5f5SRafal Jaworowski 	ether_ifattach(ifp, hwaddr);
6829f55f5f5SRafal Jaworowski 	callout_init(&sc->wd_callout, 0);
6839f55f5f5SRafal Jaworowski 
6849f55f5f5SRafal Jaworowski 	/* Probe PHY(s) */
6859f55f5f5SRafal Jaworowski 	error = mii_phy_probe(dev, &sc->miibus, mge_ifmedia_upd, mge_ifmedia_sts);
6869f55f5f5SRafal Jaworowski 	if (error) {
6879f55f5f5SRafal Jaworowski 		device_printf(dev, "MII failed to find PHY\n");
6889f55f5f5SRafal Jaworowski 		if_free(ifp);
6899f55f5f5SRafal Jaworowski 		sc->ifp = NULL;
6909f55f5f5SRafal Jaworowski 		mge_detach(dev);
6919f55f5f5SRafal Jaworowski 		return (error);
6929f55f5f5SRafal Jaworowski 	}
6939f55f5f5SRafal Jaworowski 	sc->mii = device_get_softc(sc->miibus);
6949f55f5f5SRafal Jaworowski 
6959f55f5f5SRafal Jaworowski 	/* Attach interrupt handlers */
6969f55f5f5SRafal Jaworowski 	for (i = 0; i < 2; ++i) {
6979f55f5f5SRafal Jaworowski 		error = bus_setup_intr(dev, sc->res[1 + i],
6989f55f5f5SRafal Jaworowski 		    INTR_TYPE_NET | INTR_MPSAFE, NULL, *mge_intrs[i].handler,
6999f55f5f5SRafal Jaworowski 		    sc, &sc->ih_cookie[i]);
7009f55f5f5SRafal Jaworowski 		if (error) {
7019f55f5f5SRafal Jaworowski 			device_printf(dev, "could not setup %s\n",
7029f55f5f5SRafal Jaworowski 			    mge_intrs[i].description);
7039f55f5f5SRafal Jaworowski 			ether_ifdetach(sc->ifp);
7049f55f5f5SRafal Jaworowski 			return (error);
7059f55f5f5SRafal Jaworowski 		}
7069f55f5f5SRafal Jaworowski 	}
7079f55f5f5SRafal Jaworowski 
7089f55f5f5SRafal Jaworowski 	return (0);
7099f55f5f5SRafal Jaworowski }
7109f55f5f5SRafal Jaworowski 
7119f55f5f5SRafal Jaworowski static int
7129f55f5f5SRafal Jaworowski mge_detach(device_t dev)
7139f55f5f5SRafal Jaworowski {
7149f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
7159f55f5f5SRafal Jaworowski 	int error,i;
7169f55f5f5SRafal Jaworowski 
7179f55f5f5SRafal Jaworowski 	sc = device_get_softc(dev);
7189f55f5f5SRafal Jaworowski 
7199f55f5f5SRafal Jaworowski 	/* Stop controller and free TX queue */
7209f55f5f5SRafal Jaworowski 	if (sc->ifp)
7219f55f5f5SRafal Jaworowski 		mge_shutdown(dev);
7229f55f5f5SRafal Jaworowski 
7239f55f5f5SRafal Jaworowski 	/* Wait for stopping ticks */
7249f55f5f5SRafal Jaworowski         callout_drain(&sc->wd_callout);
7259f55f5f5SRafal Jaworowski 
7269f55f5f5SRafal Jaworowski 	/* Stop and release all interrupts */
7279f55f5f5SRafal Jaworowski 	for (i = 0; i < 2; ++i) {
7289f55f5f5SRafal Jaworowski 		error = bus_teardown_intr(dev, sc->res[1 + i], sc->ih_cookie[i]);
7299f55f5f5SRafal Jaworowski 		if (error)
7309f55f5f5SRafal Jaworowski 			device_printf(dev, "could not release %s\n",
7319f55f5f5SRafal Jaworowski 			    mge_intrs[i].description);
7329f55f5f5SRafal Jaworowski 	}
7339f55f5f5SRafal Jaworowski 
7349f55f5f5SRafal Jaworowski 	/* Detach network interface */
7359f55f5f5SRafal Jaworowski 	if (sc->ifp) {
7369f55f5f5SRafal Jaworowski 		ether_ifdetach(sc->ifp);
7379f55f5f5SRafal Jaworowski 		if_free(sc->ifp);
7389f55f5f5SRafal Jaworowski 	}
7399f55f5f5SRafal Jaworowski 
7409f55f5f5SRafal Jaworowski 	/* Free DMA resources */
7419f55f5f5SRafal Jaworowski 	mge_free_dma(sc);
7429f55f5f5SRafal Jaworowski 
7439f55f5f5SRafal Jaworowski 	/* Free IO memory handler */
7449f55f5f5SRafal Jaworowski 	bus_release_resources(dev, res_spec, sc->res);
7459f55f5f5SRafal Jaworowski 
7469f55f5f5SRafal Jaworowski 	/* Destroy mutexes */
7479f55f5f5SRafal Jaworowski 	mtx_destroy(&sc->receive_lock);
7489f55f5f5SRafal Jaworowski 	mtx_destroy(&sc->transmit_lock);
7499f55f5f5SRafal Jaworowski 
7509f55f5f5SRafal Jaworowski 	return (0);
7519f55f5f5SRafal Jaworowski }
7529f55f5f5SRafal Jaworowski 
7539f55f5f5SRafal Jaworowski static void
7549f55f5f5SRafal Jaworowski mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
7559f55f5f5SRafal Jaworowski {
7569f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
7579f55f5f5SRafal Jaworowski 	struct mii_data *mii;
7589f55f5f5SRafal Jaworowski 
7599f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK(sc);
7609f55f5f5SRafal Jaworowski 
7619f55f5f5SRafal Jaworowski 	mii = sc->mii;
7629f55f5f5SRafal Jaworowski 	mii_pollstat(mii);
7639f55f5f5SRafal Jaworowski 
7649f55f5f5SRafal Jaworowski 	ifmr->ifm_active = mii->mii_media_active;
7659f55f5f5SRafal Jaworowski 	ifmr->ifm_status = mii->mii_media_status;
7669f55f5f5SRafal Jaworowski 
7679f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_UNLOCK(sc);
7689f55f5f5SRafal Jaworowski }
7699f55f5f5SRafal Jaworowski 
7709f55f5f5SRafal Jaworowski static uint32_t
7719f55f5f5SRafal Jaworowski mge_set_port_serial_control(uint32_t media)
7729f55f5f5SRafal Jaworowski {
7739f55f5f5SRafal Jaworowski 	uint32_t port_config;
7749f55f5f5SRafal Jaworowski 
7759f55f5f5SRafal Jaworowski 	port_config = PORT_SERIAL_RES_BIT9 | PORT_SERIAL_FORCE_LINK_FAIL |
7769f55f5f5SRafal Jaworowski 	    PORT_SERIAL_MRU(PORT_SERIAL_MRU_1552);
7779f55f5f5SRafal Jaworowski 
7789f55f5f5SRafal Jaworowski 	if (IFM_TYPE(media) == IFM_ETHER) {
7799f55f5f5SRafal Jaworowski 		switch(IFM_SUBTYPE(media)) {
7809f55f5f5SRafal Jaworowski 			case IFM_AUTO:
7819f55f5f5SRafal Jaworowski 				break;
7829f55f5f5SRafal Jaworowski 			case IFM_1000_T:
7839f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_GMII_SPEED_1000 |
7849f55f5f5SRafal Jaworowski 				    PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC |
7859f55f5f5SRafal Jaworowski 				    PORT_SERIAL_SPEED_AUTONEG);
7869f55f5f5SRafal Jaworowski 				break;
7879f55f5f5SRafal Jaworowski 			case IFM_100_TX:
7889f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_MII_SPEED_100 |
7899f55f5f5SRafal Jaworowski 				    PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC |
7909f55f5f5SRafal Jaworowski 				    PORT_SERIAL_SPEED_AUTONEG);
7919f55f5f5SRafal Jaworowski 				break;
7929f55f5f5SRafal Jaworowski 			case IFM_10_T:
7939f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_AUTONEG |
7949f55f5f5SRafal Jaworowski 				    PORT_SERIAL_AUTONEG_FC |
7959f55f5f5SRafal Jaworowski 				    PORT_SERIAL_SPEED_AUTONEG);
7969f55f5f5SRafal Jaworowski 				break;
7979f55f5f5SRafal Jaworowski 		}
7989f55f5f5SRafal Jaworowski 		if (media & IFM_FDX)
7999f55f5f5SRafal Jaworowski 			port_config |= PORT_SERIAL_FULL_DUPLEX;
8009f55f5f5SRafal Jaworowski 	}
8019f55f5f5SRafal Jaworowski 	return (port_config);
8029f55f5f5SRafal Jaworowski }
8039f55f5f5SRafal Jaworowski 
8049f55f5f5SRafal Jaworowski static int
8059f55f5f5SRafal Jaworowski mge_ifmedia_upd(struct ifnet *ifp)
8069f55f5f5SRafal Jaworowski {
8079f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
8089f55f5f5SRafal Jaworowski 
8099f55f5f5SRafal Jaworowski 	if (ifp->if_flags & IFF_UP) {
8109f55f5f5SRafal Jaworowski 		MGE_GLOBAL_LOCK(sc);
8119f55f5f5SRafal Jaworowski 
8129f55f5f5SRafal Jaworowski 		sc->mge_media_status = sc->mii->mii_media.ifm_media;
8139f55f5f5SRafal Jaworowski 		mii_mediachg(sc->mii);
8149f55f5f5SRafal Jaworowski 		mge_init_locked(sc);
8159f55f5f5SRafal Jaworowski 
8169f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
8179f55f5f5SRafal Jaworowski 	}
8189f55f5f5SRafal Jaworowski 
8199f55f5f5SRafal Jaworowski 	return (0);
8209f55f5f5SRafal Jaworowski }
8219f55f5f5SRafal Jaworowski 
8229f55f5f5SRafal Jaworowski static void
8239f55f5f5SRafal Jaworowski mge_init(void *arg)
8249f55f5f5SRafal Jaworowski {
8259f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
8269f55f5f5SRafal Jaworowski 
8279f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
8289f55f5f5SRafal Jaworowski 
8299f55f5f5SRafal Jaworowski 	mge_init_locked(arg);
8309f55f5f5SRafal Jaworowski 
8319f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
8329f55f5f5SRafal Jaworowski }
8339f55f5f5SRafal Jaworowski 
8349f55f5f5SRafal Jaworowski static void
8359f55f5f5SRafal Jaworowski mge_init_locked(void *arg)
8369f55f5f5SRafal Jaworowski {
8379f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
8389f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
8399f55f5f5SRafal Jaworowski 	volatile uint32_t reg_val;
8409f55f5f5SRafal Jaworowski 	int i, count;
8419f55f5f5SRafal Jaworowski 
8429f55f5f5SRafal Jaworowski 
8439f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK_ASSERT(sc);
8449f55f5f5SRafal Jaworowski 
8459f55f5f5SRafal Jaworowski 	/* Stop interface */
8469f55f5f5SRafal Jaworowski 	mge_stop(sc);
8479f55f5f5SRafal Jaworowski 
8489f55f5f5SRafal Jaworowski 	/* Disable interrupts */
8499f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 0);
8509f55f5f5SRafal Jaworowski 
8519f55f5f5SRafal Jaworowski 	/* Set MAC address */
8529f55f5f5SRafal Jaworowski 	mge_set_mac_address(sc);
8539f55f5f5SRafal Jaworowski 
8549f55f5f5SRafal Jaworowski 	/* Setup multicast filters */
8559f55f5f5SRafal Jaworowski 	mge_setup_multicast(sc);
8569f55f5f5SRafal Jaworowski 
8578e1dc58eSRafal Jaworowski 	if (sc->mge_ver == 2) {
8589f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL1, MGE_RGMII_EN);
8599f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_FIXED_PRIO_CONF, MGE_FIXED_PRIO_EN(0));
8608e1dc58eSRafal Jaworowski 	}
8619f55f5f5SRafal Jaworowski 
8628e1dc58eSRafal Jaworowski 	/* Initialize TX queue configuration registers */
8638e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(0), sc->mge_tx_tok_cnt);
8648e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_TOKEN_CONF(0), sc->mge_tx_tok_cfg);
8658e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_ARBITER_CONF(0), sc->mge_tx_arb_cfg);
8668e1dc58eSRafal Jaworowski 
8678e1dc58eSRafal Jaworowski 	/* Clear TX queue configuration registers for unused queues */
8689f55f5f5SRafal Jaworowski 	for (i = 1; i < 7; i++) {
8698e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(i), 0);
8708e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_TOKEN_CONF(i), 0);
8718e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_ARBITER_CONF(i), 0);
8729f55f5f5SRafal Jaworowski 	}
8739f55f5f5SRafal Jaworowski 
8749f55f5f5SRafal Jaworowski 	/* Set default MTU */
8758e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, sc->mge_mtu, 0);
8769f55f5f5SRafal Jaworowski 
8779f55f5f5SRafal Jaworowski 	/* Port configuration */
8789f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_CONFIG,
8799f55f5f5SRafal Jaworowski 	    PORT_CONFIG_RXCS | PORT_CONFIG_DFLT_RXQ(0) |
8809f55f5f5SRafal Jaworowski 	    PORT_CONFIG_ARO_RXQ(0));
8819f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_EXT_CONFIG , 0x0);
8829f55f5f5SRafal Jaworowski 
8839f55f5f5SRafal Jaworowski 	/* Setup port configuration */
8849f55f5f5SRafal Jaworowski 	reg_val = mge_set_port_serial_control(sc->mge_media_status);
8859f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
8869f55f5f5SRafal Jaworowski 
8879f55f5f5SRafal Jaworowski 	/* Setup SDMA configuration */
8889f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_SDMA_CONFIG , MGE_SDMA_RX_BYTE_SWAP |
8899f55f5f5SRafal Jaworowski 	    MGE_SDMA_TX_BYTE_SWAP |
8909f55f5f5SRafal Jaworowski 	    MGE_SDMA_RX_BURST_SIZE(MGE_SDMA_BURST_16_WORD) |
8919f55f5f5SRafal Jaworowski 	    MGE_SDMA_TX_BURST_SIZE(MGE_SDMA_BURST_16_WORD));
8929f55f5f5SRafal Jaworowski 
8939f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, 0x0);
8949f55f5f5SRafal Jaworowski 
8959f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_CUR_DESC_PTR, sc->tx_desc_start);
8969f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE),
8979f55f5f5SRafal Jaworowski 	    sc->rx_desc_start);
8989f55f5f5SRafal Jaworowski 
8999f55f5f5SRafal Jaworowski 	/* Reset descriptor indexes */
9009f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = 0;
9019f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
9029f55f5f5SRafal Jaworowski 	sc->tx_desc_used_idx = 0;
9035817716fSRafal Jaworowski 	sc->tx_desc_used_count = 0;
9049f55f5f5SRafal Jaworowski 
9059f55f5f5SRafal Jaworowski 	/* Enable RX descriptors */
9069f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
9079f55f5f5SRafal Jaworowski 		dw = &sc->mge_rx_desc[i];
9089f55f5f5SRafal Jaworowski 		dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
9099f55f5f5SRafal Jaworowski 		dw->mge_desc->buff_size = MCLBYTES;
9109f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
9119f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
9129f55f5f5SRafal Jaworowski 	}
9139f55f5f5SRafal Jaworowski 
9149f55f5f5SRafal Jaworowski 	/* Enable RX queue */
9159f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE));
9169f55f5f5SRafal Jaworowski 
9179f55f5f5SRafal Jaworowski 	/* Enable port */
9189f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL);
9199f55f5f5SRafal Jaworowski 	reg_val |= PORT_SERIAL_ENABLE;
9209f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
9219f55f5f5SRafal Jaworowski 	count = 0x100000;
9229f55f5f5SRafal Jaworowski 	for (;;) {
9239f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_PORT_STATUS);
9249f55f5f5SRafal Jaworowski 		if (reg_val & MGE_STATUS_LINKUP)
9259f55f5f5SRafal Jaworowski 			break;
9269f55f5f5SRafal Jaworowski 		DELAY(100);
9279f55f5f5SRafal Jaworowski 		if (--count == 0) {
9289f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "Timeout on link-up\n");
9299f55f5f5SRafal Jaworowski 			break;
9309f55f5f5SRafal Jaworowski 		}
9319f55f5f5SRafal Jaworowski 	}
9329f55f5f5SRafal Jaworowski 
9339f55f5f5SRafal Jaworowski 	/* Setup interrupts coalescing */
9349f55f5f5SRafal Jaworowski 	mge_set_rxic(sc);
9359f55f5f5SRafal Jaworowski 	mge_set_txic(sc);
9369f55f5f5SRafal Jaworowski 
9379f55f5f5SRafal Jaworowski 	/* Enable interrupts */
9389f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
9399f55f5f5SRafal Jaworowski         /*
9409f55f5f5SRafal Jaworowski 	 * * ...only if polling is not turned on. Disable interrupts explicitly
9419f55f5f5SRafal Jaworowski 	 * if polling is enabled.
9429f55f5f5SRafal Jaworowski 	 */
9439f55f5f5SRafal Jaworowski 	if (sc->ifp->if_capenable & IFCAP_POLLING)
9449f55f5f5SRafal Jaworowski 		mge_intrs_ctrl(sc, 0);
9459f55f5f5SRafal Jaworowski 	else
9469f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */
9479f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 1);
9489f55f5f5SRafal Jaworowski 
9499f55f5f5SRafal Jaworowski 	/* Activate network interface */
9509f55f5f5SRafal Jaworowski 	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
9519f55f5f5SRafal Jaworowski 	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9529f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
9539f55f5f5SRafal Jaworowski 
9549f55f5f5SRafal Jaworowski 	/* Schedule watchdog timeout */
9559f55f5f5SRafal Jaworowski 	callout_reset(&sc->wd_callout, hz, mge_tick, sc);
9569f55f5f5SRafal Jaworowski }
9579f55f5f5SRafal Jaworowski 
9589f55f5f5SRafal Jaworowski static void
9599f55f5f5SRafal Jaworowski mge_intr_err(void *arg)
9609f55f5f5SRafal Jaworowski {
9619f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
9629f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
9639f55f5f5SRafal Jaworowski 
9649f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
9659f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
9669f55f5f5SRafal Jaworowski }
9679f55f5f5SRafal Jaworowski 
9689f55f5f5SRafal Jaworowski static void
9699f55f5f5SRafal Jaworowski mge_intr_misc(void *arg)
9709f55f5f5SRafal Jaworowski {
9719f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
9729f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
9739f55f5f5SRafal Jaworowski 
9749f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
9759f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
9769f55f5f5SRafal Jaworowski }
9779f55f5f5SRafal Jaworowski 
9789f55f5f5SRafal Jaworowski static void
9799f55f5f5SRafal Jaworowski mge_intr_rx(void *arg) {
9809f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
9819f55f5f5SRafal Jaworowski 	uint32_t int_cause, int_cause_ext;
9829f55f5f5SRafal Jaworowski 
9839f55f5f5SRafal Jaworowski 	MGE_RECEIVE_LOCK(sc);
9849f55f5f5SRafal Jaworowski 
9859f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
9869f55f5f5SRafal Jaworowski 	if (sc->ifp->if_capenable & IFCAP_POLLING) {
9879f55f5f5SRafal Jaworowski 		MGE_RECEIVE_UNLOCK(sc);
9889f55f5f5SRafal Jaworowski 		return;
9899f55f5f5SRafal Jaworowski 	}
9909f55f5f5SRafal Jaworowski #endif
9919f55f5f5SRafal Jaworowski 
9929f55f5f5SRafal Jaworowski 	/* Get interrupt cause */
9939f55f5f5SRafal Jaworowski 	int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
9949f55f5f5SRafal Jaworowski 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
9959f55f5f5SRafal Jaworowski 
9969f55f5f5SRafal Jaworowski 	/* Check for resource error */
9979f55f5f5SRafal Jaworowski 	if (int_cause & MGE_PORT_INT_RXERRQ0) {
9989f55f5f5SRafal Jaworowski 		mge_reinit_rx(sc);
9999f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE,
10009f55f5f5SRafal Jaworowski 		    int_cause & ~MGE_PORT_INT_RXERRQ0);
10019f55f5f5SRafal Jaworowski 	}
10029f55f5f5SRafal Jaworowski 
10039f55f5f5SRafal Jaworowski 	int_cause &= MGE_PORT_INT_RXQ0;
10049f55f5f5SRafal Jaworowski 	int_cause_ext &= MGE_PORT_INT_EXT_RXOR;
10059f55f5f5SRafal Jaworowski 
10069f55f5f5SRafal Jaworowski 	if (int_cause || int_cause_ext) {
10079f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause);
10089f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext);
10099f55f5f5SRafal Jaworowski 		mge_intr_rx_locked(sc, -1);
10109f55f5f5SRafal Jaworowski 	}
10119f55f5f5SRafal Jaworowski 
10129f55f5f5SRafal Jaworowski 	MGE_RECEIVE_UNLOCK(sc);
10139f55f5f5SRafal Jaworowski }
10149f55f5f5SRafal Jaworowski 
10159f55f5f5SRafal Jaworowski 
10169f55f5f5SRafal Jaworowski static void
10179f55f5f5SRafal Jaworowski mge_intr_rx_locked(struct mge_softc *sc, int count)
10189f55f5f5SRafal Jaworowski {
10199f55f5f5SRafal Jaworowski 	struct ifnet *ifp = sc->ifp;
10209f55f5f5SRafal Jaworowski 	uint32_t status;
10219f55f5f5SRafal Jaworowski 	uint16_t bufsize;
10229f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper* dw;
10239f55f5f5SRafal Jaworowski 	struct mbuf *mb;
10249f55f5f5SRafal Jaworowski 
10259f55f5f5SRafal Jaworowski 	MGE_RECEIVE_LOCK_ASSERT(sc);
10269f55f5f5SRafal Jaworowski 
10279f55f5f5SRafal Jaworowski 	while (count != 0) {
10289f55f5f5SRafal Jaworowski 		dw = &sc->mge_rx_desc[sc->rx_desc_curr];
10299f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
10309f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
10319f55f5f5SRafal Jaworowski 
10329f55f5f5SRafal Jaworowski 		/* Get status */
10339f55f5f5SRafal Jaworowski 		status = dw->mge_desc->cmd_status;
10349f55f5f5SRafal Jaworowski 		bufsize = dw->mge_desc->buff_size;
10359f55f5f5SRafal Jaworowski 		if ((status & MGE_DMA_OWNED) != 0)
10369f55f5f5SRafal Jaworowski 			break;
10379f55f5f5SRafal Jaworowski 
10389f55f5f5SRafal Jaworowski 		if (dw->mge_desc->byte_count &&
10399f55f5f5SRafal Jaworowski 		    ~(status & MGE_ERR_SUMMARY)) {
10409f55f5f5SRafal Jaworowski 
10419f55f5f5SRafal Jaworowski 			bus_dmamap_sync(sc->mge_rx_dtag, dw->buffer_dmap,
10429f55f5f5SRafal Jaworowski 			    BUS_DMASYNC_POSTREAD);
10439f55f5f5SRafal Jaworowski 
10449f55f5f5SRafal Jaworowski 			mb = m_devget(dw->buffer->m_data,
10459f55f5f5SRafal Jaworowski 			    dw->mge_desc->byte_count - ETHER_CRC_LEN,
10469f55f5f5SRafal Jaworowski 			    0, ifp, NULL);
10479f55f5f5SRafal Jaworowski 
10485817716fSRafal Jaworowski 			if (mb == NULL)
10495817716fSRafal Jaworowski 				/* Give up if no mbufs */
10505817716fSRafal Jaworowski 				break;
10515817716fSRafal Jaworowski 
10529f55f5f5SRafal Jaworowski 			mb->m_len -= 2;
10539f55f5f5SRafal Jaworowski 			mb->m_pkthdr.len -= 2;
10549f55f5f5SRafal Jaworowski 			mb->m_data += 2;
10559f55f5f5SRafal Jaworowski 
10569f55f5f5SRafal Jaworowski 			mge_offload_process_frame(ifp, mb, status,
10579f55f5f5SRafal Jaworowski 			    bufsize);
10589f55f5f5SRafal Jaworowski 
10599f55f5f5SRafal Jaworowski 			MGE_RECEIVE_UNLOCK(sc);
10609f55f5f5SRafal Jaworowski 			(*ifp->if_input)(ifp, mb);
10619f55f5f5SRafal Jaworowski 			MGE_RECEIVE_LOCK(sc);
10629f55f5f5SRafal Jaworowski 		}
10639f55f5f5SRafal Jaworowski 
10649f55f5f5SRafal Jaworowski 		dw->mge_desc->byte_count = 0;
10659f55f5f5SRafal Jaworowski 		dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
10665817716fSRafal Jaworowski 		sc->rx_desc_curr = (++sc->rx_desc_curr % MGE_RX_DESC_NUM);
10679f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
10689f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
10699f55f5f5SRafal Jaworowski 
10709f55f5f5SRafal Jaworowski 		if (count > 0)
10719f55f5f5SRafal Jaworowski 			count -= 1;
10729f55f5f5SRafal Jaworowski 	}
10739f55f5f5SRafal Jaworowski 
10749f55f5f5SRafal Jaworowski 	return;
10759f55f5f5SRafal Jaworowski }
10769f55f5f5SRafal Jaworowski 
10779f55f5f5SRafal Jaworowski static void
10789f55f5f5SRafal Jaworowski mge_intr_sum(void *arg)
10799f55f5f5SRafal Jaworowski {
10809f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
10819f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
10829f55f5f5SRafal Jaworowski 
10839f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
10849f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
10859f55f5f5SRafal Jaworowski }
10869f55f5f5SRafal Jaworowski 
10879f55f5f5SRafal Jaworowski static void
10889f55f5f5SRafal Jaworowski mge_intr_tx(void *arg)
10899f55f5f5SRafal Jaworowski {
10909f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
10919f55f5f5SRafal Jaworowski 	uint32_t int_cause_ext;
10929f55f5f5SRafal Jaworowski 
10939f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK(sc);
10949f55f5f5SRafal Jaworowski 
10959f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
10969f55f5f5SRafal Jaworowski 	if (sc->ifp->if_capenable & IFCAP_POLLING) {
10979f55f5f5SRafal Jaworowski 		MGE_TRANSMIT_UNLOCK(sc);
10989f55f5f5SRafal Jaworowski 		return;
10999f55f5f5SRafal Jaworowski 	}
11009f55f5f5SRafal Jaworowski #endif
11019f55f5f5SRafal Jaworowski 
11029f55f5f5SRafal Jaworowski 	/* Ack the interrupt */
11039f55f5f5SRafal Jaworowski 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
11049f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT,
11059f55f5f5SRafal Jaworowski 	    int_cause_ext & ~MGE_PORT_INT_EXT_TXBUF0);
11069f55f5f5SRafal Jaworowski 
11079f55f5f5SRafal Jaworowski 	mge_intr_tx_locked(sc);
11089f55f5f5SRafal Jaworowski 
11099f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_UNLOCK(sc);
11109f55f5f5SRafal Jaworowski }
11119f55f5f5SRafal Jaworowski 
11129f55f5f5SRafal Jaworowski 
11139f55f5f5SRafal Jaworowski static void
11149f55f5f5SRafal Jaworowski mge_intr_tx_locked(struct mge_softc *sc)
11159f55f5f5SRafal Jaworowski {
11169f55f5f5SRafal Jaworowski 	struct ifnet *ifp = sc->ifp;
11179f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
11189f55f5f5SRafal Jaworowski 	struct mge_desc *desc;
11199f55f5f5SRafal Jaworowski 	uint32_t status;
11209f55f5f5SRafal Jaworowski 	int send = 0;
11219f55f5f5SRafal Jaworowski 
11229f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK_ASSERT(sc);
11239f55f5f5SRafal Jaworowski 
11249f55f5f5SRafal Jaworowski 	/* Disable watchdog */
11259f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
11269f55f5f5SRafal Jaworowski 
11279f55f5f5SRafal Jaworowski 	while (sc->tx_desc_used_count) {
11289f55f5f5SRafal Jaworowski 		/* Get the descriptor */
11299f55f5f5SRafal Jaworowski 		dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
11309f55f5f5SRafal Jaworowski 		desc = dw->mge_desc;
11319f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
11329f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
11339f55f5f5SRafal Jaworowski 
11349f55f5f5SRafal Jaworowski 		/* Get descriptor status */
11359f55f5f5SRafal Jaworowski 		status = desc->cmd_status;
11369f55f5f5SRafal Jaworowski 
11379f55f5f5SRafal Jaworowski 		if (status & MGE_DMA_OWNED)
11389f55f5f5SRafal Jaworowski 			break;
11399f55f5f5SRafal Jaworowski 
11409f55f5f5SRafal Jaworowski 		sc->tx_desc_used_idx =
11419f55f5f5SRafal Jaworowski 			(++sc->tx_desc_used_idx) % MGE_TX_DESC_NUM;;
11429f55f5f5SRafal Jaworowski 		sc->tx_desc_used_count--;
11439f55f5f5SRafal Jaworowski 
11449f55f5f5SRafal Jaworowski 		/* Update collision statistics */
11459f55f5f5SRafal Jaworowski 		if (status & MGE_ERR_SUMMARY) {
11469f55f5f5SRafal Jaworowski 			if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_LC)
11479f55f5f5SRafal Jaworowski 				ifp->if_collisions++;
11489f55f5f5SRafal Jaworowski 			if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_RL)
11499f55f5f5SRafal Jaworowski 				ifp->if_collisions += 16;
11509f55f5f5SRafal Jaworowski 		}
11519f55f5f5SRafal Jaworowski 
11529f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
11539f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTWRITE);
11549f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap);
11559f55f5f5SRafal Jaworowski 		m_freem(dw->buffer);
11569f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
11579f55f5f5SRafal Jaworowski 		send++;
11589f55f5f5SRafal Jaworowski 
11599f55f5f5SRafal Jaworowski 		ifp->if_opackets++;
11609f55f5f5SRafal Jaworowski 	}
11619f55f5f5SRafal Jaworowski 
11629f55f5f5SRafal Jaworowski 	if (send) {
11639f55f5f5SRafal Jaworowski 		/* Now send anything that was pending */
11649f55f5f5SRafal Jaworowski 		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
11659f55f5f5SRafal Jaworowski 		mge_start_locked(ifp);
11669f55f5f5SRafal Jaworowski 	}
11679f55f5f5SRafal Jaworowski }
11689f55f5f5SRafal Jaworowski 
11699f55f5f5SRafal Jaworowski static int
11709f55f5f5SRafal Jaworowski mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
11719f55f5f5SRafal Jaworowski {
11729f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
11739f55f5f5SRafal Jaworowski 	struct ifreq *ifr = (struct ifreq *)data;
11749f55f5f5SRafal Jaworowski 	int mask, error;
11759f55f5f5SRafal Jaworowski 	uint32_t flags;
11769f55f5f5SRafal Jaworowski 
11779f55f5f5SRafal Jaworowski 	error = 0;
11789f55f5f5SRafal Jaworowski 
11799f55f5f5SRafal Jaworowski 	switch (command) {
11809f55f5f5SRafal Jaworowski 	case SIOCSIFFLAGS:
11819f55f5f5SRafal Jaworowski 		MGE_GLOBAL_LOCK(sc);
11829f55f5f5SRafal Jaworowski 
11839f55f5f5SRafal Jaworowski 		if (ifp->if_flags & IFF_UP) {
11849f55f5f5SRafal Jaworowski 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
11859f55f5f5SRafal Jaworowski 				flags = ifp->if_flags ^ sc->mge_if_flags;
11869f55f5f5SRafal Jaworowski 				if (flags & IFF_PROMISC)
11879f55f5f5SRafal Jaworowski 					mge_set_prom_mode(sc,
11889f55f5f5SRafal Jaworowski 					    MGE_RX_DEFAULT_QUEUE);
11899f55f5f5SRafal Jaworowski 
11909f55f5f5SRafal Jaworowski 				if (flags & IFF_ALLMULTI)
11919f55f5f5SRafal Jaworowski 					mge_setup_multicast(sc);
11929f55f5f5SRafal Jaworowski 			} else
11939f55f5f5SRafal Jaworowski 				mge_init_locked(sc);
11949f55f5f5SRafal Jaworowski 		}
11959f55f5f5SRafal Jaworowski 		else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
11969f55f5f5SRafal Jaworowski 			mge_stop(sc);
11979f55f5f5SRafal Jaworowski 
11989f55f5f5SRafal Jaworowski 		sc->mge_if_flags = ifp->if_flags;
11999f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
12009f55f5f5SRafal Jaworowski 		break;
12019f55f5f5SRafal Jaworowski 	case SIOCADDMULTI:
12029f55f5f5SRafal Jaworowski 	case SIOCDELMULTI:
12039f55f5f5SRafal Jaworowski 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
12049f55f5f5SRafal Jaworowski 			MGE_GLOBAL_LOCK(sc);
12059f55f5f5SRafal Jaworowski 			mge_setup_multicast(sc);
12069f55f5f5SRafal Jaworowski 			MGE_GLOBAL_UNLOCK(sc);
12079f55f5f5SRafal Jaworowski 		}
12089f55f5f5SRafal Jaworowski 		break;
12099f55f5f5SRafal Jaworowski 	case SIOCSIFCAP:
12109f55f5f5SRafal Jaworowski 		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
12119f55f5f5SRafal Jaworowski 		if (mask & IFCAP_HWCSUM) {
12129f55f5f5SRafal Jaworowski 			ifp->if_capenable &= ~IFCAP_HWCSUM;
12139f55f5f5SRafal Jaworowski 			ifp->if_capenable |= IFCAP_HWCSUM & ifr->ifr_reqcap;
12149f55f5f5SRafal Jaworowski 			if (ifp->if_capenable & IFCAP_TXCSUM)
12159f55f5f5SRafal Jaworowski 				ifp->if_hwassist = MGE_CHECKSUM_FEATURES;
12169f55f5f5SRafal Jaworowski 			else
12179f55f5f5SRafal Jaworowski 				ifp->if_hwassist = 0;
12189f55f5f5SRafal Jaworowski 		}
12199f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
12209f55f5f5SRafal Jaworowski 		if (mask & IFCAP_POLLING) {
12219f55f5f5SRafal Jaworowski 			if (ifr->ifr_reqcap & IFCAP_POLLING) {
12229f55f5f5SRafal Jaworowski 				error = ether_poll_register(mge_poll, ifp);
12239f55f5f5SRafal Jaworowski 				if (error)
12249f55f5f5SRafal Jaworowski 					return(error);
12259f55f5f5SRafal Jaworowski 
12269f55f5f5SRafal Jaworowski 				MGE_GLOBAL_LOCK(sc);
12279f55f5f5SRafal Jaworowski 				mge_intrs_ctrl(sc, 0);
12289f55f5f5SRafal Jaworowski 				ifp->if_capenable |= IFCAP_POLLING;
12299f55f5f5SRafal Jaworowski 				MGE_GLOBAL_UNLOCK(sc);
12309f55f5f5SRafal Jaworowski 			} else {
12319f55f5f5SRafal Jaworowski 				error = ether_poll_deregister(ifp);
12329f55f5f5SRafal Jaworowski 				MGE_GLOBAL_LOCK(sc);
12339f55f5f5SRafal Jaworowski 				mge_intrs_ctrl(sc, 1);
12349f55f5f5SRafal Jaworowski 				ifp->if_capenable &= ~IFCAP_POLLING;
12359f55f5f5SRafal Jaworowski 				MGE_GLOBAL_UNLOCK(sc);
12369f55f5f5SRafal Jaworowski 			}
12379f55f5f5SRafal Jaworowski 		}
12389f55f5f5SRafal Jaworowski #endif
12399f55f5f5SRafal Jaworowski 		break;
12409f55f5f5SRafal Jaworowski 	case SIOCGIFMEDIA: /* fall through */
12419f55f5f5SRafal Jaworowski 	case SIOCSIFMEDIA:
12429f55f5f5SRafal Jaworowski 		if (IFM_SUBTYPE(ifr->ifr_media) == IFM_1000_T
12439f55f5f5SRafal Jaworowski 		    && !(ifr->ifr_media & IFM_FDX)) {
12449f55f5f5SRafal Jaworowski 			device_printf(sc->dev,
12459f55f5f5SRafal Jaworowski 			    "1000baseTX half-duplex unsupported\n");
12469f55f5f5SRafal Jaworowski 			return 0;
12479f55f5f5SRafal Jaworowski 		}
12489f55f5f5SRafal Jaworowski 		error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command);
12499f55f5f5SRafal Jaworowski 		break;
12509f55f5f5SRafal Jaworowski 	default:
12519f55f5f5SRafal Jaworowski 		error = ether_ioctl(ifp, command, data);
12529f55f5f5SRafal Jaworowski 	}
12539f55f5f5SRafal Jaworowski 	return (error);
12549f55f5f5SRafal Jaworowski }
12559f55f5f5SRafal Jaworowski 
12569f55f5f5SRafal Jaworowski static int
12579f55f5f5SRafal Jaworowski mge_miibus_readreg(device_t dev, int phy, int reg)
12589f55f5f5SRafal Jaworowski {
12599f55f5f5SRafal Jaworowski 	uint32_t retries;
12609f55f5f5SRafal Jaworowski 
12619f55f5f5SRafal Jaworowski 	/*
12629f55f5f5SRafal Jaworowski 	 * We assume static PHY address <=> device unit mapping:
12639f55f5f5SRafal Jaworowski 	 * PHY Address = MV_PHY_ADDR_BASE + devce unit.
12649f55f5f5SRafal Jaworowski 	 * This is true for most Marvell boards.
12659f55f5f5SRafal Jaworowski 	 *
12669f55f5f5SRafal Jaworowski 	 * Code below grants proper PHY detection on each device
12679f55f5f5SRafal Jaworowski 	 * unit.
12689f55f5f5SRafal Jaworowski 	 */
12699f55f5f5SRafal Jaworowski 
12709f55f5f5SRafal Jaworowski 	if ((MV_PHY_ADDR_BASE + device_get_unit(dev)) != phy)
12719f55f5f5SRafal Jaworowski 		return (0);
12729f55f5f5SRafal Jaworowski 
12739f55f5f5SRafal Jaworowski 	MGE_WRITE(sc_mge0, MGE_REG_SMI, 0x1fffffff &
12749f55f5f5SRafal Jaworowski 	    (MGE_SMI_READ | (reg << 21) | (phy << 16)));
12759f55f5f5SRafal Jaworowski 
12769f55f5f5SRafal Jaworowski 	retries = MGE_SMI_READ_RETRIES;
12779f55f5f5SRafal Jaworowski 	while (--retries && !(MGE_READ(sc_mge0, MGE_REG_SMI) & MGE_SMI_READVALID))
12789f55f5f5SRafal Jaworowski 		DELAY(MGE_SMI_READ_DELAY);
12799f55f5f5SRafal Jaworowski 
12809f55f5f5SRafal Jaworowski 	if (retries == 0)
12819f55f5f5SRafal Jaworowski 		device_printf(dev, "Timeout while reading from PHY\n");
12829f55f5f5SRafal Jaworowski 
12839f55f5f5SRafal Jaworowski 	return (MGE_READ(sc_mge0, MGE_REG_SMI) & 0xffff);
12849f55f5f5SRafal Jaworowski }
12859f55f5f5SRafal Jaworowski 
12869f55f5f5SRafal Jaworowski static void
12879f55f5f5SRafal Jaworowski mge_miibus_writereg(device_t dev, int phy, int reg, int value)
12889f55f5f5SRafal Jaworowski {
12899f55f5f5SRafal Jaworowski 	uint32_t retries;
12909f55f5f5SRafal Jaworowski 
12919f55f5f5SRafal Jaworowski 	if ((MV_PHY_ADDR_BASE + device_get_unit(dev)) != phy)
12929f55f5f5SRafal Jaworowski 		return;
12939f55f5f5SRafal Jaworowski 
12949f55f5f5SRafal Jaworowski 	MGE_WRITE(sc_mge0, MGE_REG_SMI, 0x1fffffff &
12959f55f5f5SRafal Jaworowski 	    (MGE_SMI_WRITE | (reg << 21) | (phy << 16) | (value & 0xffff)));
12969f55f5f5SRafal Jaworowski 
12979f55f5f5SRafal Jaworowski 	retries = MGE_SMI_WRITE_RETRIES;
12989f55f5f5SRafal Jaworowski 	while (--retries && MGE_READ(sc_mge0, MGE_REG_SMI) & MGE_SMI_BUSY)
12999f55f5f5SRafal Jaworowski 		DELAY(MGE_SMI_WRITE_DELAY);
13009f55f5f5SRafal Jaworowski 
13019f55f5f5SRafal Jaworowski 	if (retries == 0)
13029f55f5f5SRafal Jaworowski 		device_printf(dev, "Timeout while writing to PHY\n");
13039f55f5f5SRafal Jaworowski }
13049f55f5f5SRafal Jaworowski 
13059f55f5f5SRafal Jaworowski static int
13069f55f5f5SRafal Jaworowski mge_probe(device_t dev)
13079f55f5f5SRafal Jaworowski {
13089f55f5f5SRafal Jaworowski 
13099f55f5f5SRafal Jaworowski 	device_set_desc(dev, "Marvell Gigabit Ethernet controller");
13109f55f5f5SRafal Jaworowski 	return (BUS_PROBE_DEFAULT);
13119f55f5f5SRafal Jaworowski }
13129f55f5f5SRafal Jaworowski 
13139f55f5f5SRafal Jaworowski static int
13149f55f5f5SRafal Jaworowski mge_resume(device_t dev)
13159f55f5f5SRafal Jaworowski {
13169f55f5f5SRafal Jaworowski 
13179f55f5f5SRafal Jaworowski 	device_printf(dev, "%s\n", __FUNCTION__);
13189f55f5f5SRafal Jaworowski 	return (0);
13199f55f5f5SRafal Jaworowski }
13209f55f5f5SRafal Jaworowski 
13219f55f5f5SRafal Jaworowski static int
13229f55f5f5SRafal Jaworowski mge_shutdown(device_t dev)
13239f55f5f5SRafal Jaworowski {
13249f55f5f5SRafal Jaworowski 	struct mge_softc *sc = device_get_softc(dev);
13259f55f5f5SRafal Jaworowski 
13269f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
13279f55f5f5SRafal Jaworowski 
13289f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
13299f55f5f5SRafal Jaworowski         if (sc->ifp->if_capenable & IFCAP_POLLING)
13309f55f5f5SRafal Jaworowski 		ether_poll_deregister(sc->ifp);
13319f55f5f5SRafal Jaworowski #endif
13329f55f5f5SRafal Jaworowski 
13339f55f5f5SRafal Jaworowski 	mge_stop(sc);
13349f55f5f5SRafal Jaworowski 
13359f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
13369f55f5f5SRafal Jaworowski 
13379f55f5f5SRafal Jaworowski 	return (0);
13389f55f5f5SRafal Jaworowski }
13399f55f5f5SRafal Jaworowski 
13409f55f5f5SRafal Jaworowski static int
13419f55f5f5SRafal Jaworowski mge_encap(struct mge_softc *sc, struct mbuf *m0)
13429f55f5f5SRafal Jaworowski {
13439f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw = NULL;
13449f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
13459f55f5f5SRafal Jaworowski 	bus_dma_segment_t segs[MGE_TX_DESC_NUM];
13469f55f5f5SRafal Jaworowski 	bus_dmamap_t mapp;
13479f55f5f5SRafal Jaworowski 	int error;
13489f55f5f5SRafal Jaworowski 	int seg, nsegs;
13499f55f5f5SRafal Jaworowski 	int desc_no;
13509f55f5f5SRafal Jaworowski 
13519f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
13529f55f5f5SRafal Jaworowski 
13539f55f5f5SRafal Jaworowski 	/* Check for free descriptors */
13549f55f5f5SRafal Jaworowski 	if (sc->tx_desc_used_count + 1 >= MGE_TX_DESC_NUM) {
13559f55f5f5SRafal Jaworowski 		/* No free descriptors */
13569f55f5f5SRafal Jaworowski 		return (-1);
13579f55f5f5SRafal Jaworowski 	}
13589f55f5f5SRafal Jaworowski 
13599f55f5f5SRafal Jaworowski 	/* Fetch unused map */
13609f55f5f5SRafal Jaworowski 	desc_no = sc->tx_desc_curr;
13619f55f5f5SRafal Jaworowski 	dw = &sc->mge_tx_desc[desc_no];
13629f55f5f5SRafal Jaworowski 	mapp = dw->buffer_dmap;
13639f55f5f5SRafal Jaworowski 
13649f55f5f5SRafal Jaworowski 	bus_dmamap_sync(sc->mge_desc_dtag, mapp,
13659f55f5f5SRafal Jaworowski 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
13669f55f5f5SRafal Jaworowski 
13679f55f5f5SRafal Jaworowski 	/* Create mapping in DMA memory */
13689f55f5f5SRafal Jaworowski 	error = bus_dmamap_load_mbuf_sg(sc->mge_tx_dtag, mapp, m0, segs, &nsegs,
13699f55f5f5SRafal Jaworowski 	    BUS_DMA_NOWAIT);
13709f55f5f5SRafal Jaworowski 	if (error != 0 || nsegs != 1 ) {
13719f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, mapp);
13729f55f5f5SRafal Jaworowski 		return ((error != 0) ? error : -1);
13739f55f5f5SRafal Jaworowski 	}
13749f55f5f5SRafal Jaworowski 
13759f55f5f5SRafal Jaworowski 	bus_dmamap_sync(sc->mge_tx_dtag, mapp, BUS_DMASYNC_PREWRITE);
13769f55f5f5SRafal Jaworowski 
13779f55f5f5SRafal Jaworowski 	/* Everything is ok, now we can send buffers */
13789f55f5f5SRafal Jaworowski 	for (seg = 0; seg < nsegs; seg++) {
13799f55f5f5SRafal Jaworowski 		dw->mge_desc->byte_count = segs[seg].ds_len;
13809f55f5f5SRafal Jaworowski 		dw->mge_desc->buffer = segs[seg].ds_addr;
13819f55f5f5SRafal Jaworowski 		dw->buffer = m0;
13829f55f5f5SRafal Jaworowski 		dw->mge_desc->cmd_status = MGE_TX_LAST | MGE_TX_FIRST |
13839f55f5f5SRafal Jaworowski 		    MGE_TX_ETH_CRC | MGE_TX_EN_INT | MGE_TX_PADDING |
13849f55f5f5SRafal Jaworowski 		    MGE_DMA_OWNED;
13859f55f5f5SRafal Jaworowski 
13869f55f5f5SRafal Jaworowski 		if (seg == 0)
13879f55f5f5SRafal Jaworowski 			mge_offload_setup_descriptor(sc, dw);
13889f55f5f5SRafal Jaworowski 	}
13899f55f5f5SRafal Jaworowski 
13909f55f5f5SRafal Jaworowski 	bus_dmamap_sync(sc->mge_desc_dtag, mapp,
13919f55f5f5SRafal Jaworowski 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
13929f55f5f5SRafal Jaworowski 
13939f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = (++sc->tx_desc_curr) % MGE_TX_DESC_NUM;
13949f55f5f5SRafal Jaworowski 	sc->tx_desc_used_count++;
13959f55f5f5SRafal Jaworowski 	return (0);
13969f55f5f5SRafal Jaworowski }
13979f55f5f5SRafal Jaworowski 
13989f55f5f5SRafal Jaworowski static void
13999f55f5f5SRafal Jaworowski mge_tick(void *msc)
14009f55f5f5SRafal Jaworowski {
14019f55f5f5SRafal Jaworowski 	struct mge_softc *sc = msc;
14029f55f5f5SRafal Jaworowski 
14039f55f5f5SRafal Jaworowski 	/* Check for TX timeout */
14049f55f5f5SRafal Jaworowski 	mge_watchdog(sc);
14059f55f5f5SRafal Jaworowski 
14069f55f5f5SRafal Jaworowski 	mii_tick(sc->mii);
14079f55f5f5SRafal Jaworowski 
14089f55f5f5SRafal Jaworowski 	/* Check for media type change */
14099f55f5f5SRafal Jaworowski 	if(sc->mge_media_status != sc->mii->mii_media.ifm_media)
14109f55f5f5SRafal Jaworowski 		mge_ifmedia_upd(sc->ifp);
14119f55f5f5SRafal Jaworowski 
14129f55f5f5SRafal Jaworowski 	/* Schedule another timeout one second from now */
14139f55f5f5SRafal Jaworowski 	callout_reset(&sc->wd_callout, hz, mge_tick, sc);
14149f55f5f5SRafal Jaworowski }
14159f55f5f5SRafal Jaworowski 
14169f55f5f5SRafal Jaworowski static void
14179f55f5f5SRafal Jaworowski mge_watchdog(struct mge_softc *sc)
14189f55f5f5SRafal Jaworowski {
14199f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
14209f55f5f5SRafal Jaworowski 
14219f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
14229f55f5f5SRafal Jaworowski 
14239f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
14249f55f5f5SRafal Jaworowski 
14259f55f5f5SRafal Jaworowski 	if (sc->wd_timer == 0 || --sc->wd_timer) {
14269f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
14279f55f5f5SRafal Jaworowski 		return;
14289f55f5f5SRafal Jaworowski 	}
14299f55f5f5SRafal Jaworowski 
14309f55f5f5SRafal Jaworowski 	ifp->if_oerrors++;
14319f55f5f5SRafal Jaworowski 	if_printf(ifp, "watchdog timeout\n");
14329f55f5f5SRafal Jaworowski 
14339f55f5f5SRafal Jaworowski 	mge_stop(sc);
14349f55f5f5SRafal Jaworowski 	mge_init_locked(sc);
14359f55f5f5SRafal Jaworowski 
14369f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
14379f55f5f5SRafal Jaworowski }
14389f55f5f5SRafal Jaworowski 
14399f55f5f5SRafal Jaworowski static void
14409f55f5f5SRafal Jaworowski mge_start(struct ifnet *ifp)
14419f55f5f5SRafal Jaworowski {
14429f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
14439f55f5f5SRafal Jaworowski 
14449f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK(sc);
14459f55f5f5SRafal Jaworowski 
14469f55f5f5SRafal Jaworowski 	mge_start_locked(ifp);
14479f55f5f5SRafal Jaworowski 
14489f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_UNLOCK(sc);
14499f55f5f5SRafal Jaworowski }
14509f55f5f5SRafal Jaworowski 
14519f55f5f5SRafal Jaworowski static void
14529f55f5f5SRafal Jaworowski mge_start_locked(struct ifnet *ifp)
14539f55f5f5SRafal Jaworowski {
14549f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
14559f55f5f5SRafal Jaworowski 	struct mbuf *m0, *mtmp;
14569f55f5f5SRafal Jaworowski 	uint32_t reg_val, queued = 0;
14579f55f5f5SRafal Jaworowski 
14589f55f5f5SRafal Jaworowski 	sc = ifp->if_softc;
14599f55f5f5SRafal Jaworowski 
14609f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK_ASSERT(sc);
14619f55f5f5SRafal Jaworowski 
14629f55f5f5SRafal Jaworowski 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
14639f55f5f5SRafal Jaworowski 	    IFF_DRV_RUNNING)
14649f55f5f5SRafal Jaworowski 		return;
14659f55f5f5SRafal Jaworowski 
14669f55f5f5SRafal Jaworowski 	for (;;) {
14679f55f5f5SRafal Jaworowski 		/* Get packet from the queue */
14689f55f5f5SRafal Jaworowski 		IF_DEQUEUE(&ifp->if_snd, m0);
14699f55f5f5SRafal Jaworowski 		if (m0 == NULL)
14709f55f5f5SRafal Jaworowski 			break;
14719f55f5f5SRafal Jaworowski 
14729f55f5f5SRafal Jaworowski 		mtmp = m_defrag(m0, M_DONTWAIT);
14739f55f5f5SRafal Jaworowski 		if (mtmp)
14749f55f5f5SRafal Jaworowski 			m0 = mtmp;
14759f55f5f5SRafal Jaworowski 
14769f55f5f5SRafal Jaworowski 		if (mge_encap(sc, m0)) {
14779f55f5f5SRafal Jaworowski 			IF_PREPEND(&ifp->if_snd, m0);
14789f55f5f5SRafal Jaworowski 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
14799f55f5f5SRafal Jaworowski 			break;
14809f55f5f5SRafal Jaworowski 		}
14819f55f5f5SRafal Jaworowski 		queued++;
14829f55f5f5SRafal Jaworowski 		BPF_MTAP(ifp, m0);
14839f55f5f5SRafal Jaworowski 	}
14849f55f5f5SRafal Jaworowski 
14859f55f5f5SRafal Jaworowski 	if (queued) {
14869f55f5f5SRafal Jaworowski 		/* Enable transmitter and watchdog timer */
14879f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD);
14889f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_ENABLE_TXQ);
14899f55f5f5SRafal Jaworowski 		sc->wd_timer = 5;
14909f55f5f5SRafal Jaworowski 	}
14919f55f5f5SRafal Jaworowski }
14929f55f5f5SRafal Jaworowski 
14939f55f5f5SRafal Jaworowski static void
14949f55f5f5SRafal Jaworowski mge_stop(struct mge_softc *sc)
14959f55f5f5SRafal Jaworowski {
14969f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
14979f55f5f5SRafal Jaworowski 	volatile uint32_t reg_val, status;
14989f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
14999f55f5f5SRafal Jaworowski 	struct mge_desc *desc;
15009f55f5f5SRafal Jaworowski 	int count;
15019f55f5f5SRafal Jaworowski 
15029f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
15039f55f5f5SRafal Jaworowski 
15049f55f5f5SRafal Jaworowski 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
15059f55f5f5SRafal Jaworowski 		return;
15069f55f5f5SRafal Jaworowski 
15079f55f5f5SRafal Jaworowski 	/* Stop tick engine */
15089f55f5f5SRafal Jaworowski 	callout_stop(&sc->wd_callout);
15099f55f5f5SRafal Jaworowski 
15109f55f5f5SRafal Jaworowski 	/* Disable interface */
15119f55f5f5SRafal Jaworowski 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
15129f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
15139f55f5f5SRafal Jaworowski 
15149f55f5f5SRafal Jaworowski 	/* Disable interrupts */
15159f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 0);
15169f55f5f5SRafal Jaworowski 
15179f55f5f5SRafal Jaworowski 	/* Disable Rx and Tx */
15189f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD);
15199f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_DISABLE_TXQ);
15209f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_DISABLE_RXQ_ALL);
15219f55f5f5SRafal Jaworowski 
15229f55f5f5SRafal Jaworowski 	/* Remove pending data from TX queue */
15235817716fSRafal Jaworowski 	while (sc->tx_desc_used_idx != sc->tx_desc_curr &&
15245817716fSRafal Jaworowski 	    sc->tx_desc_used_count) {
15259f55f5f5SRafal Jaworowski 		/* Get the descriptor */
15269f55f5f5SRafal Jaworowski 		dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
15279f55f5f5SRafal Jaworowski 		desc = dw->mge_desc;
15289f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
15299f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
15309f55f5f5SRafal Jaworowski 
15319f55f5f5SRafal Jaworowski 		/* Get descriptor status */
15329f55f5f5SRafal Jaworowski 		status = desc->cmd_status;
15339f55f5f5SRafal Jaworowski 
15349f55f5f5SRafal Jaworowski 		if (status & MGE_DMA_OWNED)
15359f55f5f5SRafal Jaworowski 			break;
15369f55f5f5SRafal Jaworowski 
15379f55f5f5SRafal Jaworowski 		sc->tx_desc_used_idx = (++sc->tx_desc_used_idx) %
15389f55f5f5SRafal Jaworowski 		    MGE_TX_DESC_NUM;
15395817716fSRafal Jaworowski 		sc->tx_desc_used_count--;
15409f55f5f5SRafal Jaworowski 
15419f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
15429f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTWRITE);
15439f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap);
15449f55f5f5SRafal Jaworowski 
15459f55f5f5SRafal Jaworowski 		m_freem(dw->buffer);
15469f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
15479f55f5f5SRafal Jaworowski 	}
15489f55f5f5SRafal Jaworowski 
15499f55f5f5SRafal Jaworowski 	/* Wait for end of transmission */
15509f55f5f5SRafal Jaworowski 	count = 0x100000;
15519f55f5f5SRafal Jaworowski 	while (count--) {
15529f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_PORT_STATUS);
15539f55f5f5SRafal Jaworowski 		if ( !(reg_val & MGE_STATUS_TX_IN_PROG) &&
15549f55f5f5SRafal Jaworowski 		    (reg_val & MGE_STATUS_TX_FIFO_EMPTY))
15559f55f5f5SRafal Jaworowski 			break;
15569f55f5f5SRafal Jaworowski 		DELAY(100);
15579f55f5f5SRafal Jaworowski 	}
15589f55f5f5SRafal Jaworowski 
15599f55f5f5SRafal Jaworowski 	if(!count)
15609f55f5f5SRafal Jaworowski 		if_printf(ifp, "%s: timeout while waiting for end of transmission\n",
15619f55f5f5SRafal Jaworowski 		    __FUNCTION__);
15629f55f5f5SRafal Jaworowski 
15639f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL);
15649f55f5f5SRafal Jaworowski 	reg_val &= ~(PORT_SERIAL_ENABLE);
15659f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL ,reg_val);
15669f55f5f5SRafal Jaworowski }
15679f55f5f5SRafal Jaworowski 
15689f55f5f5SRafal Jaworowski static int
15699f55f5f5SRafal Jaworowski mge_suspend(device_t dev)
15709f55f5f5SRafal Jaworowski {
15719f55f5f5SRafal Jaworowski 
15729f55f5f5SRafal Jaworowski 	device_printf(dev, "%s\n", __FUNCTION__);
15739f55f5f5SRafal Jaworowski 	return (0);
15749f55f5f5SRafal Jaworowski }
15759f55f5f5SRafal Jaworowski 
15769f55f5f5SRafal Jaworowski static void
15779f55f5f5SRafal Jaworowski mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame,
15789f55f5f5SRafal Jaworowski     uint32_t status, uint16_t bufsize)
15799f55f5f5SRafal Jaworowski {
15809f55f5f5SRafal Jaworowski 	int csum_flags = 0;
15819f55f5f5SRafal Jaworowski 
15829f55f5f5SRafal Jaworowski 	if (ifp->if_capenable & IFCAP_RXCSUM) {
15839f55f5f5SRafal Jaworowski 		if ((status & MGE_RX_L3_IS_IP) && (status & MGE_RX_IP_OK))
15849f55f5f5SRafal Jaworowski 			csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID;
15859f55f5f5SRafal Jaworowski 
15869f55f5f5SRafal Jaworowski 		if ((bufsize & MGE_RX_IP_FRAGMENT) == 0 &&
15879f55f5f5SRafal Jaworowski 		    (MGE_RX_L4_IS_TCP(status) || MGE_RX_L4_IS_UDP(status)) &&
15889f55f5f5SRafal Jaworowski 		    (status & MGE_RX_L4_CSUM_OK)) {
15899f55f5f5SRafal Jaworowski 			csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
15909f55f5f5SRafal Jaworowski 			frame->m_pkthdr.csum_data = 0xFFFF;
15919f55f5f5SRafal Jaworowski 		}
15929f55f5f5SRafal Jaworowski 
15939f55f5f5SRafal Jaworowski 		frame->m_pkthdr.csum_flags = csum_flags;
15949f55f5f5SRafal Jaworowski 	}
15959f55f5f5SRafal Jaworowski }
15969f55f5f5SRafal Jaworowski 
15979f55f5f5SRafal Jaworowski static void
15989f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(struct mge_softc *sc, struct mge_desc_wrapper *dw)
15999f55f5f5SRafal Jaworowski {
16009f55f5f5SRafal Jaworowski 	struct mbuf *m0 = dw->buffer;
16019f55f5f5SRafal Jaworowski 	struct ether_vlan_header *eh = mtod(m0, struct ether_vlan_header *);
16029f55f5f5SRafal Jaworowski 	int csum_flags = m0->m_pkthdr.csum_flags;
16039f55f5f5SRafal Jaworowski 	int cmd_status = 0;
16049f55f5f5SRafal Jaworowski 	struct ip *ip;
16059f55f5f5SRafal Jaworowski 	int ehlen, etype;
16069f55f5f5SRafal Jaworowski 
16079f55f5f5SRafal Jaworowski 	if (csum_flags) {
16089f55f5f5SRafal Jaworowski 		if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
16099f55f5f5SRafal Jaworowski 			etype = ntohs(eh->evl_proto);
16109f55f5f5SRafal Jaworowski 			ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
16119f55f5f5SRafal Jaworowski 			csum_flags |= MGE_TX_VLAN_TAGGED;
16129f55f5f5SRafal Jaworowski 		} else {
16139f55f5f5SRafal Jaworowski 			etype = ntohs(eh->evl_encap_proto);
16149f55f5f5SRafal Jaworowski 			ehlen = ETHER_HDR_LEN;
16159f55f5f5SRafal Jaworowski 		}
16169f55f5f5SRafal Jaworowski 
16179f55f5f5SRafal Jaworowski 		if (etype != ETHERTYPE_IP) {
16189f55f5f5SRafal Jaworowski 			if_printf(sc->ifp,
16199f55f5f5SRafal Jaworowski 			    "TCP/IP Offload enabled for unsupported "
16209f55f5f5SRafal Jaworowski 			    "protocol!\n");
16219f55f5f5SRafal Jaworowski 			return;
16229f55f5f5SRafal Jaworowski 		}
16239f55f5f5SRafal Jaworowski 
16249f55f5f5SRafal Jaworowski 		ip = (struct ip *)(m0->m_data + ehlen);
16259f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_IP_HDR_SIZE(ip->ip_hl);
16269f55f5f5SRafal Jaworowski 
16279f55f5f5SRafal Jaworowski 		if ((m0->m_flags & M_FRAG) == 0)
16289f55f5f5SRafal Jaworowski 			cmd_status |= MGE_TX_NOT_FRAGMENT;
16299f55f5f5SRafal Jaworowski 	}
16309f55f5f5SRafal Jaworowski 
16319f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_IP)
16329f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_IP_CSUM;
16339f55f5f5SRafal Jaworowski 
16349f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_TCP)
16359f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_L4_CSUM;
16369f55f5f5SRafal Jaworowski 
16379f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_UDP)
16389f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_L4_CSUM | MGE_TX_UDP;
16399f55f5f5SRafal Jaworowski 
16409f55f5f5SRafal Jaworowski 	dw->mge_desc->cmd_status |= cmd_status;
16419f55f5f5SRafal Jaworowski }
16429f55f5f5SRafal Jaworowski 
16439f55f5f5SRafal Jaworowski static void
16449f55f5f5SRafal Jaworowski mge_intrs_ctrl(struct mge_softc *sc, int enable)
16459f55f5f5SRafal Jaworowski {
16469f55f5f5SRafal Jaworowski 
16479f55f5f5SRafal Jaworowski 	if (enable) {
16489f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK , MGE_PORT_INT_RXQ0 |
16499f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXTEND | MGE_PORT_INT_RXERRQ0);
16509f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT , MGE_PORT_INT_EXT_TXERR0 |
16519f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXT_RXOR | MGE_PORT_INT_EXT_TXUR |
16529f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXT_TXBUF0);
16539f55f5f5SRafal Jaworowski 	} else {
16549f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_INT_CAUSE, 0x0);
16559f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_INT_MASK, 0x0);
16569f55f5f5SRafal Jaworowski 
16579f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE, 0x0);
16589f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, 0x0);
16599f55f5f5SRafal Jaworowski 
16609f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK, 0x0);
16619f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT, 0x0);
16629f55f5f5SRafal Jaworowski 	}
16639f55f5f5SRafal Jaworowski }
16649f55f5f5SRafal Jaworowski 
16659f55f5f5SRafal Jaworowski static uint8_t
16669f55f5f5SRafal Jaworowski mge_crc8(uint8_t *data, int size)
16679f55f5f5SRafal Jaworowski {
16689f55f5f5SRafal Jaworowski 	uint8_t crc = 0;
16699f55f5f5SRafal Jaworowski 	static const uint8_t ct[256] = {
16709f55f5f5SRafal Jaworowski 		0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
16719f55f5f5SRafal Jaworowski 		0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
16729f55f5f5SRafal Jaworowski 		0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
16739f55f5f5SRafal Jaworowski 		0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
16749f55f5f5SRafal Jaworowski 		0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
16759f55f5f5SRafal Jaworowski 		0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
16769f55f5f5SRafal Jaworowski 		0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
16779f55f5f5SRafal Jaworowski 		0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
16789f55f5f5SRafal Jaworowski 		0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
16799f55f5f5SRafal Jaworowski 		0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
16809f55f5f5SRafal Jaworowski 		0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
16819f55f5f5SRafal Jaworowski 		0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
16829f55f5f5SRafal Jaworowski 		0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
16839f55f5f5SRafal Jaworowski 		0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
16849f55f5f5SRafal Jaworowski 		0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
16859f55f5f5SRafal Jaworowski 		0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
16869f55f5f5SRafal Jaworowski 		0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
16879f55f5f5SRafal Jaworowski 		0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
16889f55f5f5SRafal Jaworowski 		0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
16899f55f5f5SRafal Jaworowski 		0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
16909f55f5f5SRafal Jaworowski 		0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
16919f55f5f5SRafal Jaworowski 		0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
16929f55f5f5SRafal Jaworowski 		0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
16939f55f5f5SRafal Jaworowski 		0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
16949f55f5f5SRafal Jaworowski 		0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
16959f55f5f5SRafal Jaworowski 		0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
16969f55f5f5SRafal Jaworowski 		0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
16979f55f5f5SRafal Jaworowski 		0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
16989f55f5f5SRafal Jaworowski 		0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
16999f55f5f5SRafal Jaworowski 		0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
17009f55f5f5SRafal Jaworowski 		0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
17019f55f5f5SRafal Jaworowski 		0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
17029f55f5f5SRafal Jaworowski 	};
17039f55f5f5SRafal Jaworowski 
17049f55f5f5SRafal Jaworowski 	while(size--)
17059f55f5f5SRafal Jaworowski 		crc = ct[crc ^ *(data++)];
17069f55f5f5SRafal Jaworowski 
17079f55f5f5SRafal Jaworowski 	return(crc);
17089f55f5f5SRafal Jaworowski }
17099f55f5f5SRafal Jaworowski 
17109f55f5f5SRafal Jaworowski static void
17119f55f5f5SRafal Jaworowski mge_setup_multicast(struct mge_softc *sc)
17129f55f5f5SRafal Jaworowski {
17139f55f5f5SRafal Jaworowski 	uint8_t special[5] = { 0x01, 0x00, 0x5E, 0x00, 0x00 };
17149f55f5f5SRafal Jaworowski 	uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1;
17159f55f5f5SRafal Jaworowski 	uint32_t smt[MGE_MCAST_REG_NUMBER];
17169f55f5f5SRafal Jaworowski 	uint32_t omt[MGE_MCAST_REG_NUMBER];
17179f55f5f5SRafal Jaworowski 	struct ifnet *ifp = sc->ifp;
17189f55f5f5SRafal Jaworowski 	struct ifmultiaddr *ifma;
17199f55f5f5SRafal Jaworowski 	uint8_t *mac;
17209f55f5f5SRafal Jaworowski 	int i;
17219f55f5f5SRafal Jaworowski 
17229f55f5f5SRafal Jaworowski 	if (ifp->if_flags & IFF_ALLMULTI) {
17239f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++)
17249f55f5f5SRafal Jaworowski 			smt[i] = omt[i] = (v << 24) | (v << 16) | (v << 8) | v;
17259f55f5f5SRafal Jaworowski 	} else {
17269f55f5f5SRafal Jaworowski 		memset(smt, 0, sizeof(smt));
17279f55f5f5SRafal Jaworowski 		memset(omt, 0, sizeof(omt));
17289f55f5f5SRafal Jaworowski 
17299f55f5f5SRafal Jaworowski 		IF_ADDR_LOCK(ifp);
17309f55f5f5SRafal Jaworowski 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
17319f55f5f5SRafal Jaworowski 			if (ifma->ifma_addr->sa_family != AF_LINK)
17329f55f5f5SRafal Jaworowski 				continue;
17339f55f5f5SRafal Jaworowski 
17349f55f5f5SRafal Jaworowski 			mac = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
17359f55f5f5SRafal Jaworowski 			if (memcmp(mac, special, sizeof(special)) == 0) {
17369f55f5f5SRafal Jaworowski 				i = mac[5];
17379f55f5f5SRafal Jaworowski 				smt[i >> 2] |= v << ((i & 0x03) << 3);
17389f55f5f5SRafal Jaworowski 			} else {
17399f55f5f5SRafal Jaworowski 				i = mge_crc8(mac, ETHER_ADDR_LEN);
17409f55f5f5SRafal Jaworowski 				omt[i >> 2] |= v << ((i & 0x03) << 3);
17419f55f5f5SRafal Jaworowski 			}
17429f55f5f5SRafal Jaworowski 		}
17439f55f5f5SRafal Jaworowski 		IF_ADDR_UNLOCK(ifp);
17449f55f5f5SRafal Jaworowski 	}
17459f55f5f5SRafal Jaworowski 
17469f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
17479f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), smt[i]);
17489f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), omt[i]);
17499f55f5f5SRafal Jaworowski 	}
17509f55f5f5SRafal Jaworowski }
17519f55f5f5SRafal Jaworowski 
17529f55f5f5SRafal Jaworowski static void
17539f55f5f5SRafal Jaworowski mge_set_rxic(struct mge_softc *sc)
17549f55f5f5SRafal Jaworowski {
17559f55f5f5SRafal Jaworowski 	uint32_t reg;
17569f55f5f5SRafal Jaworowski 
17578e1dc58eSRafal Jaworowski 	if (sc->rx_ic_time > sc->mge_rx_ipg_max)
17588e1dc58eSRafal Jaworowski 		sc->rx_ic_time = sc->mge_rx_ipg_max;
17599f55f5f5SRafal Jaworowski 
17609f55f5f5SRafal Jaworowski 	reg = MGE_READ(sc, MGE_SDMA_CONFIG);
17618e1dc58eSRafal Jaworowski 	reg &= ~mge_rx_ipg(sc->mge_rx_ipg_max, sc->mge_ver);
17628e1dc58eSRafal Jaworowski 	reg |= mge_rx_ipg(sc->rx_ic_time, sc->mge_ver);
17639f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_SDMA_CONFIG, reg);
17649f55f5f5SRafal Jaworowski }
17659f55f5f5SRafal Jaworowski 
17669f55f5f5SRafal Jaworowski static void
17679f55f5f5SRafal Jaworowski mge_set_txic(struct mge_softc *sc)
17689f55f5f5SRafal Jaworowski {
17699f55f5f5SRafal Jaworowski 	uint32_t reg;
17709f55f5f5SRafal Jaworowski 
17718e1dc58eSRafal Jaworowski 	if (sc->tx_ic_time > sc->mge_tfut_ipg_max)
17728e1dc58eSRafal Jaworowski 		sc->tx_ic_time = sc->mge_tfut_ipg_max;
17739f55f5f5SRafal Jaworowski 
17749f55f5f5SRafal Jaworowski 	reg = MGE_READ(sc, MGE_TX_FIFO_URGENT_TRSH);
17758e1dc58eSRafal Jaworowski 	reg &= ~mge_tfut_ipg(sc->mge_tfut_ipg_max, sc->mge_ver);
17768e1dc58eSRafal Jaworowski 	reg |= mge_tfut_ipg(sc->tx_ic_time, sc->mge_ver);
17779f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, reg);
17789f55f5f5SRafal Jaworowski }
17799f55f5f5SRafal Jaworowski 
17809f55f5f5SRafal Jaworowski static int
17819f55f5f5SRafal Jaworowski mge_sysctl_ic(SYSCTL_HANDLER_ARGS)
17829f55f5f5SRafal Jaworowski {
17839f55f5f5SRafal Jaworowski 	struct mge_softc *sc = (struct mge_softc *)arg1;
17848e1dc58eSRafal Jaworowski 	uint32_t time;
17859f55f5f5SRafal Jaworowski 	int error;
17869f55f5f5SRafal Jaworowski 
17878e1dc58eSRafal Jaworowski 	time = (arg2 == MGE_IC_RX) ? sc->rx_ic_time : sc->tx_ic_time;
17889f55f5f5SRafal Jaworowski 	error = sysctl_handle_int(oidp, &time, 0, req);
17899f55f5f5SRafal Jaworowski 	if (error != 0)
17909f55f5f5SRafal Jaworowski 		return(error);
17919f55f5f5SRafal Jaworowski 
17929f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
17939f55f5f5SRafal Jaworowski 	if (arg2 == MGE_IC_RX) {
17949f55f5f5SRafal Jaworowski 		sc->rx_ic_time = time;
17959f55f5f5SRafal Jaworowski 		mge_set_rxic(sc);
17969f55f5f5SRafal Jaworowski 	} else {
17979f55f5f5SRafal Jaworowski 		sc->tx_ic_time = time;
17989f55f5f5SRafal Jaworowski 		mge_set_txic(sc);
17999f55f5f5SRafal Jaworowski 	}
18009f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
18019f55f5f5SRafal Jaworowski 
18029f55f5f5SRafal Jaworowski 	return(0);
18039f55f5f5SRafal Jaworowski }
18049f55f5f5SRafal Jaworowski 
18059f55f5f5SRafal Jaworowski static void
18069f55f5f5SRafal Jaworowski mge_add_sysctls(struct mge_softc *sc)
18079f55f5f5SRafal Jaworowski {
18089f55f5f5SRafal Jaworowski 	struct sysctl_ctx_list *ctx;
18099f55f5f5SRafal Jaworowski 	struct sysctl_oid_list *children;
18109f55f5f5SRafal Jaworowski 	struct sysctl_oid *tree;
18119f55f5f5SRafal Jaworowski 
18129f55f5f5SRafal Jaworowski 	ctx = device_get_sysctl_ctx(sc->dev);
18139f55f5f5SRafal Jaworowski 	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
18149f55f5f5SRafal Jaworowski 	tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "int_coal",
18159f55f5f5SRafal Jaworowski 	    CTLFLAG_RD, 0, "MGE Interrupts coalescing");
18169f55f5f5SRafal Jaworowski 	children = SYSCTL_CHILDREN(tree);
18179f55f5f5SRafal Jaworowski 
18189f55f5f5SRafal Jaworowski 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_time",
18199f55f5f5SRafal Jaworowski 	    CTLTYPE_UINT | CTLFLAG_RW, sc, MGE_IC_RX, mge_sysctl_ic,
18209f55f5f5SRafal Jaworowski 	    "I", "IC RX time threshold");
18219f55f5f5SRafal Jaworowski 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_time",
18229f55f5f5SRafal Jaworowski 	    CTLTYPE_UINT | CTLFLAG_RW, sc, MGE_IC_TX, mge_sysctl_ic,
18239f55f5f5SRafal Jaworowski 	    "I", "IC TX time threshold");
18249f55f5f5SRafal Jaworowski }
1825