xref: /freebsd/sys/dev/mge/if_mge.c (revision b8fad6c0ef9355d1dda96fa382708b0cf68d27ef)
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>
5376039bc8SGleb Smirnoff #include <net/if_var.h>
549f55f5f5SRafal Jaworowski #include <net/if_arp.h>
559f55f5f5SRafal Jaworowski #include <net/if_dl.h>
569f55f5f5SRafal Jaworowski #include <net/if_media.h>
579f55f5f5SRafal Jaworowski #include <net/if_types.h>
589f55f5f5SRafal Jaworowski #include <net/if_vlan_var.h>
599f55f5f5SRafal Jaworowski 
609f55f5f5SRafal Jaworowski #include <netinet/in_systm.h>
619f55f5f5SRafal Jaworowski #include <netinet/in.h>
629f55f5f5SRafal Jaworowski #include <netinet/ip.h>
639f55f5f5SRafal Jaworowski 
649f55f5f5SRafal Jaworowski #include <sys/sockio.h>
659f55f5f5SRafal Jaworowski #include <sys/bus.h>
669f55f5f5SRafal Jaworowski #include <machine/bus.h>
679f55f5f5SRafal Jaworowski #include <sys/rman.h>
689f55f5f5SRafal Jaworowski #include <machine/resource.h>
699f55f5f5SRafal Jaworowski 
709f55f5f5SRafal Jaworowski #include <dev/mii/mii.h>
719f55f5f5SRafal Jaworowski #include <dev/mii/miivar.h>
729f55f5f5SRafal Jaworowski 
73db5ef4fcSRafal Jaworowski #include <dev/fdt/fdt_common.h>
74db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus.h>
75db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h>
769f55f5f5SRafal Jaworowski 
779f55f5f5SRafal Jaworowski #include <dev/mge/if_mgevar.h>
789f55f5f5SRafal Jaworowski #include <arm/mv/mvreg.h>
798e1dc58eSRafal Jaworowski #include <arm/mv/mvvar.h>
809f55f5f5SRafal Jaworowski 
819f55f5f5SRafal Jaworowski #include "miibus_if.h"
829f55f5f5SRafal Jaworowski 
839f55f5f5SRafal Jaworowski static int mge_probe(device_t dev);
849f55f5f5SRafal Jaworowski static int mge_attach(device_t dev);
859f55f5f5SRafal Jaworowski static int mge_detach(device_t dev);
869f55f5f5SRafal Jaworowski static int mge_shutdown(device_t dev);
879f55f5f5SRafal Jaworowski static int mge_suspend(device_t dev);
889f55f5f5SRafal Jaworowski static int mge_resume(device_t dev);
899f55f5f5SRafal Jaworowski 
909f55f5f5SRafal Jaworowski static int mge_miibus_readreg(device_t dev, int phy, int reg);
918e45f0b7SAndriy Gapon static int mge_miibus_writereg(device_t dev, int phy, int reg, int value);
929f55f5f5SRafal Jaworowski 
939f55f5f5SRafal Jaworowski static int mge_ifmedia_upd(struct ifnet *ifp);
949f55f5f5SRafal Jaworowski static void mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
959f55f5f5SRafal Jaworowski 
969f55f5f5SRafal Jaworowski static void mge_init(void *arg);
979f55f5f5SRafal Jaworowski static void mge_init_locked(void *arg);
989f55f5f5SRafal Jaworowski static void mge_start(struct ifnet *ifp);
999f55f5f5SRafal Jaworowski static void mge_start_locked(struct ifnet *ifp);
1009f55f5f5SRafal Jaworowski static void mge_watchdog(struct mge_softc *sc);
1019f55f5f5SRafal Jaworowski static int mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
1029f55f5f5SRafal Jaworowski 
1038e1dc58eSRafal Jaworowski static uint32_t mge_tfut_ipg(uint32_t val, int ver);
1048e1dc58eSRafal Jaworowski static uint32_t mge_rx_ipg(uint32_t val, int ver);
1058e1dc58eSRafal Jaworowski static void mge_ver_params(struct mge_softc *sc);
1068e1dc58eSRafal Jaworowski 
1079f55f5f5SRafal Jaworowski static void mge_intrs_ctrl(struct mge_softc *sc, int enable);
10875f1438bSOleksandr Tymoshenko static void mge_intr_rxtx(void *arg);
1099f55f5f5SRafal Jaworowski static void mge_intr_rx(void *arg);
11075f1438bSOleksandr Tymoshenko static void mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause,
11175f1438bSOleksandr Tymoshenko     uint32_t int_cause_ext);
1121abcdbd1SAttilio Rao static int mge_intr_rx_locked(struct mge_softc *sc, int count);
1139f55f5f5SRafal Jaworowski static void mge_intr_tx(void *arg);
1149f55f5f5SRafal Jaworowski static void mge_intr_tx_locked(struct mge_softc *sc);
1159f55f5f5SRafal Jaworowski static void mge_intr_misc(void *arg);
1169f55f5f5SRafal Jaworowski static void mge_intr_sum(void *arg);
1179f55f5f5SRafal Jaworowski static void mge_intr_err(void *arg);
1189f55f5f5SRafal Jaworowski static void mge_stop(struct mge_softc *sc);
1199f55f5f5SRafal Jaworowski static void mge_tick(void *msc);
1209f55f5f5SRafal Jaworowski static uint32_t mge_set_port_serial_control(uint32_t media);
1219f55f5f5SRafal Jaworowski static void mge_get_mac_address(struct mge_softc *sc, uint8_t *addr);
1229f55f5f5SRafal Jaworowski static void mge_set_mac_address(struct mge_softc *sc);
1239f55f5f5SRafal Jaworowski static void mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte,
1249f55f5f5SRafal Jaworowski     uint8_t queue);
1259f55f5f5SRafal Jaworowski static void mge_set_prom_mode(struct mge_softc *sc, uint8_t queue);
1269f55f5f5SRafal Jaworowski static int mge_allocate_dma(struct mge_softc *sc);
1279f55f5f5SRafal Jaworowski static int mge_alloc_desc_dma(struct mge_softc *sc,
1289f55f5f5SRafal Jaworowski     struct mge_desc_wrapper* desc_tab, uint32_t size, bus_dma_tag_t *buffer_tag);
1299f55f5f5SRafal Jaworowski static int mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map,
1309f55f5f5SRafal Jaworowski     struct mbuf **mbufp, bus_addr_t *paddr);
1319f55f5f5SRafal Jaworowski static void mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error);
1329f55f5f5SRafal Jaworowski static void mge_free_dma(struct mge_softc *sc);
1339f55f5f5SRafal Jaworowski static void mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab, uint32_t size,
1349f55f5f5SRafal Jaworowski     bus_dma_tag_t buffer_tag, uint8_t free_mbufs);
1359f55f5f5SRafal Jaworowski static void mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame,
1369f55f5f5SRafal Jaworowski     uint32_t status, uint16_t bufsize);
1379f55f5f5SRafal Jaworowski static void mge_offload_setup_descriptor(struct mge_softc *sc,
1389f55f5f5SRafal Jaworowski     struct mge_desc_wrapper *dw);
1399f55f5f5SRafal Jaworowski static uint8_t mge_crc8(uint8_t *data, int size);
1409f55f5f5SRafal Jaworowski static void mge_setup_multicast(struct mge_softc *sc);
1419f55f5f5SRafal Jaworowski static void mge_set_rxic(struct mge_softc *sc);
1429f55f5f5SRafal Jaworowski static void mge_set_txic(struct mge_softc *sc);
1439f55f5f5SRafal Jaworowski static void mge_add_sysctls(struct mge_softc *sc);
1449f55f5f5SRafal Jaworowski static int mge_sysctl_ic(SYSCTL_HANDLER_ARGS);
1459f55f5f5SRafal Jaworowski 
1469f55f5f5SRafal Jaworowski static device_method_t mge_methods[] = {
1479f55f5f5SRafal Jaworowski 	/* Device interface */
1489f55f5f5SRafal Jaworowski 	DEVMETHOD(device_probe,		mge_probe),
1499f55f5f5SRafal Jaworowski 	DEVMETHOD(device_attach,	mge_attach),
1509f55f5f5SRafal Jaworowski 	DEVMETHOD(device_detach,	mge_detach),
1519f55f5f5SRafal Jaworowski 	DEVMETHOD(device_shutdown,	mge_shutdown),
1529f55f5f5SRafal Jaworowski 	DEVMETHOD(device_suspend,	mge_suspend),
1539f55f5f5SRafal Jaworowski 	DEVMETHOD(device_resume,	mge_resume),
1549f55f5f5SRafal Jaworowski 	/* MII interface */
1559f55f5f5SRafal Jaworowski 	DEVMETHOD(miibus_readreg,	mge_miibus_readreg),
1569f55f5f5SRafal Jaworowski 	DEVMETHOD(miibus_writereg,	mge_miibus_writereg),
1579f55f5f5SRafal Jaworowski 	{ 0, 0 }
1589f55f5f5SRafal Jaworowski };
1599f55f5f5SRafal Jaworowski 
1609f55f5f5SRafal Jaworowski static driver_t mge_driver = {
1619f55f5f5SRafal Jaworowski 	"mge",
1629f55f5f5SRafal Jaworowski 	mge_methods,
1639f55f5f5SRafal Jaworowski 	sizeof(struct mge_softc),
1649f55f5f5SRafal Jaworowski };
1659f55f5f5SRafal Jaworowski 
1669f55f5f5SRafal Jaworowski static devclass_t mge_devclass;
1679f55f5f5SRafal Jaworowski 
168db5ef4fcSRafal Jaworowski DRIVER_MODULE(mge, simplebus, mge_driver, mge_devclass, 0, 0);
1699f55f5f5SRafal Jaworowski DRIVER_MODULE(miibus, mge, miibus_driver, miibus_devclass, 0, 0);
1709f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, ether, 1, 1, 1);
1719f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, miibus, 1, 1, 1);
1729f55f5f5SRafal Jaworowski 
1739f55f5f5SRafal Jaworowski static struct resource_spec res_spec[] = {
1749f55f5f5SRafal Jaworowski 	{ SYS_RES_MEMORY, 0, RF_ACTIVE },
1759f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
1769f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE },
1779f55f5f5SRafal Jaworowski 	{ SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE },
1789f55f5f5SRafal Jaworowski 	{ -1, 0 }
1799f55f5f5SRafal Jaworowski };
1809f55f5f5SRafal Jaworowski 
1819f55f5f5SRafal Jaworowski static struct {
1829f55f5f5SRafal Jaworowski 	driver_intr_t *handler;
1839f55f5f5SRafal Jaworowski 	char * description;
18475f1438bSOleksandr Tymoshenko } mge_intrs[MGE_INTR_COUNT + 1] = {
18575f1438bSOleksandr Tymoshenko 	{ mge_intr_rxtx,"GbE aggregated interrupt" },
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;
197db5ef4fcSRafal Jaworowski 	uint8_t lmac[6];
198db5ef4fcSRafal Jaworowski 	int i, valid;
1999f55f5f5SRafal Jaworowski 
200db5ef4fcSRafal Jaworowski 	/*
201db5ef4fcSRafal Jaworowski 	 * Retrieve hw address from the device tree.
202db5ef4fcSRafal Jaworowski 	 */
203db5ef4fcSRafal Jaworowski 	i = OF_getprop(sc->node, "local-mac-address", (void *)lmac, 6);
204db5ef4fcSRafal Jaworowski 	if (i == 6) {
205db5ef4fcSRafal Jaworowski 		valid = 0;
206db5ef4fcSRafal Jaworowski 		for (i = 0; i < 6; i++)
207db5ef4fcSRafal Jaworowski 			if (lmac[i] != 0) {
208db5ef4fcSRafal Jaworowski 				valid = 1;
209db5ef4fcSRafal Jaworowski 				break;
210db5ef4fcSRafal Jaworowski 			}
2119f55f5f5SRafal Jaworowski 
212db5ef4fcSRafal Jaworowski 		if (valid) {
213db5ef4fcSRafal Jaworowski 			bcopy(lmac, addr, 6);
214db5ef4fcSRafal Jaworowski 			return;
215db5ef4fcSRafal Jaworowski 		}
216db5ef4fcSRafal Jaworowski 	}
217db5ef4fcSRafal Jaworowski 
218db5ef4fcSRafal Jaworowski 	/*
219db5ef4fcSRafal Jaworowski 	 * Fall back -- use the currently programmed address.
220db5ef4fcSRafal Jaworowski 	 */
2219f55f5f5SRafal Jaworowski 	mac_l = MGE_READ(sc, MGE_MAC_ADDR_L);
2229f55f5f5SRafal Jaworowski 	mac_h = MGE_READ(sc, MGE_MAC_ADDR_H);
2239f55f5f5SRafal Jaworowski 
2249f55f5f5SRafal Jaworowski 	addr[0] = (mac_h & 0xff000000) >> 24;
2259f55f5f5SRafal Jaworowski 	addr[1] = (mac_h & 0x00ff0000) >> 16;
2269f55f5f5SRafal Jaworowski 	addr[2] = (mac_h & 0x0000ff00) >> 8;
2279f55f5f5SRafal Jaworowski 	addr[3] = (mac_h & 0x000000ff);
2289f55f5f5SRafal Jaworowski 	addr[4] = (mac_l & 0x0000ff00) >> 8;
2299f55f5f5SRafal Jaworowski 	addr[5] = (mac_l & 0x000000ff);
2309f55f5f5SRafal Jaworowski }
2319f55f5f5SRafal Jaworowski 
2328e1dc58eSRafal Jaworowski static uint32_t
2338e1dc58eSRafal Jaworowski mge_tfut_ipg(uint32_t val, int ver)
2348e1dc58eSRafal Jaworowski {
2358e1dc58eSRafal Jaworowski 
2368e1dc58eSRafal Jaworowski 	switch (ver) {
2378e1dc58eSRafal Jaworowski 	case 1:
2388e1dc58eSRafal Jaworowski 		return ((val & 0x3fff) << 4);
2398e1dc58eSRafal Jaworowski 	case 2:
2408e1dc58eSRafal Jaworowski 	default:
2418e1dc58eSRafal Jaworowski 		return ((val & 0xffff) << 4);
2428e1dc58eSRafal Jaworowski 	}
2438e1dc58eSRafal Jaworowski }
2448e1dc58eSRafal Jaworowski 
2458e1dc58eSRafal Jaworowski static uint32_t
2468e1dc58eSRafal Jaworowski mge_rx_ipg(uint32_t val, int ver)
2478e1dc58eSRafal Jaworowski {
2488e1dc58eSRafal Jaworowski 
2498e1dc58eSRafal Jaworowski 	switch (ver) {
2508e1dc58eSRafal Jaworowski 	case 1:
2518e1dc58eSRafal Jaworowski 		return ((val & 0x3fff) << 8);
2528e1dc58eSRafal Jaworowski 	case 2:
2538e1dc58eSRafal Jaworowski 	default:
2548e1dc58eSRafal Jaworowski 		return (((val & 0x8000) << 10) | ((val & 0x7fff) << 7));
2558e1dc58eSRafal Jaworowski 	}
2568e1dc58eSRafal Jaworowski }
2578e1dc58eSRafal Jaworowski 
2588e1dc58eSRafal Jaworowski static void
2598e1dc58eSRafal Jaworowski mge_ver_params(struct mge_softc *sc)
2608e1dc58eSRafal Jaworowski {
2618e1dc58eSRafal Jaworowski 	uint32_t d, r;
2628e1dc58eSRafal Jaworowski 
2638e1dc58eSRafal Jaworowski 	soc_id(&d, &r);
26475f1438bSOleksandr Tymoshenko 	if (d == MV_DEV_88F6281 || d == MV_DEV_88F6781 ||
265c8953e12SHiroki Sato 	    d == MV_DEV_88F6282 ||
266c8953e12SHiroki Sato 	    d == MV_DEV_MV78100 ||
26775f1438bSOleksandr Tymoshenko 	    d == MV_DEV_MV78100_Z0 ||
26875f1438bSOleksandr Tymoshenko 	    (d & MV_DEV_FAMILY_MASK) == MV_DEV_DISCOVERY) {
2698e1dc58eSRafal Jaworowski 		sc->mge_ver = 2;
2708e1dc58eSRafal Jaworowski 		sc->mge_mtu = 0x4e8;
2718e1dc58eSRafal Jaworowski 		sc->mge_tfut_ipg_max = 0xFFFF;
2728e1dc58eSRafal Jaworowski 		sc->mge_rx_ipg_max = 0xFFFF;
2738e1dc58eSRafal Jaworowski 		sc->mge_tx_arb_cfg = 0xFC0000FF;
2748e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cfg = 0xFFFF7FFF;
2758e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cnt = 0x3FFFFFFF;
2768e1dc58eSRafal Jaworowski 	} else {
2778e1dc58eSRafal Jaworowski 		sc->mge_ver = 1;
2788e1dc58eSRafal Jaworowski 		sc->mge_mtu = 0x458;
2798e1dc58eSRafal Jaworowski 		sc->mge_tfut_ipg_max = 0x3FFF;
2808e1dc58eSRafal Jaworowski 		sc->mge_rx_ipg_max = 0x3FFF;
2818e1dc58eSRafal Jaworowski 		sc->mge_tx_arb_cfg = 0x000000FF;
2828e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cfg = 0x3FFFFFFF;
2838e1dc58eSRafal Jaworowski 		sc->mge_tx_tok_cnt = 0x3FFFFFFF;
2848e1dc58eSRafal Jaworowski 	}
28575f1438bSOleksandr Tymoshenko 	if (d == MV_DEV_88RC8180)
28675f1438bSOleksandr Tymoshenko 		sc->mge_intr_cnt = 1;
28775f1438bSOleksandr Tymoshenko 	else
28875f1438bSOleksandr Tymoshenko 		sc->mge_intr_cnt = 2;
28975f1438bSOleksandr Tymoshenko 
29075f1438bSOleksandr Tymoshenko 	if (d == MV_DEV_MV78160 || d == MV_DEV_MV78260 || d == MV_DEV_MV78460)
29175f1438bSOleksandr Tymoshenko 		sc->mge_hw_csum = 0;
29275f1438bSOleksandr Tymoshenko 	else
29375f1438bSOleksandr Tymoshenko 		sc->mge_hw_csum = 1;
2948e1dc58eSRafal Jaworowski }
2958e1dc58eSRafal Jaworowski 
2969f55f5f5SRafal Jaworowski static void
2979f55f5f5SRafal Jaworowski mge_set_mac_address(struct mge_softc *sc)
2989f55f5f5SRafal Jaworowski {
2999f55f5f5SRafal Jaworowski 	char *if_mac;
3009f55f5f5SRafal Jaworowski 	uint32_t mac_l, mac_h;
3019f55f5f5SRafal Jaworowski 
3029f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK_ASSERT(sc);
3039f55f5f5SRafal Jaworowski 
3049f55f5f5SRafal Jaworowski 	if_mac = (char *)IF_LLADDR(sc->ifp);
3059f55f5f5SRafal Jaworowski 
3069f55f5f5SRafal Jaworowski 	mac_l = (if_mac[4] << 8) | (if_mac[5]);
3079f55f5f5SRafal Jaworowski 	mac_h = (if_mac[0] << 24)| (if_mac[1] << 16) |
3089f55f5f5SRafal Jaworowski 	    (if_mac[2] << 8) | (if_mac[3] << 0);
3099f55f5f5SRafal Jaworowski 
3109f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_MAC_ADDR_L, mac_l);
3119f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_MAC_ADDR_H, mac_h);
3129f55f5f5SRafal Jaworowski 
3139f55f5f5SRafal Jaworowski 	mge_set_ucast_address(sc, if_mac[5], MGE_RX_DEFAULT_QUEUE);
3149f55f5f5SRafal Jaworowski }
3159f55f5f5SRafal Jaworowski 
3169f55f5f5SRafal Jaworowski static void
3179f55f5f5SRafal Jaworowski mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte, uint8_t queue)
3189f55f5f5SRafal Jaworowski {
3199f55f5f5SRafal Jaworowski 	uint32_t reg_idx, reg_off, reg_val, i;
3209f55f5f5SRafal Jaworowski 
3219f55f5f5SRafal Jaworowski 	last_byte &= 0xf;
3229f55f5f5SRafal Jaworowski 	reg_idx = last_byte / MGE_UCAST_REG_NUMBER;
3239f55f5f5SRafal Jaworowski 	reg_off = (last_byte % MGE_UCAST_REG_NUMBER) * 8;
3249f55f5f5SRafal Jaworowski 	reg_val = (1 | (queue << 1)) << reg_off;
3259f55f5f5SRafal Jaworowski 
3269f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_UCAST_REG_NUMBER; i++) {
3279f55f5f5SRafal Jaworowski 		if ( i == reg_idx)
3289f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val);
3299f55f5f5SRafal Jaworowski 		else
3309f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), 0);
3319f55f5f5SRafal Jaworowski 	}
3329f55f5f5SRafal Jaworowski }
3339f55f5f5SRafal Jaworowski 
3349f55f5f5SRafal Jaworowski static void
3359f55f5f5SRafal Jaworowski mge_set_prom_mode(struct mge_softc *sc, uint8_t queue)
3369f55f5f5SRafal Jaworowski {
3379f55f5f5SRafal Jaworowski 	uint32_t port_config;
3389f55f5f5SRafal Jaworowski 	uint32_t reg_val, i;
3399f55f5f5SRafal Jaworowski 
3409f55f5f5SRafal Jaworowski 	/* Enable or disable promiscuous mode as needed */
3419f55f5f5SRafal Jaworowski 	if (sc->ifp->if_flags & IFF_PROMISC) {
3429f55f5f5SRafal Jaworowski 		port_config = MGE_READ(sc, MGE_PORT_CONFIG);
3439f55f5f5SRafal Jaworowski 		port_config |= PORT_CONFIG_UPM;
3449f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_CONFIG, port_config);
3459f55f5f5SRafal Jaworowski 
3469f55f5f5SRafal Jaworowski 		reg_val = ((1 | (queue << 1)) | (1 | (queue << 1)) << 8 |
3479f55f5f5SRafal Jaworowski 		   (1 | (queue << 1)) << 16 | (1 | (queue << 1)) << 24);
3489f55f5f5SRafal Jaworowski 
3499f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
3509f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), reg_val);
3519f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), reg_val);
3529f55f5f5SRafal Jaworowski 		}
3539f55f5f5SRafal Jaworowski 
3549f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_UCAST_REG_NUMBER; i++)
3559f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val);
3569f55f5f5SRafal Jaworowski 
3579f55f5f5SRafal Jaworowski 	} else {
3589f55f5f5SRafal Jaworowski 		port_config = MGE_READ(sc, MGE_PORT_CONFIG);
3599f55f5f5SRafal Jaworowski 		port_config &= ~PORT_CONFIG_UPM;
3609f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_CONFIG, port_config);
3619f55f5f5SRafal Jaworowski 
3629f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
3639f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), 0);
3649f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), 0);
3659f55f5f5SRafal Jaworowski 		}
3669f55f5f5SRafal Jaworowski 
3679f55f5f5SRafal Jaworowski 		mge_set_mac_address(sc);
3689f55f5f5SRafal Jaworowski 	}
3699f55f5f5SRafal Jaworowski }
3709f55f5f5SRafal Jaworowski 
3719f55f5f5SRafal Jaworowski static void
3729f55f5f5SRafal Jaworowski mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
3739f55f5f5SRafal Jaworowski {
3749f55f5f5SRafal Jaworowski 	u_int32_t *paddr;
3759f55f5f5SRafal Jaworowski 
3769f55f5f5SRafal Jaworowski 	KASSERT(nseg == 1, ("wrong number of segments, should be 1"));
3779f55f5f5SRafal Jaworowski 	paddr = arg;
3789f55f5f5SRafal Jaworowski 
3799f55f5f5SRafal Jaworowski 	*paddr = segs->ds_addr;
3809f55f5f5SRafal Jaworowski }
3819f55f5f5SRafal Jaworowski 
3829f55f5f5SRafal Jaworowski static int
3839f55f5f5SRafal Jaworowski mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf **mbufp,
3849f55f5f5SRafal Jaworowski     bus_addr_t *paddr)
3859f55f5f5SRafal Jaworowski {
3869f55f5f5SRafal Jaworowski 	struct mbuf *new_mbuf;
3879f55f5f5SRafal Jaworowski 	bus_dma_segment_t seg[1];
3889f55f5f5SRafal Jaworowski 	int error;
3899f55f5f5SRafal Jaworowski 	int nsegs;
3909f55f5f5SRafal Jaworowski 
3919f55f5f5SRafal Jaworowski 	KASSERT(mbufp != NULL, ("NULL mbuf pointer!"));
3929f55f5f5SRafal Jaworowski 
393c6499eccSGleb Smirnoff 	new_mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
3949f55f5f5SRafal Jaworowski 	if (new_mbuf == NULL)
3959f55f5f5SRafal Jaworowski 		return (ENOBUFS);
3969f55f5f5SRafal Jaworowski 	new_mbuf->m_len = new_mbuf->m_pkthdr.len = new_mbuf->m_ext.ext_size;
3979f55f5f5SRafal Jaworowski 
3989f55f5f5SRafal Jaworowski 	if (*mbufp) {
3999f55f5f5SRafal Jaworowski 		bus_dmamap_sync(tag, map, BUS_DMASYNC_POSTREAD);
4009f55f5f5SRafal Jaworowski 		bus_dmamap_unload(tag, map);
4019f55f5f5SRafal Jaworowski 	}
4029f55f5f5SRafal Jaworowski 
4039f55f5f5SRafal Jaworowski 	error = bus_dmamap_load_mbuf_sg(tag, map, new_mbuf, seg, &nsegs,
4049f55f5f5SRafal Jaworowski 	    BUS_DMA_NOWAIT);
4059f55f5f5SRafal Jaworowski 	KASSERT(nsegs == 1, ("Too many segments returned!"));
4069f55f5f5SRafal Jaworowski 	if (nsegs != 1 || error)
4079f55f5f5SRafal Jaworowski 		panic("mge_new_rxbuf(): nsegs(%d), error(%d)", nsegs, error);
4089f55f5f5SRafal Jaworowski 
4099f55f5f5SRafal Jaworowski 	bus_dmamap_sync(tag, map, BUS_DMASYNC_PREREAD);
4109f55f5f5SRafal Jaworowski 
4119f55f5f5SRafal Jaworowski 	(*mbufp) = new_mbuf;
4129f55f5f5SRafal Jaworowski 	(*paddr) = seg->ds_addr;
4139f55f5f5SRafal Jaworowski 	return (0);
4149f55f5f5SRafal Jaworowski }
4159f55f5f5SRafal Jaworowski 
4169f55f5f5SRafal Jaworowski static int
4179f55f5f5SRafal Jaworowski mge_alloc_desc_dma(struct mge_softc *sc, struct mge_desc_wrapper* tab,
4189f55f5f5SRafal Jaworowski     uint32_t size, bus_dma_tag_t *buffer_tag)
4199f55f5f5SRafal Jaworowski {
4209f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
4219f55f5f5SRafal Jaworowski 	bus_addr_t desc_paddr;
4229f55f5f5SRafal Jaworowski 	int i, error;
4239f55f5f5SRafal Jaworowski 
4249f55f5f5SRafal Jaworowski 	desc_paddr = 0;
4259f55f5f5SRafal Jaworowski 	for (i = size - 1; i >= 0; i--) {
4269f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
4279f55f5f5SRafal Jaworowski 		error = bus_dmamem_alloc(sc->mge_desc_dtag,
4289f55f5f5SRafal Jaworowski 		    (void**)&(dw->mge_desc),
4299f55f5f5SRafal Jaworowski 		    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
4309f55f5f5SRafal Jaworowski 		    &(dw->desc_dmap));
4319f55f5f5SRafal Jaworowski 
4329f55f5f5SRafal Jaworowski 		if (error) {
4339f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "failed to allocate DMA memory\n");
4349f55f5f5SRafal Jaworowski 			dw->mge_desc = NULL;
4359f55f5f5SRafal Jaworowski 			return (ENXIO);
4369f55f5f5SRafal Jaworowski 		}
4379f55f5f5SRafal Jaworowski 
4389f55f5f5SRafal Jaworowski 		error = bus_dmamap_load(sc->mge_desc_dtag, dw->desc_dmap,
4399f55f5f5SRafal Jaworowski 		    dw->mge_desc, sizeof(struct mge_desc), mge_get_dma_addr,
4409f55f5f5SRafal Jaworowski 		    &(dw->mge_desc_paddr), BUS_DMA_NOWAIT);
4419f55f5f5SRafal Jaworowski 
4429f55f5f5SRafal Jaworowski 		if (error) {
4439f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "can't load descriptor\n");
4449f55f5f5SRafal Jaworowski 			bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc,
4459f55f5f5SRafal Jaworowski 			    dw->desc_dmap);
4469f55f5f5SRafal Jaworowski 			dw->mge_desc = NULL;
4479f55f5f5SRafal Jaworowski 			return (ENXIO);
4489f55f5f5SRafal Jaworowski 		}
4499f55f5f5SRafal Jaworowski 
4509f55f5f5SRafal Jaworowski 		/* Chain descriptors */
4519f55f5f5SRafal Jaworowski 		dw->mge_desc->next_desc = desc_paddr;
4529f55f5f5SRafal Jaworowski 		desc_paddr = dw->mge_desc_paddr;
4539f55f5f5SRafal Jaworowski 	}
4549f55f5f5SRafal Jaworowski 	tab[size - 1].mge_desc->next_desc = desc_paddr;
4559f55f5f5SRafal Jaworowski 
4569f55f5f5SRafal Jaworowski 	/* Allocate a busdma tag for mbufs. */
45762ce43ccSScott Long 	error = bus_dma_tag_create(bus_get_dma_tag(sc->dev),	/* parent */
45875f1438bSOleksandr Tymoshenko 	    1, 0,				/* alignment, boundary */
4599f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
4609f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR,			/* highaddr */
4619f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* filtfunc, filtfuncarg */
4629f55f5f5SRafal Jaworowski 	    MCLBYTES, 1,			/* maxsize, nsegments */
4639f55f5f5SRafal Jaworowski 	    MCLBYTES, 0,			/* maxsegsz, flags */
4649f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* lockfunc, lockfuncarg */
4659f55f5f5SRafal Jaworowski 	    buffer_tag);			/* dmat */
4669f55f5f5SRafal Jaworowski 	if (error) {
4679f55f5f5SRafal Jaworowski 		if_printf(sc->ifp, "failed to create busdma tag for mbufs\n");
4689f55f5f5SRafal Jaworowski 		return (ENXIO);
4699f55f5f5SRafal Jaworowski 	}
4709f55f5f5SRafal Jaworowski 
4719f55f5f5SRafal Jaworowski 	/* Create TX busdma maps */
4729f55f5f5SRafal Jaworowski 	for (i = 0; i < size; i++) {
4739f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
4749f55f5f5SRafal Jaworowski 		error = bus_dmamap_create(*buffer_tag, 0, &dw->buffer_dmap);
4759f55f5f5SRafal Jaworowski 		if (error) {
4769f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "failed to create map for mbuf\n");
4779f55f5f5SRafal Jaworowski 			return (ENXIO);
4789f55f5f5SRafal Jaworowski 		}
4799f55f5f5SRafal Jaworowski 
4809f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
4819f55f5f5SRafal Jaworowski 		dw->mge_desc->buffer = (bus_addr_t)NULL;
4829f55f5f5SRafal Jaworowski 	}
4839f55f5f5SRafal Jaworowski 
4849f55f5f5SRafal Jaworowski 	return (0);
4859f55f5f5SRafal Jaworowski }
4869f55f5f5SRafal Jaworowski 
4879f55f5f5SRafal Jaworowski static int
4889f55f5f5SRafal Jaworowski mge_allocate_dma(struct mge_softc *sc)
4899f55f5f5SRafal Jaworowski {
4909f55f5f5SRafal Jaworowski 	int error;
4919f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
492d6bdd318SRafal Jaworowski 	int i;
4939f55f5f5SRafal Jaworowski 
4949f55f5f5SRafal Jaworowski 	/* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
49562ce43ccSScott Long 	error = bus_dma_tag_create(bus_get_dma_tag(sc->dev),	/* parent */
4969f55f5f5SRafal Jaworowski 	    16, 0,				/* alignment, boundary */
4979f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
4989f55f5f5SRafal Jaworowski 	    BUS_SPACE_MAXADDR,			/* highaddr */
4999f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* filtfunc, filtfuncarg */
5009f55f5f5SRafal Jaworowski 	    sizeof(struct mge_desc), 1,		/* maxsize, nsegments */
5019f55f5f5SRafal Jaworowski 	    sizeof(struct mge_desc), 0,		/* maxsegsz, flags */
5029f55f5f5SRafal Jaworowski 	    NULL, NULL,				/* lockfunc, lockfuncarg */
5039f55f5f5SRafal Jaworowski 	    &sc->mge_desc_dtag);		/* dmat */
5049f55f5f5SRafal Jaworowski 
5059f55f5f5SRafal Jaworowski 
5069f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM,
5079f55f5f5SRafal Jaworowski 	    &sc->mge_tx_dtag);
5089f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM,
5099f55f5f5SRafal Jaworowski 	    &sc->mge_rx_dtag);
5109f55f5f5SRafal Jaworowski 
5119f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
5129f55f5f5SRafal Jaworowski 		dw = &(sc->mge_rx_desc[i]);
5139f55f5f5SRafal Jaworowski 		mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer,
5149f55f5f5SRafal Jaworowski 		    &dw->mge_desc->buffer);
5159f55f5f5SRafal Jaworowski 	}
5169f55f5f5SRafal Jaworowski 
5179f55f5f5SRafal Jaworowski 	sc->tx_desc_start = sc->mge_tx_desc[0].mge_desc_paddr;
5189f55f5f5SRafal Jaworowski 	sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr;
5199f55f5f5SRafal Jaworowski 
5209f55f5f5SRafal Jaworowski 	return (0);
5219f55f5f5SRafal Jaworowski }
5229f55f5f5SRafal Jaworowski 
5239f55f5f5SRafal Jaworowski static void
5249f55f5f5SRafal Jaworowski mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab,
5259f55f5f5SRafal Jaworowski     uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs)
5269f55f5f5SRafal Jaworowski {
5279f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
5289f55f5f5SRafal Jaworowski 	int i;
5299f55f5f5SRafal Jaworowski 
5309f55f5f5SRafal Jaworowski 	for (i = 0; i < size; i++) {
5319f55f5f5SRafal Jaworowski 		/* Free RX mbuf */
5329f55f5f5SRafal Jaworowski 		dw = &(tab[i]);
5339f55f5f5SRafal Jaworowski 
5349f55f5f5SRafal Jaworowski 		if (dw->buffer_dmap) {
5359f55f5f5SRafal Jaworowski 			if (free_mbufs) {
5369f55f5f5SRafal Jaworowski 				bus_dmamap_sync(buffer_tag, dw->buffer_dmap,
5379f55f5f5SRafal Jaworowski 				    BUS_DMASYNC_POSTREAD);
5389f55f5f5SRafal Jaworowski 				bus_dmamap_unload(buffer_tag, dw->buffer_dmap);
5399f55f5f5SRafal Jaworowski 			}
5409f55f5f5SRafal Jaworowski 			bus_dmamap_destroy(buffer_tag, dw->buffer_dmap);
5419f55f5f5SRafal Jaworowski 			if (free_mbufs)
5429f55f5f5SRafal Jaworowski 				m_freem(dw->buffer);
5439f55f5f5SRafal Jaworowski 		}
5449f55f5f5SRafal Jaworowski 		/* Free RX descriptors */
5459f55f5f5SRafal Jaworowski 		if (dw->desc_dmap) {
5469f55f5f5SRafal Jaworowski 			bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
5479f55f5f5SRafal Jaworowski 			    BUS_DMASYNC_POSTREAD);
5489f55f5f5SRafal Jaworowski 			bus_dmamap_unload(sc->mge_desc_dtag, dw->desc_dmap);
5499f55f5f5SRafal Jaworowski 			bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc,
5509f55f5f5SRafal Jaworowski 			    dw->desc_dmap);
5519f55f5f5SRafal Jaworowski 		}
5529f55f5f5SRafal Jaworowski 	}
5539f55f5f5SRafal Jaworowski }
5549f55f5f5SRafal Jaworowski 
5559f55f5f5SRafal Jaworowski static void
5569f55f5f5SRafal Jaworowski mge_free_dma(struct mge_softc *sc)
5579f55f5f5SRafal Jaworowski {
5589f55f5f5SRafal Jaworowski 	/* Free desciptors and mbufs */
5599f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1);
5609f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM, sc->mge_tx_dtag, 0);
5619f55f5f5SRafal Jaworowski 
5629f55f5f5SRafal Jaworowski 	/* Destroy mbuf dma tag */
5639f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_tx_dtag);
5649f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_rx_dtag);
5659f55f5f5SRafal Jaworowski 	/* Destroy descriptors tag */
5669f55f5f5SRafal Jaworowski 	bus_dma_tag_destroy(sc->mge_desc_dtag);
5679f55f5f5SRafal Jaworowski }
5689f55f5f5SRafal Jaworowski 
5699f55f5f5SRafal Jaworowski static void
5709f55f5f5SRafal Jaworowski mge_reinit_rx(struct mge_softc *sc)
5719f55f5f5SRafal Jaworowski {
5729f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
5739f55f5f5SRafal Jaworowski 	int i;
5749f55f5f5SRafal Jaworowski 
575d6bdd318SRafal Jaworowski 	MGE_RECEIVE_LOCK_ASSERT(sc);
5769f55f5f5SRafal Jaworowski 
5779f55f5f5SRafal Jaworowski 	mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1);
5789f55f5f5SRafal Jaworowski 
5799f55f5f5SRafal Jaworowski 	mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM,
5809f55f5f5SRafal Jaworowski 	    &sc->mge_rx_dtag);
5819f55f5f5SRafal Jaworowski 
5829f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
5839f55f5f5SRafal Jaworowski 		dw = &(sc->mge_rx_desc[i]);
5849f55f5f5SRafal Jaworowski 		mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer,
5859f55f5f5SRafal Jaworowski 		&dw->mge_desc->buffer);
5869f55f5f5SRafal Jaworowski 	}
5879f55f5f5SRafal Jaworowski 
5889f55f5f5SRafal Jaworowski 	sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr;
5899f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
5909f55f5f5SRafal Jaworowski 
5919f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE),
5929f55f5f5SRafal Jaworowski 	    sc->rx_desc_start);
5939f55f5f5SRafal Jaworowski 
5949f55f5f5SRafal Jaworowski 	/* Enable RX queue */
5959f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE));
5969f55f5f5SRafal Jaworowski }
5979f55f5f5SRafal Jaworowski 
5989f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
5999f55f5f5SRafal Jaworowski static poll_handler_t mge_poll;
6009f55f5f5SRafal Jaworowski 
6011abcdbd1SAttilio Rao static int
6029f55f5f5SRafal Jaworowski mge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
6039f55f5f5SRafal Jaworowski {
6049f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
6059f55f5f5SRafal Jaworowski 	uint32_t int_cause, int_cause_ext;
6061abcdbd1SAttilio Rao 	int rx_npkts = 0;
6079f55f5f5SRafal Jaworowski 
6089f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
6099f55f5f5SRafal Jaworowski 
6109f55f5f5SRafal Jaworowski 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
6119f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
6121abcdbd1SAttilio Rao 		return (rx_npkts);
6139f55f5f5SRafal Jaworowski 	}
6149f55f5f5SRafal Jaworowski 
6159f55f5f5SRafal Jaworowski 	if (cmd == POLL_AND_CHECK_STATUS) {
6169f55f5f5SRafal Jaworowski 		int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
6179f55f5f5SRafal Jaworowski 		int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
6189f55f5f5SRafal Jaworowski 
6199f55f5f5SRafal Jaworowski 		/* Check for resource error */
6209f55f5f5SRafal Jaworowski 		if (int_cause & MGE_PORT_INT_RXERRQ0)
6219f55f5f5SRafal Jaworowski 			mge_reinit_rx(sc);
6229f55f5f5SRafal Jaworowski 
6239f55f5f5SRafal Jaworowski 		if (int_cause || int_cause_ext) {
6249f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause);
6259f55f5f5SRafal Jaworowski 			MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext);
6269f55f5f5SRafal Jaworowski 		}
6279f55f5f5SRafal Jaworowski 	}
6289f55f5f5SRafal Jaworowski 
6299f55f5f5SRafal Jaworowski 	mge_intr_tx_locked(sc);
6301abcdbd1SAttilio Rao 	rx_npkts = mge_intr_rx_locked(sc, count);
6319f55f5f5SRafal Jaworowski 
6329f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
6331abcdbd1SAttilio Rao 	return (rx_npkts);
6349f55f5f5SRafal Jaworowski }
6359f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */
6369f55f5f5SRafal Jaworowski 
6379f55f5f5SRafal Jaworowski static int
6389f55f5f5SRafal Jaworowski mge_attach(device_t dev)
6399f55f5f5SRafal Jaworowski {
6409f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
641a6eb469dSPhilip Paeps 	struct mii_softc *miisc;
6429f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
6439f55f5f5SRafal Jaworowski 	uint8_t hwaddr[ETHER_ADDR_LEN];
6448e5d93dbSMarius Strobl 	int i, error, phy;
6459f55f5f5SRafal Jaworowski 
6469f55f5f5SRafal Jaworowski 	sc = device_get_softc(dev);
6479f55f5f5SRafal Jaworowski 	sc->dev = dev;
648db5ef4fcSRafal Jaworowski 	sc->node = ofw_bus_get_node(dev);
6499f55f5f5SRafal Jaworowski 
6508e1dc58eSRafal Jaworowski 	/* Set chip version-dependent parameters */
6518e1dc58eSRafal Jaworowski 	mge_ver_params(sc);
6528e1dc58eSRafal Jaworowski 
653aa15e881SRafal Jaworowski 	/* Get phy address and used softc from fdt */
654aa15e881SRafal Jaworowski 	if (fdt_get_phyaddr(sc->node, sc->dev, &phy, (void **)&sc->phy_sc) != 0)
655db5ef4fcSRafal Jaworowski 		return (ENXIO);
656db5ef4fcSRafal Jaworowski 
6579f55f5f5SRafal Jaworowski 	/* Initialize mutexes */
6589f55f5f5SRafal Jaworowski 	mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "mge TX lock", MTX_DEF);
6599f55f5f5SRafal Jaworowski 	mtx_init(&sc->receive_lock, device_get_nameunit(dev), "mge RX lock", MTX_DEF);
6609f55f5f5SRafal Jaworowski 
6619f55f5f5SRafal Jaworowski 	/* Allocate IO and IRQ resources */
6629f55f5f5SRafal Jaworowski 	error = bus_alloc_resources(dev, res_spec, sc->res);
6639f55f5f5SRafal Jaworowski 	if (error) {
6649f55f5f5SRafal Jaworowski 		device_printf(dev, "could not allocate resources\n");
6659f55f5f5SRafal Jaworowski 		mge_detach(dev);
6669f55f5f5SRafal Jaworowski 		return (ENXIO);
6679f55f5f5SRafal Jaworowski 	}
6689f55f5f5SRafal Jaworowski 
6699f55f5f5SRafal Jaworowski 	/* Allocate DMA, buffers, buffer descriptors */
6709f55f5f5SRafal Jaworowski 	error = mge_allocate_dma(sc);
6719f55f5f5SRafal Jaworowski 	if (error) {
6729f55f5f5SRafal Jaworowski 		mge_detach(dev);
6739f55f5f5SRafal Jaworowski 		return (ENXIO);
6749f55f5f5SRafal Jaworowski 	}
6759f55f5f5SRafal Jaworowski 
6769f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = 0;
6779f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
6789f55f5f5SRafal Jaworowski 	sc->tx_desc_used_idx = 0;
6795817716fSRafal Jaworowski 	sc->tx_desc_used_count = 0;
6809f55f5f5SRafal Jaworowski 
6819f55f5f5SRafal Jaworowski 	/* Configure defaults for interrupts coalescing */
6829f55f5f5SRafal Jaworowski 	sc->rx_ic_time = 768;
6839f55f5f5SRafal Jaworowski 	sc->tx_ic_time = 768;
6849f55f5f5SRafal Jaworowski 	mge_add_sysctls(sc);
6859f55f5f5SRafal Jaworowski 
6869f55f5f5SRafal Jaworowski 	/* Allocate network interface */
6879f55f5f5SRafal Jaworowski 	ifp = sc->ifp = if_alloc(IFT_ETHER);
6889f55f5f5SRafal Jaworowski 	if (ifp == NULL) {
6899f55f5f5SRafal Jaworowski 		device_printf(dev, "if_alloc() failed\n");
6909f55f5f5SRafal Jaworowski 		mge_detach(dev);
6919f55f5f5SRafal Jaworowski 		return (ENOMEM);
6929f55f5f5SRafal Jaworowski 	}
6939f55f5f5SRafal Jaworowski 
6949f55f5f5SRafal Jaworowski 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
6959f55f5f5SRafal Jaworowski 	ifp->if_softc = sc;
6969f55f5f5SRafal Jaworowski 	ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST;
69775f1438bSOleksandr Tymoshenko 	ifp->if_capabilities = IFCAP_VLAN_MTU;
69875f1438bSOleksandr Tymoshenko 	if (sc->mge_hw_csum) {
69975f1438bSOleksandr Tymoshenko 		ifp->if_capabilities |= IFCAP_HWCSUM;
7009f55f5f5SRafal Jaworowski 		ifp->if_hwassist = MGE_CHECKSUM_FEATURES;
70175f1438bSOleksandr Tymoshenko 	}
70275f1438bSOleksandr Tymoshenko 	ifp->if_capenable = ifp->if_capabilities;
7039f55f5f5SRafal Jaworowski 
7049f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
7059f55f5f5SRafal Jaworowski 	/* Advertise that polling is supported */
7069f55f5f5SRafal Jaworowski 	ifp->if_capabilities |= IFCAP_POLLING;
7079f55f5f5SRafal Jaworowski #endif
7089f55f5f5SRafal Jaworowski 
7099f55f5f5SRafal Jaworowski 	ifp->if_init = mge_init;
7109f55f5f5SRafal Jaworowski 	ifp->if_start = mge_start;
7119f55f5f5SRafal Jaworowski 	ifp->if_ioctl = mge_ioctl;
7129f55f5f5SRafal Jaworowski 
7139f55f5f5SRafal Jaworowski 	ifp->if_snd.ifq_drv_maxlen = MGE_TX_DESC_NUM - 1;
7149f55f5f5SRafal Jaworowski 	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
7159f55f5f5SRafal Jaworowski 	IFQ_SET_READY(&ifp->if_snd);
7169f55f5f5SRafal Jaworowski 
7179f55f5f5SRafal Jaworowski 	mge_get_mac_address(sc, hwaddr);
7189f55f5f5SRafal Jaworowski 	ether_ifattach(ifp, hwaddr);
7199f55f5f5SRafal Jaworowski 	callout_init(&sc->wd_callout, 0);
7209f55f5f5SRafal Jaworowski 
7218e5d93dbSMarius Strobl 	/* Attach PHY(s) */
7228e5d93dbSMarius Strobl 	error = mii_attach(dev, &sc->miibus, ifp, mge_ifmedia_upd,
7238e5d93dbSMarius Strobl 	    mge_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
7249f55f5f5SRafal Jaworowski 	if (error) {
7258e5d93dbSMarius Strobl 		device_printf(dev, "attaching PHYs failed\n");
7269f55f5f5SRafal Jaworowski 		mge_detach(dev);
7279f55f5f5SRafal Jaworowski 		return (error);
7289f55f5f5SRafal Jaworowski 	}
7299f55f5f5SRafal Jaworowski 	sc->mii = device_get_softc(sc->miibus);
7309f55f5f5SRafal Jaworowski 
731a6eb469dSPhilip Paeps 	/* Tell the MAC where to find the PHY so autoneg works */
732a6eb469dSPhilip Paeps 	miisc = LIST_FIRST(&sc->mii->mii_phys);
733a6eb469dSPhilip Paeps 	MGE_WRITE(sc, MGE_REG_PHYDEV, miisc->mii_phy);
734a6eb469dSPhilip Paeps 
7359f55f5f5SRafal Jaworowski 	/* Attach interrupt handlers */
73675f1438bSOleksandr Tymoshenko 	/* TODO: review flags, in part. mark RX as INTR_ENTROPY ? */
73775f1438bSOleksandr Tymoshenko 	for (i = 1; i <= sc->mge_intr_cnt; ++i) {
73875f1438bSOleksandr Tymoshenko 		error = bus_setup_intr(dev, sc->res[i],
73975f1438bSOleksandr Tymoshenko 		    INTR_TYPE_NET | INTR_MPSAFE,
74075f1438bSOleksandr Tymoshenko 		    NULL, *mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].handler,
74175f1438bSOleksandr Tymoshenko 		    sc, &sc->ih_cookie[i - 1]);
7429f55f5f5SRafal Jaworowski 		if (error) {
7439f55f5f5SRafal Jaworowski 			device_printf(dev, "could not setup %s\n",
74475f1438bSOleksandr Tymoshenko 			    mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].description);
745a6eb469dSPhilip Paeps 			mge_detach(dev);
7469f55f5f5SRafal Jaworowski 			return (error);
7479f55f5f5SRafal Jaworowski 		}
7489f55f5f5SRafal Jaworowski 	}
7499f55f5f5SRafal Jaworowski 
7509f55f5f5SRafal Jaworowski 	return (0);
7519f55f5f5SRafal Jaworowski }
7529f55f5f5SRafal Jaworowski 
7539f55f5f5SRafal Jaworowski static int
7549f55f5f5SRafal Jaworowski mge_detach(device_t dev)
7559f55f5f5SRafal Jaworowski {
7569f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
7579f55f5f5SRafal Jaworowski 	int error,i;
7589f55f5f5SRafal Jaworowski 
7599f55f5f5SRafal Jaworowski 	sc = device_get_softc(dev);
7609f55f5f5SRafal Jaworowski 
7619f55f5f5SRafal Jaworowski 	/* Stop controller and free TX queue */
7629f55f5f5SRafal Jaworowski 	if (sc->ifp)
7639f55f5f5SRafal Jaworowski 		mge_shutdown(dev);
7649f55f5f5SRafal Jaworowski 
7659f55f5f5SRafal Jaworowski 	/* Wait for stopping ticks */
7669f55f5f5SRafal Jaworowski         callout_drain(&sc->wd_callout);
7679f55f5f5SRafal Jaworowski 
7689f55f5f5SRafal Jaworowski 	/* Stop and release all interrupts */
76975f1438bSOleksandr Tymoshenko 	for (i = 0; i < sc->mge_intr_cnt; ++i) {
770a6eb469dSPhilip Paeps 		if (!sc->ih_cookie[i])
771a6eb469dSPhilip Paeps 			continue;
772a6eb469dSPhilip Paeps 
7739f55f5f5SRafal Jaworowski 		error = bus_teardown_intr(dev, sc->res[1 + i], sc->ih_cookie[i]);
7749f55f5f5SRafal Jaworowski 		if (error)
7759f55f5f5SRafal Jaworowski 			device_printf(dev, "could not release %s\n",
77675f1438bSOleksandr Tymoshenko 			    mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i + 1)].description);
7779f55f5f5SRafal Jaworowski 	}
7789f55f5f5SRafal Jaworowski 
7799f55f5f5SRafal Jaworowski 	/* Detach network interface */
7809f55f5f5SRafal Jaworowski 	if (sc->ifp) {
7819f55f5f5SRafal Jaworowski 		ether_ifdetach(sc->ifp);
7829f55f5f5SRafal Jaworowski 		if_free(sc->ifp);
7839f55f5f5SRafal Jaworowski 	}
7849f55f5f5SRafal Jaworowski 
7859f55f5f5SRafal Jaworowski 	/* Free DMA resources */
7869f55f5f5SRafal Jaworowski 	mge_free_dma(sc);
7879f55f5f5SRafal Jaworowski 
7889f55f5f5SRafal Jaworowski 	/* Free IO memory handler */
7899f55f5f5SRafal Jaworowski 	bus_release_resources(dev, res_spec, sc->res);
7909f55f5f5SRafal Jaworowski 
7919f55f5f5SRafal Jaworowski 	/* Destroy mutexes */
7929f55f5f5SRafal Jaworowski 	mtx_destroy(&sc->receive_lock);
7939f55f5f5SRafal Jaworowski 	mtx_destroy(&sc->transmit_lock);
7949f55f5f5SRafal Jaworowski 
7959f55f5f5SRafal Jaworowski 	return (0);
7969f55f5f5SRafal Jaworowski }
7979f55f5f5SRafal Jaworowski 
7989f55f5f5SRafal Jaworowski static void
7999f55f5f5SRafal Jaworowski mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
8009f55f5f5SRafal Jaworowski {
8019f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
8029f55f5f5SRafal Jaworowski 	struct mii_data *mii;
8039f55f5f5SRafal Jaworowski 
8049f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK(sc);
8059f55f5f5SRafal Jaworowski 
8069f55f5f5SRafal Jaworowski 	mii = sc->mii;
8079f55f5f5SRafal Jaworowski 	mii_pollstat(mii);
8089f55f5f5SRafal Jaworowski 
8099f55f5f5SRafal Jaworowski 	ifmr->ifm_active = mii->mii_media_active;
8109f55f5f5SRafal Jaworowski 	ifmr->ifm_status = mii->mii_media_status;
8119f55f5f5SRafal Jaworowski 
8129f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_UNLOCK(sc);
8139f55f5f5SRafal Jaworowski }
8149f55f5f5SRafal Jaworowski 
8159f55f5f5SRafal Jaworowski static uint32_t
8169f55f5f5SRafal Jaworowski mge_set_port_serial_control(uint32_t media)
8179f55f5f5SRafal Jaworowski {
8189f55f5f5SRafal Jaworowski 	uint32_t port_config;
8199f55f5f5SRafal Jaworowski 
8209f55f5f5SRafal Jaworowski 	port_config = PORT_SERIAL_RES_BIT9 | PORT_SERIAL_FORCE_LINK_FAIL |
8219f55f5f5SRafal Jaworowski 	    PORT_SERIAL_MRU(PORT_SERIAL_MRU_1552);
8229f55f5f5SRafal Jaworowski 
8239f55f5f5SRafal Jaworowski 	if (IFM_TYPE(media) == IFM_ETHER) {
8249f55f5f5SRafal Jaworowski 		switch(IFM_SUBTYPE(media)) {
8259f55f5f5SRafal Jaworowski 			case IFM_AUTO:
8269f55f5f5SRafal Jaworowski 				break;
8279f55f5f5SRafal Jaworowski 			case IFM_1000_T:
8289f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_GMII_SPEED_1000 |
8299f55f5f5SRafal Jaworowski 				    PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC |
8309f55f5f5SRafal Jaworowski 				    PORT_SERIAL_SPEED_AUTONEG);
8319f55f5f5SRafal Jaworowski 				break;
8329f55f5f5SRafal Jaworowski 			case IFM_100_TX:
8339f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_MII_SPEED_100 |
8349f55f5f5SRafal Jaworowski 				    PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC |
8359f55f5f5SRafal Jaworowski 				    PORT_SERIAL_SPEED_AUTONEG);
8369f55f5f5SRafal Jaworowski 				break;
8379f55f5f5SRafal Jaworowski 			case IFM_10_T:
8389f55f5f5SRafal Jaworowski 				port_config  |= (PORT_SERIAL_AUTONEG |
8399f55f5f5SRafal Jaworowski 				    PORT_SERIAL_AUTONEG_FC |
8409f55f5f5SRafal Jaworowski 				    PORT_SERIAL_SPEED_AUTONEG);
8419f55f5f5SRafal Jaworowski 				break;
8429f55f5f5SRafal Jaworowski 		}
8439f55f5f5SRafal Jaworowski 		if (media & IFM_FDX)
8449f55f5f5SRafal Jaworowski 			port_config |= PORT_SERIAL_FULL_DUPLEX;
8459f55f5f5SRafal Jaworowski 	}
8469f55f5f5SRafal Jaworowski 	return (port_config);
8479f55f5f5SRafal Jaworowski }
8489f55f5f5SRafal Jaworowski 
8499f55f5f5SRafal Jaworowski static int
8509f55f5f5SRafal Jaworowski mge_ifmedia_upd(struct ifnet *ifp)
8519f55f5f5SRafal Jaworowski {
8529f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
8539f55f5f5SRafal Jaworowski 
8549f55f5f5SRafal Jaworowski 	if (ifp->if_flags & IFF_UP) {
8559f55f5f5SRafal Jaworowski 		MGE_GLOBAL_LOCK(sc);
8569f55f5f5SRafal Jaworowski 
8579f55f5f5SRafal Jaworowski 		sc->mge_media_status = sc->mii->mii_media.ifm_media;
8589f55f5f5SRafal Jaworowski 		mii_mediachg(sc->mii);
8599f55f5f5SRafal Jaworowski 		mge_init_locked(sc);
8609f55f5f5SRafal Jaworowski 
8619f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
8629f55f5f5SRafal Jaworowski 	}
8639f55f5f5SRafal Jaworowski 
8649f55f5f5SRafal Jaworowski 	return (0);
8659f55f5f5SRafal Jaworowski }
8669f55f5f5SRafal Jaworowski 
8679f55f5f5SRafal Jaworowski static void
8689f55f5f5SRafal Jaworowski mge_init(void *arg)
8699f55f5f5SRafal Jaworowski {
8709f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
8719f55f5f5SRafal Jaworowski 
8729f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
8739f55f5f5SRafal Jaworowski 
8749f55f5f5SRafal Jaworowski 	mge_init_locked(arg);
8759f55f5f5SRafal Jaworowski 
8769f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
8779f55f5f5SRafal Jaworowski }
8789f55f5f5SRafal Jaworowski 
8799f55f5f5SRafal Jaworowski static void
8809f55f5f5SRafal Jaworowski mge_init_locked(void *arg)
8819f55f5f5SRafal Jaworowski {
8829f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
8839f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
8849f55f5f5SRafal Jaworowski 	volatile uint32_t reg_val;
8859f55f5f5SRafal Jaworowski 	int i, count;
8869f55f5f5SRafal Jaworowski 
8879f55f5f5SRafal Jaworowski 
8889f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK_ASSERT(sc);
8899f55f5f5SRafal Jaworowski 
8909f55f5f5SRafal Jaworowski 	/* Stop interface */
8919f55f5f5SRafal Jaworowski 	mge_stop(sc);
8929f55f5f5SRafal Jaworowski 
8939f55f5f5SRafal Jaworowski 	/* Disable interrupts */
8949f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 0);
8959f55f5f5SRafal Jaworowski 
8969f55f5f5SRafal Jaworowski 	/* Set MAC address */
8979f55f5f5SRafal Jaworowski 	mge_set_mac_address(sc);
8989f55f5f5SRafal Jaworowski 
8999f55f5f5SRafal Jaworowski 	/* Setup multicast filters */
9009f55f5f5SRafal Jaworowski 	mge_setup_multicast(sc);
9019f55f5f5SRafal Jaworowski 
9028e1dc58eSRafal Jaworowski 	if (sc->mge_ver == 2) {
9039f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL1, MGE_RGMII_EN);
9049f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_FIXED_PRIO_CONF, MGE_FIXED_PRIO_EN(0));
9058e1dc58eSRafal Jaworowski 	}
9069f55f5f5SRafal Jaworowski 
9078e1dc58eSRafal Jaworowski 	/* Initialize TX queue configuration registers */
9088e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(0), sc->mge_tx_tok_cnt);
9098e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_TOKEN_CONF(0), sc->mge_tx_tok_cfg);
9108e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_ARBITER_CONF(0), sc->mge_tx_arb_cfg);
9118e1dc58eSRafal Jaworowski 
9128e1dc58eSRafal Jaworowski 	/* Clear TX queue configuration registers for unused queues */
9139f55f5f5SRafal Jaworowski 	for (i = 1; i < 7; i++) {
9148e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(i), 0);
9158e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_TOKEN_CONF(i), 0);
9168e1dc58eSRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_ARBITER_CONF(i), 0);
9179f55f5f5SRafal Jaworowski 	}
9189f55f5f5SRafal Jaworowski 
9199f55f5f5SRafal Jaworowski 	/* Set default MTU */
9208e1dc58eSRafal Jaworowski 	MGE_WRITE(sc, sc->mge_mtu, 0);
9219f55f5f5SRafal Jaworowski 
9229f55f5f5SRafal Jaworowski 	/* Port configuration */
9239f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_CONFIG,
9249f55f5f5SRafal Jaworowski 	    PORT_CONFIG_RXCS | PORT_CONFIG_DFLT_RXQ(0) |
9259f55f5f5SRafal Jaworowski 	    PORT_CONFIG_ARO_RXQ(0));
9269f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_EXT_CONFIG , 0x0);
9279f55f5f5SRafal Jaworowski 
9289f55f5f5SRafal Jaworowski 	/* Setup port configuration */
9299f55f5f5SRafal Jaworowski 	reg_val = mge_set_port_serial_control(sc->mge_media_status);
9309f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
9319f55f5f5SRafal Jaworowski 
9329f55f5f5SRafal Jaworowski 	/* Setup SDMA configuration */
9339f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_SDMA_CONFIG , MGE_SDMA_RX_BYTE_SWAP |
9349f55f5f5SRafal Jaworowski 	    MGE_SDMA_TX_BYTE_SWAP |
9359f55f5f5SRafal Jaworowski 	    MGE_SDMA_RX_BURST_SIZE(MGE_SDMA_BURST_16_WORD) |
9369f55f5f5SRafal Jaworowski 	    MGE_SDMA_TX_BURST_SIZE(MGE_SDMA_BURST_16_WORD));
9379f55f5f5SRafal Jaworowski 
9389f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, 0x0);
9399f55f5f5SRafal Jaworowski 
9409f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_CUR_DESC_PTR, sc->tx_desc_start);
9419f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE),
9429f55f5f5SRafal Jaworowski 	    sc->rx_desc_start);
9439f55f5f5SRafal Jaworowski 
9449f55f5f5SRafal Jaworowski 	/* Reset descriptor indexes */
9459f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = 0;
9469f55f5f5SRafal Jaworowski 	sc->rx_desc_curr = 0;
9479f55f5f5SRafal Jaworowski 	sc->tx_desc_used_idx = 0;
9485817716fSRafal Jaworowski 	sc->tx_desc_used_count = 0;
9499f55f5f5SRafal Jaworowski 
9509f55f5f5SRafal Jaworowski 	/* Enable RX descriptors */
9519f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
9529f55f5f5SRafal Jaworowski 		dw = &sc->mge_rx_desc[i];
9539f55f5f5SRafal Jaworowski 		dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
9549f55f5f5SRafal Jaworowski 		dw->mge_desc->buff_size = MCLBYTES;
9559f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
9569f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
9579f55f5f5SRafal Jaworowski 	}
9589f55f5f5SRafal Jaworowski 
9599f55f5f5SRafal Jaworowski 	/* Enable RX queue */
9609f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE));
9619f55f5f5SRafal Jaworowski 
9629f55f5f5SRafal Jaworowski 	/* Enable port */
9639f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL);
9649f55f5f5SRafal Jaworowski 	reg_val |= PORT_SERIAL_ENABLE;
9659f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
9669f55f5f5SRafal Jaworowski 	count = 0x100000;
9679f55f5f5SRafal Jaworowski 	for (;;) {
9689f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_PORT_STATUS);
9699f55f5f5SRafal Jaworowski 		if (reg_val & MGE_STATUS_LINKUP)
9709f55f5f5SRafal Jaworowski 			break;
9719f55f5f5SRafal Jaworowski 		DELAY(100);
9729f55f5f5SRafal Jaworowski 		if (--count == 0) {
9739f55f5f5SRafal Jaworowski 			if_printf(sc->ifp, "Timeout on link-up\n");
9749f55f5f5SRafal Jaworowski 			break;
9759f55f5f5SRafal Jaworowski 		}
9769f55f5f5SRafal Jaworowski 	}
9779f55f5f5SRafal Jaworowski 
9789f55f5f5SRafal Jaworowski 	/* Setup interrupts coalescing */
9799f55f5f5SRafal Jaworowski 	mge_set_rxic(sc);
9809f55f5f5SRafal Jaworowski 	mge_set_txic(sc);
9819f55f5f5SRafal Jaworowski 
9829f55f5f5SRafal Jaworowski 	/* Enable interrupts */
9839f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
9849f55f5f5SRafal Jaworowski         /*
9859f55f5f5SRafal Jaworowski 	 * * ...only if polling is not turned on. Disable interrupts explicitly
9869f55f5f5SRafal Jaworowski 	 * if polling is enabled.
9879f55f5f5SRafal Jaworowski 	 */
9889f55f5f5SRafal Jaworowski 	if (sc->ifp->if_capenable & IFCAP_POLLING)
9899f55f5f5SRafal Jaworowski 		mge_intrs_ctrl(sc, 0);
9909f55f5f5SRafal Jaworowski 	else
9919f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */
9929f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 1);
9939f55f5f5SRafal Jaworowski 
9949f55f5f5SRafal Jaworowski 	/* Activate network interface */
9959f55f5f5SRafal Jaworowski 	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
9969f55f5f5SRafal Jaworowski 	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9979f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
9989f55f5f5SRafal Jaworowski 
9999f55f5f5SRafal Jaworowski 	/* Schedule watchdog timeout */
10009f55f5f5SRafal Jaworowski 	callout_reset(&sc->wd_callout, hz, mge_tick, sc);
10019f55f5f5SRafal Jaworowski }
10029f55f5f5SRafal Jaworowski 
10039f55f5f5SRafal Jaworowski static void
100475f1438bSOleksandr Tymoshenko mge_intr_rxtx(void *arg)
100575f1438bSOleksandr Tymoshenko {
100675f1438bSOleksandr Tymoshenko 	struct mge_softc *sc = arg;
100775f1438bSOleksandr Tymoshenko 	uint32_t int_cause, int_cause_ext;
100875f1438bSOleksandr Tymoshenko 
100975f1438bSOleksandr Tymoshenko 	MGE_GLOBAL_LOCK(sc);
101075f1438bSOleksandr Tymoshenko 
101175f1438bSOleksandr Tymoshenko #ifdef DEVICE_POLLING
101275f1438bSOleksandr Tymoshenko 	if (sc->ifp->if_capenable & IFCAP_POLLING) {
101375f1438bSOleksandr Tymoshenko 		MGE_GLOBAL_UNLOCK(sc);
101475f1438bSOleksandr Tymoshenko 		return;
101575f1438bSOleksandr Tymoshenko 	}
101675f1438bSOleksandr Tymoshenko #endif
101775f1438bSOleksandr Tymoshenko 
101875f1438bSOleksandr Tymoshenko 	/* Get interrupt cause */
101975f1438bSOleksandr Tymoshenko 	int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
102075f1438bSOleksandr Tymoshenko 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
102175f1438bSOleksandr Tymoshenko 
102275f1438bSOleksandr Tymoshenko 	/* Check for Transmit interrupt */
102375f1438bSOleksandr Tymoshenko 	if (int_cause_ext & (MGE_PORT_INT_EXT_TXBUF0 |
102475f1438bSOleksandr Tymoshenko 	    MGE_PORT_INT_EXT_TXUR)) {
102575f1438bSOleksandr Tymoshenko 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext &
102675f1438bSOleksandr Tymoshenko 		    (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR)));
102775f1438bSOleksandr Tymoshenko 		mge_intr_tx_locked(sc);
102875f1438bSOleksandr Tymoshenko 	}
102975f1438bSOleksandr Tymoshenko 
103075f1438bSOleksandr Tymoshenko 	MGE_TRANSMIT_UNLOCK(sc);
103175f1438bSOleksandr Tymoshenko 
103275f1438bSOleksandr Tymoshenko 	/* Check for Receive interrupt */
103375f1438bSOleksandr Tymoshenko 	mge_intr_rx_check(sc, int_cause, int_cause_ext);
103475f1438bSOleksandr Tymoshenko 
103575f1438bSOleksandr Tymoshenko 	MGE_RECEIVE_UNLOCK(sc);
103675f1438bSOleksandr Tymoshenko }
103775f1438bSOleksandr Tymoshenko 
103875f1438bSOleksandr Tymoshenko static void
10399f55f5f5SRafal Jaworowski mge_intr_err(void *arg)
10409f55f5f5SRafal Jaworowski {
10419f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
10429f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
10439f55f5f5SRafal Jaworowski 
10449f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
10459f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
10469f55f5f5SRafal Jaworowski }
10479f55f5f5SRafal Jaworowski 
10489f55f5f5SRafal Jaworowski static void
10499f55f5f5SRafal Jaworowski mge_intr_misc(void *arg)
10509f55f5f5SRafal Jaworowski {
10519f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
10529f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
10539f55f5f5SRafal Jaworowski 
10549f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
10559f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
10569f55f5f5SRafal Jaworowski }
10579f55f5f5SRafal Jaworowski 
10589f55f5f5SRafal Jaworowski static void
10599f55f5f5SRafal Jaworowski mge_intr_rx(void *arg) {
10609f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
10619f55f5f5SRafal Jaworowski 	uint32_t int_cause, int_cause_ext;
10629f55f5f5SRafal Jaworowski 
10639f55f5f5SRafal Jaworowski 	MGE_RECEIVE_LOCK(sc);
10649f55f5f5SRafal Jaworowski 
10659f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
10669f55f5f5SRafal Jaworowski 	if (sc->ifp->if_capenable & IFCAP_POLLING) {
10679f55f5f5SRafal Jaworowski 		MGE_RECEIVE_UNLOCK(sc);
10689f55f5f5SRafal Jaworowski 		return;
10699f55f5f5SRafal Jaworowski 	}
10709f55f5f5SRafal Jaworowski #endif
10719f55f5f5SRafal Jaworowski 
10729f55f5f5SRafal Jaworowski 	/* Get interrupt cause */
10739f55f5f5SRafal Jaworowski 	int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
10749f55f5f5SRafal Jaworowski 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
10759f55f5f5SRafal Jaworowski 
107675f1438bSOleksandr Tymoshenko 	mge_intr_rx_check(sc, int_cause, int_cause_ext);
107775f1438bSOleksandr Tymoshenko 
107875f1438bSOleksandr Tymoshenko 	MGE_RECEIVE_UNLOCK(sc);
107975f1438bSOleksandr Tymoshenko }
108075f1438bSOleksandr Tymoshenko 
108175f1438bSOleksandr Tymoshenko static void
108275f1438bSOleksandr Tymoshenko mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause,
108375f1438bSOleksandr Tymoshenko     uint32_t int_cause_ext)
108475f1438bSOleksandr Tymoshenko {
10859f55f5f5SRafal Jaworowski 	/* Check for resource error */
10869f55f5f5SRafal Jaworowski 	if (int_cause & MGE_PORT_INT_RXERRQ0) {
10879f55f5f5SRafal Jaworowski 		mge_reinit_rx(sc);
10889f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE,
108975f1438bSOleksandr Tymoshenko 		    ~(int_cause & MGE_PORT_INT_RXERRQ0));
10909f55f5f5SRafal Jaworowski 	}
10919f55f5f5SRafal Jaworowski 
10929f55f5f5SRafal Jaworowski 	int_cause &= MGE_PORT_INT_RXQ0;
10939f55f5f5SRafal Jaworowski 	int_cause_ext &= MGE_PORT_INT_EXT_RXOR;
10949f55f5f5SRafal Jaworowski 
10959f55f5f5SRafal Jaworowski 	if (int_cause || int_cause_ext) {
10969f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause);
10979f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext);
10989f55f5f5SRafal Jaworowski 		mge_intr_rx_locked(sc, -1);
10999f55f5f5SRafal Jaworowski 	}
11009f55f5f5SRafal Jaworowski }
11019f55f5f5SRafal Jaworowski 
11021abcdbd1SAttilio Rao static int
11039f55f5f5SRafal Jaworowski mge_intr_rx_locked(struct mge_softc *sc, int count)
11049f55f5f5SRafal Jaworowski {
11059f55f5f5SRafal Jaworowski 	struct ifnet *ifp = sc->ifp;
11069f55f5f5SRafal Jaworowski 	uint32_t status;
11079f55f5f5SRafal Jaworowski 	uint16_t bufsize;
11089f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper* dw;
11099f55f5f5SRafal Jaworowski 	struct mbuf *mb;
11101abcdbd1SAttilio Rao 	int rx_npkts = 0;
11119f55f5f5SRafal Jaworowski 
11129f55f5f5SRafal Jaworowski 	MGE_RECEIVE_LOCK_ASSERT(sc);
11139f55f5f5SRafal Jaworowski 
11149f55f5f5SRafal Jaworowski 	while (count != 0) {
11159f55f5f5SRafal Jaworowski 		dw = &sc->mge_rx_desc[sc->rx_desc_curr];
11169f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
11179f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
11189f55f5f5SRafal Jaworowski 
11199f55f5f5SRafal Jaworowski 		/* Get status */
11209f55f5f5SRafal Jaworowski 		status = dw->mge_desc->cmd_status;
11219f55f5f5SRafal Jaworowski 		bufsize = dw->mge_desc->buff_size;
11229f55f5f5SRafal Jaworowski 		if ((status & MGE_DMA_OWNED) != 0)
11239f55f5f5SRafal Jaworowski 			break;
11249f55f5f5SRafal Jaworowski 
11259f55f5f5SRafal Jaworowski 		if (dw->mge_desc->byte_count &&
11269f55f5f5SRafal Jaworowski 		    ~(status & MGE_ERR_SUMMARY)) {
11279f55f5f5SRafal Jaworowski 
11289f55f5f5SRafal Jaworowski 			bus_dmamap_sync(sc->mge_rx_dtag, dw->buffer_dmap,
11299f55f5f5SRafal Jaworowski 			    BUS_DMASYNC_POSTREAD);
11309f55f5f5SRafal Jaworowski 
11319f55f5f5SRafal Jaworowski 			mb = m_devget(dw->buffer->m_data,
11329f55f5f5SRafal Jaworowski 			    dw->mge_desc->byte_count - ETHER_CRC_LEN,
11339f55f5f5SRafal Jaworowski 			    0, ifp, NULL);
11349f55f5f5SRafal Jaworowski 
11355817716fSRafal Jaworowski 			if (mb == NULL)
11365817716fSRafal Jaworowski 				/* Give up if no mbufs */
11375817716fSRafal Jaworowski 				break;
11385817716fSRafal Jaworowski 
11399f55f5f5SRafal Jaworowski 			mb->m_len -= 2;
11409f55f5f5SRafal Jaworowski 			mb->m_pkthdr.len -= 2;
11419f55f5f5SRafal Jaworowski 			mb->m_data += 2;
11429f55f5f5SRafal Jaworowski 
1143*b8fad6c0SFabien Thomas 			mb->m_pkthdr.rcvif = ifp;
1144*b8fad6c0SFabien Thomas 
11459f55f5f5SRafal Jaworowski 			mge_offload_process_frame(ifp, mb, status,
11469f55f5f5SRafal Jaworowski 			    bufsize);
11479f55f5f5SRafal Jaworowski 
11489f55f5f5SRafal Jaworowski 			MGE_RECEIVE_UNLOCK(sc);
11499f55f5f5SRafal Jaworowski 			(*ifp->if_input)(ifp, mb);
11509f55f5f5SRafal Jaworowski 			MGE_RECEIVE_LOCK(sc);
11511abcdbd1SAttilio Rao 			rx_npkts++;
11529f55f5f5SRafal Jaworowski 		}
11539f55f5f5SRafal Jaworowski 
11549f55f5f5SRafal Jaworowski 		dw->mge_desc->byte_count = 0;
11559f55f5f5SRafal Jaworowski 		dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
11565817716fSRafal Jaworowski 		sc->rx_desc_curr = (++sc->rx_desc_curr % MGE_RX_DESC_NUM);
11579f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
11589f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
11599f55f5f5SRafal Jaworowski 
11609f55f5f5SRafal Jaworowski 		if (count > 0)
11619f55f5f5SRafal Jaworowski 			count -= 1;
11629f55f5f5SRafal Jaworowski 	}
11639f55f5f5SRafal Jaworowski 
1164*b8fad6c0SFabien Thomas 	ifp->if_ipackets += rx_npkts;
1165*b8fad6c0SFabien Thomas 
11661abcdbd1SAttilio Rao 	return (rx_npkts);
11679f55f5f5SRafal Jaworowski }
11689f55f5f5SRafal Jaworowski 
11699f55f5f5SRafal Jaworowski static void
11709f55f5f5SRafal Jaworowski mge_intr_sum(void *arg)
11719f55f5f5SRafal Jaworowski {
11729f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
11739f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
11749f55f5f5SRafal Jaworowski 
11759f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
11769f55f5f5SRafal Jaworowski 	if_printf(ifp, "%s\n", __FUNCTION__);
11779f55f5f5SRafal Jaworowski }
11789f55f5f5SRafal Jaworowski 
11799f55f5f5SRafal Jaworowski static void
11809f55f5f5SRafal Jaworowski mge_intr_tx(void *arg)
11819f55f5f5SRafal Jaworowski {
11829f55f5f5SRafal Jaworowski 	struct mge_softc *sc = arg;
11839f55f5f5SRafal Jaworowski 	uint32_t int_cause_ext;
11849f55f5f5SRafal Jaworowski 
11859f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK(sc);
11869f55f5f5SRafal Jaworowski 
11879f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
11889f55f5f5SRafal Jaworowski 	if (sc->ifp->if_capenable & IFCAP_POLLING) {
11899f55f5f5SRafal Jaworowski 		MGE_TRANSMIT_UNLOCK(sc);
11909f55f5f5SRafal Jaworowski 		return;
11919f55f5f5SRafal Jaworowski 	}
11929f55f5f5SRafal Jaworowski #endif
11939f55f5f5SRafal Jaworowski 
11949f55f5f5SRafal Jaworowski 	/* Ack the interrupt */
11959f55f5f5SRafal Jaworowski 	int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
119675f1438bSOleksandr Tymoshenko 	MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext &
119775f1438bSOleksandr Tymoshenko 	    (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR)));
11989f55f5f5SRafal Jaworowski 
11999f55f5f5SRafal Jaworowski 	mge_intr_tx_locked(sc);
12009f55f5f5SRafal Jaworowski 
12019f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_UNLOCK(sc);
12029f55f5f5SRafal Jaworowski }
12039f55f5f5SRafal Jaworowski 
12049f55f5f5SRafal Jaworowski 
12059f55f5f5SRafal Jaworowski static void
12069f55f5f5SRafal Jaworowski mge_intr_tx_locked(struct mge_softc *sc)
12079f55f5f5SRafal Jaworowski {
12089f55f5f5SRafal Jaworowski 	struct ifnet *ifp = sc->ifp;
12099f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
12109f55f5f5SRafal Jaworowski 	struct mge_desc *desc;
12119f55f5f5SRafal Jaworowski 	uint32_t status;
12129f55f5f5SRafal Jaworowski 	int send = 0;
12139f55f5f5SRafal Jaworowski 
12149f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK_ASSERT(sc);
12159f55f5f5SRafal Jaworowski 
12169f55f5f5SRafal Jaworowski 	/* Disable watchdog */
12179f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
12189f55f5f5SRafal Jaworowski 
12199f55f5f5SRafal Jaworowski 	while (sc->tx_desc_used_count) {
12209f55f5f5SRafal Jaworowski 		/* Get the descriptor */
12219f55f5f5SRafal Jaworowski 		dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
12229f55f5f5SRafal Jaworowski 		desc = dw->mge_desc;
12239f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
12249f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
12259f55f5f5SRafal Jaworowski 
12269f55f5f5SRafal Jaworowski 		/* Get descriptor status */
12279f55f5f5SRafal Jaworowski 		status = desc->cmd_status;
12289f55f5f5SRafal Jaworowski 
12299f55f5f5SRafal Jaworowski 		if (status & MGE_DMA_OWNED)
12309f55f5f5SRafal Jaworowski 			break;
12319f55f5f5SRafal Jaworowski 
12329f55f5f5SRafal Jaworowski 		sc->tx_desc_used_idx =
1233c2ede4b3SMartin Blapp 			(++sc->tx_desc_used_idx) % MGE_TX_DESC_NUM;
12349f55f5f5SRafal Jaworowski 		sc->tx_desc_used_count--;
12359f55f5f5SRafal Jaworowski 
12369f55f5f5SRafal Jaworowski 		/* Update collision statistics */
12379f55f5f5SRafal Jaworowski 		if (status & MGE_ERR_SUMMARY) {
12389f55f5f5SRafal Jaworowski 			if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_LC)
12399f55f5f5SRafal Jaworowski 				ifp->if_collisions++;
12409f55f5f5SRafal Jaworowski 			if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_RL)
12419f55f5f5SRafal Jaworowski 				ifp->if_collisions += 16;
12429f55f5f5SRafal Jaworowski 		}
12439f55f5f5SRafal Jaworowski 
12449f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
12459f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTWRITE);
12469f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap);
12479f55f5f5SRafal Jaworowski 		m_freem(dw->buffer);
12489f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
12499f55f5f5SRafal Jaworowski 		send++;
12509f55f5f5SRafal Jaworowski 
12519f55f5f5SRafal Jaworowski 		ifp->if_opackets++;
12529f55f5f5SRafal Jaworowski 	}
12539f55f5f5SRafal Jaworowski 
12549f55f5f5SRafal Jaworowski 	if (send) {
12559f55f5f5SRafal Jaworowski 		/* Now send anything that was pending */
12569f55f5f5SRafal Jaworowski 		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
12579f55f5f5SRafal Jaworowski 		mge_start_locked(ifp);
12589f55f5f5SRafal Jaworowski 	}
12599f55f5f5SRafal Jaworowski }
12609f55f5f5SRafal Jaworowski 
12619f55f5f5SRafal Jaworowski static int
12629f55f5f5SRafal Jaworowski mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
12639f55f5f5SRafal Jaworowski {
12649f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
12659f55f5f5SRafal Jaworowski 	struct ifreq *ifr = (struct ifreq *)data;
12669f55f5f5SRafal Jaworowski 	int mask, error;
12679f55f5f5SRafal Jaworowski 	uint32_t flags;
12689f55f5f5SRafal Jaworowski 
12699f55f5f5SRafal Jaworowski 	error = 0;
12709f55f5f5SRafal Jaworowski 
12719f55f5f5SRafal Jaworowski 	switch (command) {
12729f55f5f5SRafal Jaworowski 	case SIOCSIFFLAGS:
12739f55f5f5SRafal Jaworowski 		MGE_GLOBAL_LOCK(sc);
12749f55f5f5SRafal Jaworowski 
12759f55f5f5SRafal Jaworowski 		if (ifp->if_flags & IFF_UP) {
12769f55f5f5SRafal Jaworowski 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
12779f55f5f5SRafal Jaworowski 				flags = ifp->if_flags ^ sc->mge_if_flags;
12789f55f5f5SRafal Jaworowski 				if (flags & IFF_PROMISC)
12799f55f5f5SRafal Jaworowski 					mge_set_prom_mode(sc,
12809f55f5f5SRafal Jaworowski 					    MGE_RX_DEFAULT_QUEUE);
12819f55f5f5SRafal Jaworowski 
12829f55f5f5SRafal Jaworowski 				if (flags & IFF_ALLMULTI)
12839f55f5f5SRafal Jaworowski 					mge_setup_multicast(sc);
12849f55f5f5SRafal Jaworowski 			} else
12859f55f5f5SRafal Jaworowski 				mge_init_locked(sc);
12869f55f5f5SRafal Jaworowski 		}
12879f55f5f5SRafal Jaworowski 		else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
12889f55f5f5SRafal Jaworowski 			mge_stop(sc);
12899f55f5f5SRafal Jaworowski 
12909f55f5f5SRafal Jaworowski 		sc->mge_if_flags = ifp->if_flags;
12919f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
12929f55f5f5SRafal Jaworowski 		break;
12939f55f5f5SRafal Jaworowski 	case SIOCADDMULTI:
12949f55f5f5SRafal Jaworowski 	case SIOCDELMULTI:
12959f55f5f5SRafal Jaworowski 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
12969f55f5f5SRafal Jaworowski 			MGE_GLOBAL_LOCK(sc);
12979f55f5f5SRafal Jaworowski 			mge_setup_multicast(sc);
12989f55f5f5SRafal Jaworowski 			MGE_GLOBAL_UNLOCK(sc);
12999f55f5f5SRafal Jaworowski 		}
13009f55f5f5SRafal Jaworowski 		break;
13019f55f5f5SRafal Jaworowski 	case SIOCSIFCAP:
13029f55f5f5SRafal Jaworowski 		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
13039f55f5f5SRafal Jaworowski 		if (mask & IFCAP_HWCSUM) {
13049f55f5f5SRafal Jaworowski 			ifp->if_capenable &= ~IFCAP_HWCSUM;
13059f55f5f5SRafal Jaworowski 			ifp->if_capenable |= IFCAP_HWCSUM & ifr->ifr_reqcap;
13069f55f5f5SRafal Jaworowski 			if (ifp->if_capenable & IFCAP_TXCSUM)
13079f55f5f5SRafal Jaworowski 				ifp->if_hwassist = MGE_CHECKSUM_FEATURES;
13089f55f5f5SRafal Jaworowski 			else
13099f55f5f5SRafal Jaworowski 				ifp->if_hwassist = 0;
13109f55f5f5SRafal Jaworowski 		}
13119f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
13129f55f5f5SRafal Jaworowski 		if (mask & IFCAP_POLLING) {
13139f55f5f5SRafal Jaworowski 			if (ifr->ifr_reqcap & IFCAP_POLLING) {
13149f55f5f5SRafal Jaworowski 				error = ether_poll_register(mge_poll, ifp);
13159f55f5f5SRafal Jaworowski 				if (error)
13169f55f5f5SRafal Jaworowski 					return(error);
13179f55f5f5SRafal Jaworowski 
13189f55f5f5SRafal Jaworowski 				MGE_GLOBAL_LOCK(sc);
13199f55f5f5SRafal Jaworowski 				mge_intrs_ctrl(sc, 0);
13209f55f5f5SRafal Jaworowski 				ifp->if_capenable |= IFCAP_POLLING;
13219f55f5f5SRafal Jaworowski 				MGE_GLOBAL_UNLOCK(sc);
13229f55f5f5SRafal Jaworowski 			} else {
13239f55f5f5SRafal Jaworowski 				error = ether_poll_deregister(ifp);
13249f55f5f5SRafal Jaworowski 				MGE_GLOBAL_LOCK(sc);
13259f55f5f5SRafal Jaworowski 				mge_intrs_ctrl(sc, 1);
13269f55f5f5SRafal Jaworowski 				ifp->if_capenable &= ~IFCAP_POLLING;
13279f55f5f5SRafal Jaworowski 				MGE_GLOBAL_UNLOCK(sc);
13289f55f5f5SRafal Jaworowski 			}
13299f55f5f5SRafal Jaworowski 		}
13309f55f5f5SRafal Jaworowski #endif
13319f55f5f5SRafal Jaworowski 		break;
13329f55f5f5SRafal Jaworowski 	case SIOCGIFMEDIA: /* fall through */
13339f55f5f5SRafal Jaworowski 	case SIOCSIFMEDIA:
13349f55f5f5SRafal Jaworowski 		if (IFM_SUBTYPE(ifr->ifr_media) == IFM_1000_T
13359f55f5f5SRafal Jaworowski 		    && !(ifr->ifr_media & IFM_FDX)) {
13369f55f5f5SRafal Jaworowski 			device_printf(sc->dev,
13379f55f5f5SRafal Jaworowski 			    "1000baseTX half-duplex unsupported\n");
13389f55f5f5SRafal Jaworowski 			return 0;
13399f55f5f5SRafal Jaworowski 		}
13409f55f5f5SRafal Jaworowski 		error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command);
13419f55f5f5SRafal Jaworowski 		break;
13429f55f5f5SRafal Jaworowski 	default:
13439f55f5f5SRafal Jaworowski 		error = ether_ioctl(ifp, command, data);
13449f55f5f5SRafal Jaworowski 	}
13459f55f5f5SRafal Jaworowski 	return (error);
13469f55f5f5SRafal Jaworowski }
13479f55f5f5SRafal Jaworowski 
13489f55f5f5SRafal Jaworowski static int
13499f55f5f5SRafal Jaworowski mge_miibus_readreg(device_t dev, int phy, int reg)
13509f55f5f5SRafal Jaworowski {
1351db5ef4fcSRafal Jaworowski 	struct mge_softc *sc;
13529f55f5f5SRafal Jaworowski 	uint32_t retries;
13539f55f5f5SRafal Jaworowski 
1354db5ef4fcSRafal Jaworowski 	sc = device_get_softc(dev);
13559f55f5f5SRafal Jaworowski 
1356aa15e881SRafal Jaworowski 	MGE_WRITE(sc->phy_sc, MGE_REG_SMI, 0x1fffffff &
13579f55f5f5SRafal Jaworowski 	    (MGE_SMI_READ | (reg << 21) | (phy << 16)));
13589f55f5f5SRafal Jaworowski 
13599f55f5f5SRafal Jaworowski 	retries = MGE_SMI_READ_RETRIES;
1360aa15e881SRafal Jaworowski 	while (--retries &&
1361aa15e881SRafal Jaworowski 	    !(MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_READVALID))
13629f55f5f5SRafal Jaworowski 		DELAY(MGE_SMI_READ_DELAY);
13639f55f5f5SRafal Jaworowski 
13649f55f5f5SRafal Jaworowski 	if (retries == 0)
13659f55f5f5SRafal Jaworowski 		device_printf(dev, "Timeout while reading from PHY\n");
13669f55f5f5SRafal Jaworowski 
1367aa15e881SRafal Jaworowski 	return (MGE_READ(sc->phy_sc, MGE_REG_SMI) & 0xffff);
13689f55f5f5SRafal Jaworowski }
13699f55f5f5SRafal Jaworowski 
13708e45f0b7SAndriy Gapon static int
13719f55f5f5SRafal Jaworowski mge_miibus_writereg(device_t dev, int phy, int reg, int value)
13729f55f5f5SRafal Jaworowski {
1373db5ef4fcSRafal Jaworowski 	struct mge_softc *sc;
13749f55f5f5SRafal Jaworowski 	uint32_t retries;
13759f55f5f5SRafal Jaworowski 
1376db5ef4fcSRafal Jaworowski 	sc = device_get_softc(dev);
1377db5ef4fcSRafal Jaworowski 
1378aa15e881SRafal Jaworowski 	MGE_WRITE(sc->phy_sc, MGE_REG_SMI, 0x1fffffff &
13799f55f5f5SRafal Jaworowski 	    (MGE_SMI_WRITE | (reg << 21) | (phy << 16) | (value & 0xffff)));
13809f55f5f5SRafal Jaworowski 
13819f55f5f5SRafal Jaworowski 	retries = MGE_SMI_WRITE_RETRIES;
1382aa15e881SRafal Jaworowski 	while (--retries && MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_BUSY)
13839f55f5f5SRafal Jaworowski 		DELAY(MGE_SMI_WRITE_DELAY);
13849f55f5f5SRafal Jaworowski 
13859f55f5f5SRafal Jaworowski 	if (retries == 0)
13869f55f5f5SRafal Jaworowski 		device_printf(dev, "Timeout while writing to PHY\n");
13878e45f0b7SAndriy Gapon 	return (0);
13889f55f5f5SRafal Jaworowski }
13899f55f5f5SRafal Jaworowski 
13909f55f5f5SRafal Jaworowski static int
13919f55f5f5SRafal Jaworowski mge_probe(device_t dev)
13929f55f5f5SRafal Jaworowski {
13939f55f5f5SRafal Jaworowski 
1394add35ed5SIan Lepore 	if (!ofw_bus_status_okay(dev))
1395add35ed5SIan Lepore 		return (ENXIO);
1396add35ed5SIan Lepore 
1397db5ef4fcSRafal Jaworowski 	if (!ofw_bus_is_compatible(dev, "mrvl,ge"))
1398db5ef4fcSRafal Jaworowski 		return (ENXIO);
1399db5ef4fcSRafal Jaworowski 
14009f55f5f5SRafal Jaworowski 	device_set_desc(dev, "Marvell Gigabit Ethernet controller");
14019f55f5f5SRafal Jaworowski 	return (BUS_PROBE_DEFAULT);
14029f55f5f5SRafal Jaworowski }
14039f55f5f5SRafal Jaworowski 
14049f55f5f5SRafal Jaworowski static int
14059f55f5f5SRafal Jaworowski mge_resume(device_t dev)
14069f55f5f5SRafal Jaworowski {
14079f55f5f5SRafal Jaworowski 
14089f55f5f5SRafal Jaworowski 	device_printf(dev, "%s\n", __FUNCTION__);
14099f55f5f5SRafal Jaworowski 	return (0);
14109f55f5f5SRafal Jaworowski }
14119f55f5f5SRafal Jaworowski 
14129f55f5f5SRafal Jaworowski static int
14139f55f5f5SRafal Jaworowski mge_shutdown(device_t dev)
14149f55f5f5SRafal Jaworowski {
14159f55f5f5SRafal Jaworowski 	struct mge_softc *sc = device_get_softc(dev);
14169f55f5f5SRafal Jaworowski 
14179f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
14189f55f5f5SRafal Jaworowski 
14199f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
14209f55f5f5SRafal Jaworowski         if (sc->ifp->if_capenable & IFCAP_POLLING)
14219f55f5f5SRafal Jaworowski 		ether_poll_deregister(sc->ifp);
14229f55f5f5SRafal Jaworowski #endif
14239f55f5f5SRafal Jaworowski 
14249f55f5f5SRafal Jaworowski 	mge_stop(sc);
14259f55f5f5SRafal Jaworowski 
14269f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
14279f55f5f5SRafal Jaworowski 
14289f55f5f5SRafal Jaworowski 	return (0);
14299f55f5f5SRafal Jaworowski }
14309f55f5f5SRafal Jaworowski 
14319f55f5f5SRafal Jaworowski static int
14329f55f5f5SRafal Jaworowski mge_encap(struct mge_softc *sc, struct mbuf *m0)
14339f55f5f5SRafal Jaworowski {
14349f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw = NULL;
14359f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
14369f55f5f5SRafal Jaworowski 	bus_dma_segment_t segs[MGE_TX_DESC_NUM];
14379f55f5f5SRafal Jaworowski 	bus_dmamap_t mapp;
14389f55f5f5SRafal Jaworowski 	int error;
14399f55f5f5SRafal Jaworowski 	int seg, nsegs;
14409f55f5f5SRafal Jaworowski 	int desc_no;
14419f55f5f5SRafal Jaworowski 
14429f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
14439f55f5f5SRafal Jaworowski 
14449f55f5f5SRafal Jaworowski 	/* Fetch unused map */
14459f55f5f5SRafal Jaworowski 	desc_no = sc->tx_desc_curr;
14469f55f5f5SRafal Jaworowski 	dw = &sc->mge_tx_desc[desc_no];
14479f55f5f5SRafal Jaworowski 	mapp = dw->buffer_dmap;
14489f55f5f5SRafal Jaworowski 
14499f55f5f5SRafal Jaworowski 	/* Create mapping in DMA memory */
14509f55f5f5SRafal Jaworowski 	error = bus_dmamap_load_mbuf_sg(sc->mge_tx_dtag, mapp, m0, segs, &nsegs,
14519f55f5f5SRafal Jaworowski 	    BUS_DMA_NOWAIT);
1452*b8fad6c0SFabien Thomas 	if (error != 0) {
1453*b8fad6c0SFabien Thomas 		m_freem(m0);
1454*b8fad6c0SFabien Thomas 		return (error);
1455*b8fad6c0SFabien Thomas 	}
1456*b8fad6c0SFabien Thomas 
1457*b8fad6c0SFabien Thomas 	/* Only one segment is supported. */
1458*b8fad6c0SFabien Thomas 	if (nsegs != 1) {
14599f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, mapp);
1460*b8fad6c0SFabien Thomas 		m_freem(m0);
1461*b8fad6c0SFabien Thomas 		return (-1);
14629f55f5f5SRafal Jaworowski 	}
14639f55f5f5SRafal Jaworowski 
14649f55f5f5SRafal Jaworowski 	bus_dmamap_sync(sc->mge_tx_dtag, mapp, BUS_DMASYNC_PREWRITE);
14659f55f5f5SRafal Jaworowski 
14669f55f5f5SRafal Jaworowski 	/* Everything is ok, now we can send buffers */
14679f55f5f5SRafal Jaworowski 	for (seg = 0; seg < nsegs; seg++) {
14689f55f5f5SRafal Jaworowski 		dw->mge_desc->byte_count = segs[seg].ds_len;
14699f55f5f5SRafal Jaworowski 		dw->mge_desc->buffer = segs[seg].ds_addr;
14709f55f5f5SRafal Jaworowski 		dw->buffer = m0;
147175f1438bSOleksandr Tymoshenko 		dw->mge_desc->cmd_status = 0;
14729f55f5f5SRafal Jaworowski 		if (seg == 0)
14739f55f5f5SRafal Jaworowski 			mge_offload_setup_descriptor(sc, dw);
147475f1438bSOleksandr Tymoshenko 		dw->mge_desc->cmd_status |= MGE_TX_LAST | MGE_TX_FIRST |
147575f1438bSOleksandr Tymoshenko 		    MGE_TX_ETH_CRC | MGE_TX_EN_INT | MGE_TX_PADDING |
147675f1438bSOleksandr Tymoshenko 		    MGE_DMA_OWNED;
14779f55f5f5SRafal Jaworowski 	}
14789f55f5f5SRafal Jaworowski 
1479d6bdd318SRafal Jaworowski 	bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
14809f55f5f5SRafal Jaworowski 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
14819f55f5f5SRafal Jaworowski 
14829f55f5f5SRafal Jaworowski 	sc->tx_desc_curr = (++sc->tx_desc_curr) % MGE_TX_DESC_NUM;
14839f55f5f5SRafal Jaworowski 	sc->tx_desc_used_count++;
14849f55f5f5SRafal Jaworowski 	return (0);
14859f55f5f5SRafal Jaworowski }
14869f55f5f5SRafal Jaworowski 
14879f55f5f5SRafal Jaworowski static void
14889f55f5f5SRafal Jaworowski mge_tick(void *msc)
14899f55f5f5SRafal Jaworowski {
14909f55f5f5SRafal Jaworowski 	struct mge_softc *sc = msc;
14919f55f5f5SRafal Jaworowski 
14929f55f5f5SRafal Jaworowski 	/* Check for TX timeout */
14939f55f5f5SRafal Jaworowski 	mge_watchdog(sc);
14949f55f5f5SRafal Jaworowski 
14959f55f5f5SRafal Jaworowski 	mii_tick(sc->mii);
14969f55f5f5SRafal Jaworowski 
14979f55f5f5SRafal Jaworowski 	/* Check for media type change */
14989f55f5f5SRafal Jaworowski 	if(sc->mge_media_status != sc->mii->mii_media.ifm_media)
14999f55f5f5SRafal Jaworowski 		mge_ifmedia_upd(sc->ifp);
15009f55f5f5SRafal Jaworowski 
15019f55f5f5SRafal Jaworowski 	/* Schedule another timeout one second from now */
15029f55f5f5SRafal Jaworowski 	callout_reset(&sc->wd_callout, hz, mge_tick, sc);
15039f55f5f5SRafal Jaworowski }
15049f55f5f5SRafal Jaworowski 
15059f55f5f5SRafal Jaworowski static void
15069f55f5f5SRafal Jaworowski mge_watchdog(struct mge_softc *sc)
15079f55f5f5SRafal Jaworowski {
15089f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
15099f55f5f5SRafal Jaworowski 
15109f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
15119f55f5f5SRafal Jaworowski 
15129f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
15139f55f5f5SRafal Jaworowski 
15149f55f5f5SRafal Jaworowski 	if (sc->wd_timer == 0 || --sc->wd_timer) {
15159f55f5f5SRafal Jaworowski 		MGE_GLOBAL_UNLOCK(sc);
15169f55f5f5SRafal Jaworowski 		return;
15179f55f5f5SRafal Jaworowski 	}
15189f55f5f5SRafal Jaworowski 
15199f55f5f5SRafal Jaworowski 	ifp->if_oerrors++;
15209f55f5f5SRafal Jaworowski 	if_printf(ifp, "watchdog timeout\n");
15219f55f5f5SRafal Jaworowski 
15229f55f5f5SRafal Jaworowski 	mge_stop(sc);
15239f55f5f5SRafal Jaworowski 	mge_init_locked(sc);
15249f55f5f5SRafal Jaworowski 
15259f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
15269f55f5f5SRafal Jaworowski }
15279f55f5f5SRafal Jaworowski 
15289f55f5f5SRafal Jaworowski static void
15299f55f5f5SRafal Jaworowski mge_start(struct ifnet *ifp)
15309f55f5f5SRafal Jaworowski {
15319f55f5f5SRafal Jaworowski 	struct mge_softc *sc = ifp->if_softc;
15329f55f5f5SRafal Jaworowski 
15339f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK(sc);
15349f55f5f5SRafal Jaworowski 
15359f55f5f5SRafal Jaworowski 	mge_start_locked(ifp);
15369f55f5f5SRafal Jaworowski 
15379f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_UNLOCK(sc);
15389f55f5f5SRafal Jaworowski }
15399f55f5f5SRafal Jaworowski 
15409f55f5f5SRafal Jaworowski static void
15419f55f5f5SRafal Jaworowski mge_start_locked(struct ifnet *ifp)
15429f55f5f5SRafal Jaworowski {
15439f55f5f5SRafal Jaworowski 	struct mge_softc *sc;
15449f55f5f5SRafal Jaworowski 	struct mbuf *m0, *mtmp;
15459f55f5f5SRafal Jaworowski 	uint32_t reg_val, queued = 0;
15469f55f5f5SRafal Jaworowski 
15479f55f5f5SRafal Jaworowski 	sc = ifp->if_softc;
15489f55f5f5SRafal Jaworowski 
15499f55f5f5SRafal Jaworowski 	MGE_TRANSMIT_LOCK_ASSERT(sc);
15509f55f5f5SRafal Jaworowski 
15519f55f5f5SRafal Jaworowski 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
15529f55f5f5SRafal Jaworowski 	    IFF_DRV_RUNNING)
15539f55f5f5SRafal Jaworowski 		return;
15549f55f5f5SRafal Jaworowski 
15559f55f5f5SRafal Jaworowski 	for (;;) {
15569f55f5f5SRafal Jaworowski 		/* Get packet from the queue */
15579f55f5f5SRafal Jaworowski 		IF_DEQUEUE(&ifp->if_snd, m0);
15589f55f5f5SRafal Jaworowski 		if (m0 == NULL)
15599f55f5f5SRafal Jaworowski 			break;
15609f55f5f5SRafal Jaworowski 
1561*b8fad6c0SFabien Thomas 		if (m0->m_pkthdr.csum_flags & (CSUM_IP|CSUM_TCP|CSUM_UDP) ||
1562*b8fad6c0SFabien Thomas 		    m0->m_flags & M_VLANTAG) {
1563*b8fad6c0SFabien Thomas 			if (M_WRITABLE(m0) == 0) {
1564*b8fad6c0SFabien Thomas 				mtmp = m_dup(m0, M_NOWAIT);
1565*b8fad6c0SFabien Thomas 				m_freem(m0);
1566*b8fad6c0SFabien Thomas 				if (mtmp == NULL)
1567*b8fad6c0SFabien Thomas 					continue;
1568*b8fad6c0SFabien Thomas 				m0 = mtmp;
1569*b8fad6c0SFabien Thomas 			}
1570*b8fad6c0SFabien Thomas 		}
1571*b8fad6c0SFabien Thomas 		/* The driver support only one DMA fragment. */
1572*b8fad6c0SFabien Thomas 		if (m0->m_next != NULL) {
1573c6499eccSGleb Smirnoff 			mtmp = m_defrag(m0, M_NOWAIT);
15749f55f5f5SRafal Jaworowski 			if (mtmp)
15759f55f5f5SRafal Jaworowski 				m0 = mtmp;
1576*b8fad6c0SFabien Thomas 		}
15779f55f5f5SRafal Jaworowski 
1578*b8fad6c0SFabien Thomas 		/* Check for free descriptors */
1579*b8fad6c0SFabien Thomas 		if (sc->tx_desc_used_count + 1 >= MGE_TX_DESC_NUM) {
15809f55f5f5SRafal Jaworowski 			IF_PREPEND(&ifp->if_snd, m0);
15819f55f5f5SRafal Jaworowski 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
15829f55f5f5SRafal Jaworowski 			break;
15839f55f5f5SRafal Jaworowski 		}
1584*b8fad6c0SFabien Thomas 
1585*b8fad6c0SFabien Thomas 		if (mge_encap(sc, m0) != 0)
1586*b8fad6c0SFabien Thomas 			break;
1587*b8fad6c0SFabien Thomas 
15889f55f5f5SRafal Jaworowski 		queued++;
15899f55f5f5SRafal Jaworowski 		BPF_MTAP(ifp, m0);
15909f55f5f5SRafal Jaworowski 	}
15919f55f5f5SRafal Jaworowski 
15929f55f5f5SRafal Jaworowski 	if (queued) {
15939f55f5f5SRafal Jaworowski 		/* Enable transmitter and watchdog timer */
15949f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD);
15959f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_ENABLE_TXQ);
15969f55f5f5SRafal Jaworowski 		sc->wd_timer = 5;
15979f55f5f5SRafal Jaworowski 	}
15989f55f5f5SRafal Jaworowski }
15999f55f5f5SRafal Jaworowski 
16009f55f5f5SRafal Jaworowski static void
16019f55f5f5SRafal Jaworowski mge_stop(struct mge_softc *sc)
16029f55f5f5SRafal Jaworowski {
16039f55f5f5SRafal Jaworowski 	struct ifnet *ifp;
16049f55f5f5SRafal Jaworowski 	volatile uint32_t reg_val, status;
16059f55f5f5SRafal Jaworowski 	struct mge_desc_wrapper *dw;
16069f55f5f5SRafal Jaworowski 	struct mge_desc *desc;
16079f55f5f5SRafal Jaworowski 	int count;
16089f55f5f5SRafal Jaworowski 
16099f55f5f5SRafal Jaworowski 	ifp = sc->ifp;
16109f55f5f5SRafal Jaworowski 
16119f55f5f5SRafal Jaworowski 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
16129f55f5f5SRafal Jaworowski 		return;
16139f55f5f5SRafal Jaworowski 
16149f55f5f5SRafal Jaworowski 	/* Stop tick engine */
16159f55f5f5SRafal Jaworowski 	callout_stop(&sc->wd_callout);
16169f55f5f5SRafal Jaworowski 
16179f55f5f5SRafal Jaworowski 	/* Disable interface */
16189f55f5f5SRafal Jaworowski 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
16199f55f5f5SRafal Jaworowski 	sc->wd_timer = 0;
16209f55f5f5SRafal Jaworowski 
16219f55f5f5SRafal Jaworowski 	/* Disable interrupts */
16229f55f5f5SRafal Jaworowski 	mge_intrs_ctrl(sc, 0);
16239f55f5f5SRafal Jaworowski 
16249f55f5f5SRafal Jaworowski 	/* Disable Rx and Tx */
16259f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD);
16269f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_DISABLE_TXQ);
16279f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_DISABLE_RXQ_ALL);
16289f55f5f5SRafal Jaworowski 
16299f55f5f5SRafal Jaworowski 	/* Remove pending data from TX queue */
16305817716fSRafal Jaworowski 	while (sc->tx_desc_used_idx != sc->tx_desc_curr &&
16315817716fSRafal Jaworowski 	    sc->tx_desc_used_count) {
16329f55f5f5SRafal Jaworowski 		/* Get the descriptor */
16339f55f5f5SRafal Jaworowski 		dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
16349f55f5f5SRafal Jaworowski 		desc = dw->mge_desc;
16359f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
16369f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTREAD);
16379f55f5f5SRafal Jaworowski 
16389f55f5f5SRafal Jaworowski 		/* Get descriptor status */
16399f55f5f5SRafal Jaworowski 		status = desc->cmd_status;
16409f55f5f5SRafal Jaworowski 
16419f55f5f5SRafal Jaworowski 		if (status & MGE_DMA_OWNED)
16429f55f5f5SRafal Jaworowski 			break;
16439f55f5f5SRafal Jaworowski 
16449f55f5f5SRafal Jaworowski 		sc->tx_desc_used_idx = (++sc->tx_desc_used_idx) %
16459f55f5f5SRafal Jaworowski 		    MGE_TX_DESC_NUM;
16465817716fSRafal Jaworowski 		sc->tx_desc_used_count--;
16479f55f5f5SRafal Jaworowski 
16489f55f5f5SRafal Jaworowski 		bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
16499f55f5f5SRafal Jaworowski 		    BUS_DMASYNC_POSTWRITE);
16509f55f5f5SRafal Jaworowski 		bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap);
16519f55f5f5SRafal Jaworowski 
16529f55f5f5SRafal Jaworowski 		m_freem(dw->buffer);
16539f55f5f5SRafal Jaworowski 		dw->buffer = (struct mbuf*)NULL;
16549f55f5f5SRafal Jaworowski 	}
16559f55f5f5SRafal Jaworowski 
16569f55f5f5SRafal Jaworowski 	/* Wait for end of transmission */
16579f55f5f5SRafal Jaworowski 	count = 0x100000;
16589f55f5f5SRafal Jaworowski 	while (count--) {
16599f55f5f5SRafal Jaworowski 		reg_val = MGE_READ(sc, MGE_PORT_STATUS);
16609f55f5f5SRafal Jaworowski 		if ( !(reg_val & MGE_STATUS_TX_IN_PROG) &&
16619f55f5f5SRafal Jaworowski 		    (reg_val & MGE_STATUS_TX_FIFO_EMPTY))
16629f55f5f5SRafal Jaworowski 			break;
16639f55f5f5SRafal Jaworowski 		DELAY(100);
16649f55f5f5SRafal Jaworowski 	}
16659f55f5f5SRafal Jaworowski 
16669f55f5f5SRafal Jaworowski 	if(!count)
16679f55f5f5SRafal Jaworowski 		if_printf(ifp, "%s: timeout while waiting for end of transmission\n",
16689f55f5f5SRafal Jaworowski 		    __FUNCTION__);
16699f55f5f5SRafal Jaworowski 
16709f55f5f5SRafal Jaworowski 	reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL);
16719f55f5f5SRafal Jaworowski 	reg_val &= ~(PORT_SERIAL_ENABLE);
16729f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL ,reg_val);
16739f55f5f5SRafal Jaworowski }
16749f55f5f5SRafal Jaworowski 
16759f55f5f5SRafal Jaworowski static int
16769f55f5f5SRafal Jaworowski mge_suspend(device_t dev)
16779f55f5f5SRafal Jaworowski {
16789f55f5f5SRafal Jaworowski 
16799f55f5f5SRafal Jaworowski 	device_printf(dev, "%s\n", __FUNCTION__);
16809f55f5f5SRafal Jaworowski 	return (0);
16819f55f5f5SRafal Jaworowski }
16829f55f5f5SRafal Jaworowski 
16839f55f5f5SRafal Jaworowski static void
16849f55f5f5SRafal Jaworowski mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame,
16859f55f5f5SRafal Jaworowski     uint32_t status, uint16_t bufsize)
16869f55f5f5SRafal Jaworowski {
16879f55f5f5SRafal Jaworowski 	int csum_flags = 0;
16889f55f5f5SRafal Jaworowski 
16899f55f5f5SRafal Jaworowski 	if (ifp->if_capenable & IFCAP_RXCSUM) {
16909f55f5f5SRafal Jaworowski 		if ((status & MGE_RX_L3_IS_IP) && (status & MGE_RX_IP_OK))
16919f55f5f5SRafal Jaworowski 			csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID;
16929f55f5f5SRafal Jaworowski 
16939f55f5f5SRafal Jaworowski 		if ((bufsize & MGE_RX_IP_FRAGMENT) == 0 &&
16949f55f5f5SRafal Jaworowski 		    (MGE_RX_L4_IS_TCP(status) || MGE_RX_L4_IS_UDP(status)) &&
16959f55f5f5SRafal Jaworowski 		    (status & MGE_RX_L4_CSUM_OK)) {
16969f55f5f5SRafal Jaworowski 			csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
16979f55f5f5SRafal Jaworowski 			frame->m_pkthdr.csum_data = 0xFFFF;
16989f55f5f5SRafal Jaworowski 		}
16999f55f5f5SRafal Jaworowski 
17009f55f5f5SRafal Jaworowski 		frame->m_pkthdr.csum_flags = csum_flags;
17019f55f5f5SRafal Jaworowski 	}
17029f55f5f5SRafal Jaworowski }
17039f55f5f5SRafal Jaworowski 
17049f55f5f5SRafal Jaworowski static void
17059f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(struct mge_softc *sc, struct mge_desc_wrapper *dw)
17069f55f5f5SRafal Jaworowski {
17079f55f5f5SRafal Jaworowski 	struct mbuf *m0 = dw->buffer;
17089f55f5f5SRafal Jaworowski 	struct ether_vlan_header *eh = mtod(m0, struct ether_vlan_header *);
17099f55f5f5SRafal Jaworowski 	int csum_flags = m0->m_pkthdr.csum_flags;
17109f55f5f5SRafal Jaworowski 	int cmd_status = 0;
17119f55f5f5SRafal Jaworowski 	struct ip *ip;
17129f55f5f5SRafal Jaworowski 	int ehlen, etype;
17139f55f5f5SRafal Jaworowski 
17149f55f5f5SRafal Jaworowski 	if (csum_flags) {
17159f55f5f5SRafal Jaworowski 		if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
17169f55f5f5SRafal Jaworowski 			etype = ntohs(eh->evl_proto);
17179f55f5f5SRafal Jaworowski 			ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
17189f55f5f5SRafal Jaworowski 			csum_flags |= MGE_TX_VLAN_TAGGED;
17199f55f5f5SRafal Jaworowski 		} else {
17209f55f5f5SRafal Jaworowski 			etype = ntohs(eh->evl_encap_proto);
17219f55f5f5SRafal Jaworowski 			ehlen = ETHER_HDR_LEN;
17229f55f5f5SRafal Jaworowski 		}
17239f55f5f5SRafal Jaworowski 
17249f55f5f5SRafal Jaworowski 		if (etype != ETHERTYPE_IP) {
17259f55f5f5SRafal Jaworowski 			if_printf(sc->ifp,
17269f55f5f5SRafal Jaworowski 			    "TCP/IP Offload enabled for unsupported "
17279f55f5f5SRafal Jaworowski 			    "protocol!\n");
17289f55f5f5SRafal Jaworowski 			return;
17299f55f5f5SRafal Jaworowski 		}
17309f55f5f5SRafal Jaworowski 
17319f55f5f5SRafal Jaworowski 		ip = (struct ip *)(m0->m_data + ehlen);
17329f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_IP_HDR_SIZE(ip->ip_hl);
17339f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_NOT_FRAGMENT;
17349f55f5f5SRafal Jaworowski 	}
17359f55f5f5SRafal Jaworowski 
17369f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_IP)
17379f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_IP_CSUM;
17389f55f5f5SRafal Jaworowski 
17399f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_TCP)
17409f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_L4_CSUM;
17419f55f5f5SRafal Jaworowski 
17429f55f5f5SRafal Jaworowski 	if (csum_flags & CSUM_UDP)
17439f55f5f5SRafal Jaworowski 		cmd_status |= MGE_TX_GEN_L4_CSUM | MGE_TX_UDP;
17449f55f5f5SRafal Jaworowski 
17459f55f5f5SRafal Jaworowski 	dw->mge_desc->cmd_status |= cmd_status;
17469f55f5f5SRafal Jaworowski }
17479f55f5f5SRafal Jaworowski 
17489f55f5f5SRafal Jaworowski static void
17499f55f5f5SRafal Jaworowski mge_intrs_ctrl(struct mge_softc *sc, int enable)
17509f55f5f5SRafal Jaworowski {
17519f55f5f5SRafal Jaworowski 
17529f55f5f5SRafal Jaworowski 	if (enable) {
17539f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK , MGE_PORT_INT_RXQ0 |
17549f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXTEND | MGE_PORT_INT_RXERRQ0);
17559f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT , MGE_PORT_INT_EXT_TXERR0 |
17569f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXT_RXOR | MGE_PORT_INT_EXT_TXUR |
17579f55f5f5SRafal Jaworowski 		    MGE_PORT_INT_EXT_TXBUF0);
17589f55f5f5SRafal Jaworowski 	} else {
17599f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_INT_CAUSE, 0x0);
17609f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_INT_MASK, 0x0);
17619f55f5f5SRafal Jaworowski 
17629f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE, 0x0);
17639f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, 0x0);
17649f55f5f5SRafal Jaworowski 
17659f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK, 0x0);
17669f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT, 0x0);
17679f55f5f5SRafal Jaworowski 	}
17689f55f5f5SRafal Jaworowski }
17699f55f5f5SRafal Jaworowski 
17709f55f5f5SRafal Jaworowski static uint8_t
17719f55f5f5SRafal Jaworowski mge_crc8(uint8_t *data, int size)
17729f55f5f5SRafal Jaworowski {
17739f55f5f5SRafal Jaworowski 	uint8_t crc = 0;
17749f55f5f5SRafal Jaworowski 	static const uint8_t ct[256] = {
17759f55f5f5SRafal Jaworowski 		0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
17769f55f5f5SRafal Jaworowski 		0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
17779f55f5f5SRafal Jaworowski 		0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
17789f55f5f5SRafal Jaworowski 		0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
17799f55f5f5SRafal Jaworowski 		0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
17809f55f5f5SRafal Jaworowski 		0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
17819f55f5f5SRafal Jaworowski 		0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
17829f55f5f5SRafal Jaworowski 		0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
17839f55f5f5SRafal Jaworowski 		0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
17849f55f5f5SRafal Jaworowski 		0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
17859f55f5f5SRafal Jaworowski 		0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
17869f55f5f5SRafal Jaworowski 		0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
17879f55f5f5SRafal Jaworowski 		0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
17889f55f5f5SRafal Jaworowski 		0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
17899f55f5f5SRafal Jaworowski 		0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
17909f55f5f5SRafal Jaworowski 		0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
17919f55f5f5SRafal Jaworowski 		0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
17929f55f5f5SRafal Jaworowski 		0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
17939f55f5f5SRafal Jaworowski 		0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
17949f55f5f5SRafal Jaworowski 		0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
17959f55f5f5SRafal Jaworowski 		0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
17969f55f5f5SRafal Jaworowski 		0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
17979f55f5f5SRafal Jaworowski 		0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
17989f55f5f5SRafal Jaworowski 		0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
17999f55f5f5SRafal Jaworowski 		0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
18009f55f5f5SRafal Jaworowski 		0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
18019f55f5f5SRafal Jaworowski 		0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
18029f55f5f5SRafal Jaworowski 		0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
18039f55f5f5SRafal Jaworowski 		0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
18049f55f5f5SRafal Jaworowski 		0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
18059f55f5f5SRafal Jaworowski 		0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
18069f55f5f5SRafal Jaworowski 		0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
18079f55f5f5SRafal Jaworowski 	};
18089f55f5f5SRafal Jaworowski 
18099f55f5f5SRafal Jaworowski 	while(size--)
18109f55f5f5SRafal Jaworowski 		crc = ct[crc ^ *(data++)];
18119f55f5f5SRafal Jaworowski 
18129f55f5f5SRafal Jaworowski 	return(crc);
18139f55f5f5SRafal Jaworowski }
18149f55f5f5SRafal Jaworowski 
18159f55f5f5SRafal Jaworowski static void
18169f55f5f5SRafal Jaworowski mge_setup_multicast(struct mge_softc *sc)
18179f55f5f5SRafal Jaworowski {
18189f55f5f5SRafal Jaworowski 	uint8_t special[5] = { 0x01, 0x00, 0x5E, 0x00, 0x00 };
18199f55f5f5SRafal Jaworowski 	uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1;
18209f55f5f5SRafal Jaworowski 	uint32_t smt[MGE_MCAST_REG_NUMBER];
18219f55f5f5SRafal Jaworowski 	uint32_t omt[MGE_MCAST_REG_NUMBER];
18229f55f5f5SRafal Jaworowski 	struct ifnet *ifp = sc->ifp;
18239f55f5f5SRafal Jaworowski 	struct ifmultiaddr *ifma;
18249f55f5f5SRafal Jaworowski 	uint8_t *mac;
18259f55f5f5SRafal Jaworowski 	int i;
18269f55f5f5SRafal Jaworowski 
18279f55f5f5SRafal Jaworowski 	if (ifp->if_flags & IFF_ALLMULTI) {
18289f55f5f5SRafal Jaworowski 		for (i = 0; i < MGE_MCAST_REG_NUMBER; i++)
18299f55f5f5SRafal Jaworowski 			smt[i] = omt[i] = (v << 24) | (v << 16) | (v << 8) | v;
18309f55f5f5SRafal Jaworowski 	} else {
18319f55f5f5SRafal Jaworowski 		memset(smt, 0, sizeof(smt));
18329f55f5f5SRafal Jaworowski 		memset(omt, 0, sizeof(omt));
18339f55f5f5SRafal Jaworowski 
1834eb956cd0SRobert Watson 		if_maddr_rlock(ifp);
18359f55f5f5SRafal Jaworowski 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
18369f55f5f5SRafal Jaworowski 			if (ifma->ifma_addr->sa_family != AF_LINK)
18379f55f5f5SRafal Jaworowski 				continue;
18389f55f5f5SRafal Jaworowski 
18399f55f5f5SRafal Jaworowski 			mac = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
18409f55f5f5SRafal Jaworowski 			if (memcmp(mac, special, sizeof(special)) == 0) {
18419f55f5f5SRafal Jaworowski 				i = mac[5];
18429f55f5f5SRafal Jaworowski 				smt[i >> 2] |= v << ((i & 0x03) << 3);
18439f55f5f5SRafal Jaworowski 			} else {
18449f55f5f5SRafal Jaworowski 				i = mge_crc8(mac, ETHER_ADDR_LEN);
18459f55f5f5SRafal Jaworowski 				omt[i >> 2] |= v << ((i & 0x03) << 3);
18469f55f5f5SRafal Jaworowski 			}
18479f55f5f5SRafal Jaworowski 		}
1848eb956cd0SRobert Watson 		if_maddr_runlock(ifp);
18499f55f5f5SRafal Jaworowski 	}
18509f55f5f5SRafal Jaworowski 
18519f55f5f5SRafal Jaworowski 	for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
18529f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), smt[i]);
18539f55f5f5SRafal Jaworowski 		MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), omt[i]);
18549f55f5f5SRafal Jaworowski 	}
18559f55f5f5SRafal Jaworowski }
18569f55f5f5SRafal Jaworowski 
18579f55f5f5SRafal Jaworowski static void
18589f55f5f5SRafal Jaworowski mge_set_rxic(struct mge_softc *sc)
18599f55f5f5SRafal Jaworowski {
18609f55f5f5SRafal Jaworowski 	uint32_t reg;
18619f55f5f5SRafal Jaworowski 
18628e1dc58eSRafal Jaworowski 	if (sc->rx_ic_time > sc->mge_rx_ipg_max)
18638e1dc58eSRafal Jaworowski 		sc->rx_ic_time = sc->mge_rx_ipg_max;
18649f55f5f5SRafal Jaworowski 
18659f55f5f5SRafal Jaworowski 	reg = MGE_READ(sc, MGE_SDMA_CONFIG);
18668e1dc58eSRafal Jaworowski 	reg &= ~mge_rx_ipg(sc->mge_rx_ipg_max, sc->mge_ver);
18678e1dc58eSRafal Jaworowski 	reg |= mge_rx_ipg(sc->rx_ic_time, sc->mge_ver);
18689f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_SDMA_CONFIG, reg);
18699f55f5f5SRafal Jaworowski }
18709f55f5f5SRafal Jaworowski 
18719f55f5f5SRafal Jaworowski static void
18729f55f5f5SRafal Jaworowski mge_set_txic(struct mge_softc *sc)
18739f55f5f5SRafal Jaworowski {
18749f55f5f5SRafal Jaworowski 	uint32_t reg;
18759f55f5f5SRafal Jaworowski 
18768e1dc58eSRafal Jaworowski 	if (sc->tx_ic_time > sc->mge_tfut_ipg_max)
18778e1dc58eSRafal Jaworowski 		sc->tx_ic_time = sc->mge_tfut_ipg_max;
18789f55f5f5SRafal Jaworowski 
18799f55f5f5SRafal Jaworowski 	reg = MGE_READ(sc, MGE_TX_FIFO_URGENT_TRSH);
18808e1dc58eSRafal Jaworowski 	reg &= ~mge_tfut_ipg(sc->mge_tfut_ipg_max, sc->mge_ver);
18818e1dc58eSRafal Jaworowski 	reg |= mge_tfut_ipg(sc->tx_ic_time, sc->mge_ver);
18829f55f5f5SRafal Jaworowski 	MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, reg);
18839f55f5f5SRafal Jaworowski }
18849f55f5f5SRafal Jaworowski 
18859f55f5f5SRafal Jaworowski static int
18869f55f5f5SRafal Jaworowski mge_sysctl_ic(SYSCTL_HANDLER_ARGS)
18879f55f5f5SRafal Jaworowski {
18889f55f5f5SRafal Jaworowski 	struct mge_softc *sc = (struct mge_softc *)arg1;
18898e1dc58eSRafal Jaworowski 	uint32_t time;
18909f55f5f5SRafal Jaworowski 	int error;
18919f55f5f5SRafal Jaworowski 
18928e1dc58eSRafal Jaworowski 	time = (arg2 == MGE_IC_RX) ? sc->rx_ic_time : sc->tx_ic_time;
18939f55f5f5SRafal Jaworowski 	error = sysctl_handle_int(oidp, &time, 0, req);
18949f55f5f5SRafal Jaworowski 	if (error != 0)
18959f55f5f5SRafal Jaworowski 		return(error);
18969f55f5f5SRafal Jaworowski 
18979f55f5f5SRafal Jaworowski 	MGE_GLOBAL_LOCK(sc);
18989f55f5f5SRafal Jaworowski 	if (arg2 == MGE_IC_RX) {
18999f55f5f5SRafal Jaworowski 		sc->rx_ic_time = time;
19009f55f5f5SRafal Jaworowski 		mge_set_rxic(sc);
19019f55f5f5SRafal Jaworowski 	} else {
19029f55f5f5SRafal Jaworowski 		sc->tx_ic_time = time;
19039f55f5f5SRafal Jaworowski 		mge_set_txic(sc);
19049f55f5f5SRafal Jaworowski 	}
19059f55f5f5SRafal Jaworowski 	MGE_GLOBAL_UNLOCK(sc);
19069f55f5f5SRafal Jaworowski 
19079f55f5f5SRafal Jaworowski 	return(0);
19089f55f5f5SRafal Jaworowski }
19099f55f5f5SRafal Jaworowski 
19109f55f5f5SRafal Jaworowski static void
19119f55f5f5SRafal Jaworowski mge_add_sysctls(struct mge_softc *sc)
19129f55f5f5SRafal Jaworowski {
19139f55f5f5SRafal Jaworowski 	struct sysctl_ctx_list *ctx;
19149f55f5f5SRafal Jaworowski 	struct sysctl_oid_list *children;
19159f55f5f5SRafal Jaworowski 	struct sysctl_oid *tree;
19169f55f5f5SRafal Jaworowski 
19179f55f5f5SRafal Jaworowski 	ctx = device_get_sysctl_ctx(sc->dev);
19189f55f5f5SRafal Jaworowski 	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
19199f55f5f5SRafal Jaworowski 	tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "int_coal",
19209f55f5f5SRafal Jaworowski 	    CTLFLAG_RD, 0, "MGE Interrupts coalescing");
19219f55f5f5SRafal Jaworowski 	children = SYSCTL_CHILDREN(tree);
19229f55f5f5SRafal Jaworowski 
19239f55f5f5SRafal Jaworowski 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_time",
19249f55f5f5SRafal Jaworowski 	    CTLTYPE_UINT | CTLFLAG_RW, sc, MGE_IC_RX, mge_sysctl_ic,
19259f55f5f5SRafal Jaworowski 	    "I", "IC RX time threshold");
19269f55f5f5SRafal Jaworowski 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_time",
19279f55f5f5SRafal Jaworowski 	    CTLTYPE_UINT | CTLFLAG_RW, sc, MGE_IC_TX, mge_sysctl_ic,
19289f55f5f5SRafal Jaworowski 	    "I", "IC TX time threshold");
19299f55f5f5SRafal Jaworowski }
1930