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