xref: /freebsd/sys/arm64/broadcom/genet/if_genet.c (revision 349eddbd07d112698c5c6e51a3e8126759f651a6)
12cd0c529SMike Karels /*-
22cd0c529SMike Karels  * Copyright (c) 2020 Michael J Karels
32cd0c529SMike Karels  * Copyright (c) 2016, 2020 Jared McNeill <jmcneill@invisible.ca>
42cd0c529SMike Karels  *
52cd0c529SMike Karels  * Redistribution and use in source and binary forms, with or without
62cd0c529SMike Karels  * modification, are permitted provided that the following conditions
72cd0c529SMike Karels  * are met:
82cd0c529SMike Karels  * 1. Redistributions of source code must retain the above copyright
92cd0c529SMike Karels  *    notice, this list of conditions and the following disclaimer.
102cd0c529SMike Karels  * 2. Redistributions in binary form must reproduce the above copyright
112cd0c529SMike Karels  *    notice, this list of conditions and the following disclaimer in the
122cd0c529SMike Karels  *    documentation and/or other materials provided with the distribution.
132cd0c529SMike Karels  *
142cd0c529SMike Karels  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
152cd0c529SMike Karels  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
162cd0c529SMike Karels  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
172cd0c529SMike Karels  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
182cd0c529SMike Karels  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
192cd0c529SMike Karels  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
202cd0c529SMike Karels  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
212cd0c529SMike Karels  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
222cd0c529SMike Karels  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232cd0c529SMike Karels  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242cd0c529SMike Karels  * SUCH DAMAGE.
252cd0c529SMike Karels  *
262cd0c529SMike Karels  * $FreeBSD$
272cd0c529SMike Karels  */
282cd0c529SMike Karels 
292cd0c529SMike Karels /*
302cd0c529SMike Karels  * RPi4 (BCM 2711) Gigabit Ethernet ("GENET") controller
312cd0c529SMike Karels  *
322cd0c529SMike Karels  * This driver is derived in large part from bcmgenet.c from NetBSD by
332cd0c529SMike Karels  * Jared McNeill.  Parts of the structure and other common code in
342cd0c529SMike Karels  * this driver have been copied from if_awg.c for the Allwinner EMAC,
352cd0c529SMike Karels  * also by Jared McNeill.
362cd0c529SMike Karels  */
372cd0c529SMike Karels 
382cd0c529SMike Karels #include "opt_device_polling.h"
392cd0c529SMike Karels 
402cd0c529SMike Karels #include <sys/cdefs.h>
412cd0c529SMike Karels __FBSDID("$FreeBSD$");
422cd0c529SMike Karels 
432cd0c529SMike Karels #include <sys/param.h>
442cd0c529SMike Karels #include <sys/systm.h>
452cd0c529SMike Karels #include <sys/bus.h>
462cd0c529SMike Karels #include <sys/rman.h>
472cd0c529SMike Karels #include <sys/kernel.h>
482cd0c529SMike Karels #include <sys/endian.h>
492cd0c529SMike Karels #include <sys/mbuf.h>
502cd0c529SMike Karels #include <sys/socket.h>
512cd0c529SMike Karels #include <sys/sockio.h>
522cd0c529SMike Karels #include <sys/module.h>
532cd0c529SMike Karels #include <sys/taskqueue.h>
542cd0c529SMike Karels #include <sys/gpio.h>
552cd0c529SMike Karels 
562cd0c529SMike Karels #include <net/bpf.h>
572cd0c529SMike Karels #include <net/if.h>
582cd0c529SMike Karels #include <net/ethernet.h>
592cd0c529SMike Karels #include <net/if_dl.h>
602cd0c529SMike Karels #include <net/if_media.h>
612cd0c529SMike Karels #include <net/if_types.h>
622cd0c529SMike Karels #include <net/if_var.h>
632cd0c529SMike Karels 
642cd0c529SMike Karels #include <machine/bus.h>
652cd0c529SMike Karels 
662cd0c529SMike Karels #include <dev/ofw/ofw_bus.h>
672cd0c529SMike Karels #include <dev/ofw/ofw_bus_subr.h>
682cd0c529SMike Karels 
692cd0c529SMike Karels #define __BIT(_x)	(1 << (_x))
702cd0c529SMike Karels #include "if_genetreg.h"
712cd0c529SMike Karels 
722cd0c529SMike Karels #include <dev/mii/mii.h>
732cd0c529SMike Karels #include <dev/mii/miivar.h>
742cd0c529SMike Karels #include <dev/mii/mii_fdt.h>
752cd0c529SMike Karels 
762cd0c529SMike Karels #include <netinet/in.h>
772cd0c529SMike Karels #include <netinet/ip.h>
782cd0c529SMike Karels #include <netinet/ip6.h>
7951cefda1SMike Karels #define ICMPV6_HACK	/* workaround for chip issue */
8051cefda1SMike Karels #ifdef ICMPV6_HACK
8151cefda1SMike Karels #include <netinet/icmp6.h>
8251cefda1SMike Karels #endif
832cd0c529SMike Karels 
842cd0c529SMike Karels #include "syscon_if.h"
852cd0c529SMike Karels #include "miibus_if.h"
862cd0c529SMike Karels #include "gpio_if.h"
872cd0c529SMike Karels 
882cd0c529SMike Karels #define	RD4(sc, reg)		bus_read_4((sc)->res[_RES_MAC], (reg))
892cd0c529SMike Karels #define	WR4(sc, reg, val)	bus_write_4((sc)->res[_RES_MAC], (reg), (val))
902cd0c529SMike Karels 
912cd0c529SMike Karels #define	GEN_LOCK(sc)		mtx_lock(&(sc)->mtx)
922cd0c529SMike Karels #define	GEN_UNLOCK(sc)		mtx_unlock(&(sc)->mtx)
932cd0c529SMike Karels #define	GEN_ASSERT_LOCKED(sc)	mtx_assert(&(sc)->mtx, MA_OWNED)
942cd0c529SMike Karels #define	GEN_ASSERT_UNLOCKED(sc)	mtx_assert(&(sc)->mtx, MA_NOTOWNED)
952cd0c529SMike Karels 
962cd0c529SMike Karels #define	TX_DESC_COUNT		GENET_DMA_DESC_COUNT
972cd0c529SMike Karels #define	RX_DESC_COUNT		GENET_DMA_DESC_COUNT
982cd0c529SMike Karels 
992cd0c529SMike Karels #define	TX_NEXT(n, count)		(((n) + 1) & ((count) - 1))
1002cd0c529SMike Karels #define	RX_NEXT(n, count)		(((n) + 1) & ((count) - 1))
1012cd0c529SMike Karels 
1022cd0c529SMike Karels 
1032cd0c529SMike Karels #define	TX_MAX_SEGS		20
1042cd0c529SMike Karels 
1052cd0c529SMike Karels /* Maximum number of mbufs to send to if_input */
1062cd0c529SMike Karels static int gen_rx_batch = 16 /* RX_BATCH_DEFAULT */;
1072cd0c529SMike Karels TUNABLE_INT("hw.gen.rx_batch", &gen_rx_batch);
1082cd0c529SMike Karels 
1092cd0c529SMike Karels static struct ofw_compat_data compat_data[] = {
1102cd0c529SMike Karels 	{ "brcm,genet-v1",		1 },
1112cd0c529SMike Karels 	{ "brcm,genet-v2",		2 },
1122cd0c529SMike Karels 	{ "brcm,genet-v3",		3 },
1132cd0c529SMike Karels 	{ "brcm,genet-v4",		4 },
1142cd0c529SMike Karels 	{ "brcm,genet-v5",		5 },
1152cd0c529SMike Karels 	{ NULL,				0 }
1162cd0c529SMike Karels };
1172cd0c529SMike Karels 
1182cd0c529SMike Karels enum {
1192cd0c529SMike Karels 	_RES_MAC,		/* what to call this? */
1202cd0c529SMike Karels 	_RES_IRQ1,
1212cd0c529SMike Karels 	_RES_IRQ2,
1222cd0c529SMike Karels 	_RES_NITEMS
1232cd0c529SMike Karels };
1242cd0c529SMike Karels 
1252cd0c529SMike Karels static struct resource_spec gen_spec[] = {
1262cd0c529SMike Karels 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
1272cd0c529SMike Karels 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
1282cd0c529SMike Karels 	{ SYS_RES_IRQ,		1,	RF_ACTIVE },
1292cd0c529SMike Karels 	{ -1, 0 }
1302cd0c529SMike Karels };
1312cd0c529SMike Karels 
1322cd0c529SMike Karels /* structure per ring entry */
1332cd0c529SMike Karels struct gen_ring_ent {
1342cd0c529SMike Karels 	bus_dmamap_t		map;
1352cd0c529SMike Karels 	struct mbuf		*mbuf;
1362cd0c529SMike Karels };
1372cd0c529SMike Karels 
1382cd0c529SMike Karels struct tx_queue {
1392cd0c529SMike Karels 	int			hwindex;		/* hardware index */
1402cd0c529SMike Karels 	int			nentries;
1412cd0c529SMike Karels 	u_int			queued;			/* or avail? */
1422cd0c529SMike Karels 	u_int			cur;
1432cd0c529SMike Karels 	u_int			next;
1442cd0c529SMike Karels 	u_int			prod_idx;
1452cd0c529SMike Karels 	u_int			cons_idx;
1462cd0c529SMike Karels 	struct gen_ring_ent	*entries;
1472cd0c529SMike Karels };
1482cd0c529SMike Karels 
1492cd0c529SMike Karels struct rx_queue {
1502cd0c529SMike Karels 	int			hwindex;		/* hardware index */
1512cd0c529SMike Karels 	int			nentries;
1522cd0c529SMike Karels 	u_int			cur;
1532cd0c529SMike Karels 	u_int			prod_idx;
1542cd0c529SMike Karels 	u_int			cons_idx;
1552cd0c529SMike Karels 	struct gen_ring_ent	*entries;
1562cd0c529SMike Karels };
1572cd0c529SMike Karels 
1582cd0c529SMike Karels struct gen_softc {
1592cd0c529SMike Karels 	struct resource		*res[_RES_NITEMS];
1602cd0c529SMike Karels 	struct mtx		mtx;
1612cd0c529SMike Karels 	if_t			ifp;
1622cd0c529SMike Karels 	device_t		dev;
1632cd0c529SMike Karels 	device_t		miibus;
1642cd0c529SMike Karels 	mii_contype_t		phy_mode;
1652cd0c529SMike Karels 
1662cd0c529SMike Karels 	struct callout		stat_ch;
1672cd0c529SMike Karels 	struct task		link_task;
1682cd0c529SMike Karels 	void			*ih;
1692cd0c529SMike Karels 	void			*ih2;
1702cd0c529SMike Karels 	int			type;
1712cd0c529SMike Karels 	int			if_flags;
1722cd0c529SMike Karels 	int			link;
1732cd0c529SMike Karels 	bus_dma_tag_t		tx_buf_tag;
1742cd0c529SMike Karels 	/*
1752cd0c529SMike Karels 	 * The genet chip has multiple queues for transmit and receive.
1762cd0c529SMike Karels 	 * This driver uses only one (queue 16, the default), but is cast
1772cd0c529SMike Karels 	 * with multiple rings.  The additional rings are used for different
1782cd0c529SMike Karels 	 * priorities.
1792cd0c529SMike Karels 	 */
1802cd0c529SMike Karels #define DEF_TXQUEUE	0
1812cd0c529SMike Karels #define NTXQUEUE	1
1822cd0c529SMike Karels 	struct tx_queue		tx_queue[NTXQUEUE];
1832cd0c529SMike Karels 	struct gen_ring_ent	tx_ring_ent[TX_DESC_COUNT];  /* ring entries */
1842cd0c529SMike Karels 
1852cd0c529SMike Karels 	bus_dma_tag_t		rx_buf_tag;
1862cd0c529SMike Karels #define DEF_RXQUEUE	0
1872cd0c529SMike Karels #define NRXQUEUE	1
1882cd0c529SMike Karels 	struct rx_queue		rx_queue[NRXQUEUE];
1892cd0c529SMike Karels 	struct gen_ring_ent	rx_ring_ent[RX_DESC_COUNT];  /* ring entries */
1902cd0c529SMike Karels };
1912cd0c529SMike Karels 
1922cd0c529SMike Karels static void gen_init(void *softc);
1932cd0c529SMike Karels static void gen_start(if_t ifp);
1942cd0c529SMike Karels static void gen_destroy(struct gen_softc *sc);
1952cd0c529SMike Karels static int gen_encap(struct gen_softc *sc, struct mbuf **mp);
1962cd0c529SMike Karels static int gen_parse_tx(struct mbuf *m, int csum_flags);
1972cd0c529SMike Karels static int gen_ioctl(if_t ifp, u_long cmd, caddr_t data);
1982cd0c529SMike Karels static int gen_get_phy_mode(device_t dev);
1992cd0c529SMike Karels static bool gen_get_eaddr(device_t dev, struct ether_addr *eaddr);
2002cd0c529SMike Karels static void gen_set_enaddr(struct gen_softc *sc);
2012cd0c529SMike Karels static void gen_setup_rxfilter(struct gen_softc *sc);
2022cd0c529SMike Karels static void gen_reset(struct gen_softc *sc);
2032cd0c529SMike Karels static void gen_enable(struct gen_softc *sc);
2042cd0c529SMike Karels static void gen_dma_disable(device_t dev);
2052cd0c529SMike Karels static int gen_bus_dma_init(struct gen_softc *sc);
2062cd0c529SMike Karels static void gen_bus_dma_teardown(struct gen_softc *sc);
2072cd0c529SMike Karels static void gen_enable_intr(struct gen_softc *sc);
2082cd0c529SMike Karels static void gen_init_txrings(struct gen_softc *sc);
2092cd0c529SMike Karels static void gen_init_rxrings(struct gen_softc *sc);
2102cd0c529SMike Karels static void gen_intr(void *softc);
2112cd0c529SMike Karels static int gen_rxintr(struct gen_softc *sc, struct rx_queue *q);
2122cd0c529SMike Karels static void gen_txintr(struct gen_softc *sc, struct tx_queue *q);
2132cd0c529SMike Karels static void gen_intr2(void *softc);
2142cd0c529SMike Karels static int gen_newbuf_rx(struct gen_softc *sc, struct rx_queue *q, int index);
2152cd0c529SMike Karels static int gen_mapbuf_rx(struct gen_softc *sc, struct rx_queue *q, int index,
2162cd0c529SMike Karels     struct mbuf *m);
2172cd0c529SMike Karels static void gen_link_task(void *arg, int pending);
2182cd0c529SMike Karels static void gen_media_status(if_t ifp, struct ifmediareq *ifmr);
2192cd0c529SMike Karels static int gen_media_change(if_t ifp);
2202cd0c529SMike Karels static void gen_tick(void *softc);
2212cd0c529SMike Karels 
2222cd0c529SMike Karels static int
2232cd0c529SMike Karels gen_probe(device_t dev)
2242cd0c529SMike Karels {
2252cd0c529SMike Karels 	if (!ofw_bus_status_okay(dev))
2262cd0c529SMike Karels 		return (ENXIO);
2272cd0c529SMike Karels 
2282cd0c529SMike Karels 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
2292cd0c529SMike Karels 		return (ENXIO);
2302cd0c529SMike Karels 
2312cd0c529SMike Karels 	device_set_desc(dev, "RPi4 Gigabit Ethernet");
2322cd0c529SMike Karels 	return (BUS_PROBE_DEFAULT);
2332cd0c529SMike Karels }
2342cd0c529SMike Karels 
2352cd0c529SMike Karels static int
2362cd0c529SMike Karels gen_attach(device_t dev)
2372cd0c529SMike Karels {
2382cd0c529SMike Karels 	struct ether_addr eaddr;
2392cd0c529SMike Karels 	struct gen_softc *sc;
240*349eddbdSMike Karels 	int major, minor, error, mii_flags;
2412cd0c529SMike Karels 	bool eaddr_found;
2422cd0c529SMike Karels 
2432cd0c529SMike Karels 	sc = device_get_softc(dev);
2442cd0c529SMike Karels 	sc->dev = dev;
2452cd0c529SMike Karels 	sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
2462cd0c529SMike Karels 
2472cd0c529SMike Karels 	if (bus_alloc_resources(dev, gen_spec, sc->res) != 0) {
2482cd0c529SMike Karels 		device_printf(dev, "cannot allocate resources for device\n");
2492cd0c529SMike Karels 		error = ENXIO;
2502cd0c529SMike Karels 		goto fail;
2512cd0c529SMike Karels 	}
2522cd0c529SMike Karels 
2532cd0c529SMike Karels 	major = (RD4(sc, GENET_SYS_REV_CTRL) & REV_MAJOR) >> REV_MAJOR_SHIFT;
2542cd0c529SMike Karels 	if (major != REV_MAJOR_V5) {
2552cd0c529SMike Karels 		device_printf(dev, "version %d is not supported\n", major);
2562cd0c529SMike Karels 		error = ENXIO;
2572cd0c529SMike Karels 		goto fail;
2582cd0c529SMike Karels 	}
2592cd0c529SMike Karels 	minor = (RD4(sc, GENET_SYS_REV_CTRL) & REV_MINOR) >> REV_MINOR_SHIFT;
2602cd0c529SMike Karels 	device_printf(dev, "GENET version 5.%d phy 0x%04x\n", minor,
2612cd0c529SMike Karels 		RD4(sc, GENET_SYS_REV_CTRL) & REV_PHY);
2622cd0c529SMike Karels 
2632cd0c529SMike Karels 	mtx_init(&sc->mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF);
2642cd0c529SMike Karels 	callout_init_mtx(&sc->stat_ch, &sc->mtx, 0);
2652cd0c529SMike Karels 	TASK_INIT(&sc->link_task, 0, gen_link_task, sc);
2662cd0c529SMike Karels 
2672cd0c529SMike Karels 	error = gen_get_phy_mode(dev);
2682cd0c529SMike Karels 	if (error != 0)
2692cd0c529SMike Karels 		goto fail;
2702cd0c529SMike Karels 
2712cd0c529SMike Karels 	bzero(&eaddr, sizeof(eaddr));
2722cd0c529SMike Karels 	eaddr_found = gen_get_eaddr(dev, &eaddr);
2732cd0c529SMike Karels 
2742cd0c529SMike Karels 	/* reset core */
2752cd0c529SMike Karels 	gen_reset(sc);
2762cd0c529SMike Karels 
2772cd0c529SMike Karels 	gen_dma_disable(dev);
2782cd0c529SMike Karels 
2792cd0c529SMike Karels 	/* Setup DMA */
2802cd0c529SMike Karels 	error = gen_bus_dma_init(sc);
2812cd0c529SMike Karels 	if (error != 0) {
2822cd0c529SMike Karels 		device_printf(dev, "cannot setup bus dma\n");
2832cd0c529SMike Karels 		goto fail;
2842cd0c529SMike Karels 	}
2852cd0c529SMike Karels 
2862cd0c529SMike Karels 	/* Install interrupt handlers */
2872cd0c529SMike Karels 	error = bus_setup_intr(dev, sc->res[_RES_IRQ1],
2882cd0c529SMike Karels 	    INTR_TYPE_NET | INTR_MPSAFE, NULL, gen_intr, sc, &sc->ih);
2892cd0c529SMike Karels 	if (error != 0) {
2902cd0c529SMike Karels 		device_printf(dev, "cannot setup interrupt handler1\n");
2912cd0c529SMike Karels 		goto fail;
2922cd0c529SMike Karels 	}
2932cd0c529SMike Karels 
2942cd0c529SMike Karels 	error = bus_setup_intr(dev, sc->res[_RES_IRQ2],
2952cd0c529SMike Karels 	    INTR_TYPE_NET | INTR_MPSAFE, NULL, gen_intr2, sc, &sc->ih2);
2962cd0c529SMike Karels 	if (error != 0) {
2972cd0c529SMike Karels 		device_printf(dev, "cannot setup interrupt handler2\n");
2982cd0c529SMike Karels 		goto fail;
2992cd0c529SMike Karels 	}
3002cd0c529SMike Karels 
3012cd0c529SMike Karels 	/* Setup ethernet interface */
3022cd0c529SMike Karels 	sc->ifp = if_alloc(IFT_ETHER);
3032cd0c529SMike Karels 	if_setsoftc(sc->ifp, sc);
3042cd0c529SMike Karels 	if_initname(sc->ifp, device_get_name(dev), device_get_unit(dev));
3052cd0c529SMike Karels 	if_setflags(sc->ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
3062cd0c529SMike Karels 	if_setstartfn(sc->ifp, gen_start);
3072cd0c529SMike Karels 	if_setioctlfn(sc->ifp, gen_ioctl);
3082cd0c529SMike Karels 	if_setinitfn(sc->ifp, gen_init);
3092cd0c529SMike Karels 	if_setsendqlen(sc->ifp, TX_DESC_COUNT - 1);
3102cd0c529SMike Karels 	if_setsendqready(sc->ifp);
3112cd0c529SMike Karels #define GEN_CSUM_FEATURES	(CSUM_UDP | CSUM_TCP)
3122cd0c529SMike Karels 	if_sethwassist(sc->ifp, GEN_CSUM_FEATURES);
3132cd0c529SMike Karels 	if_setcapabilities(sc->ifp, IFCAP_VLAN_MTU | IFCAP_HWCSUM |
3142cd0c529SMike Karels 	    IFCAP_HWCSUM_IPV6);
3152cd0c529SMike Karels 	if_setcapenable(sc->ifp, if_getcapabilities(sc->ifp));
3162cd0c529SMike Karels 
3172cd0c529SMike Karels 	/* Attach MII driver */
318*349eddbdSMike Karels 	mii_flags = 0;
319*349eddbdSMike Karels 	switch (sc->phy_mode)
320*349eddbdSMike Karels 	{
321*349eddbdSMike Karels 	case MII_CONTYPE_RGMII_ID:
322*349eddbdSMike Karels 		mii_flags |= MIIF_RX_DELAY | MIIF_TX_DELAY;
323*349eddbdSMike Karels 		break;
324*349eddbdSMike Karels 	case MII_CONTYPE_RGMII_RXID:
325*349eddbdSMike Karels 		mii_flags |= MIIF_RX_DELAY;
326*349eddbdSMike Karels 		break;
327*349eddbdSMike Karels 	case MII_CONTYPE_RGMII_TXID:
328*349eddbdSMike Karels 		mii_flags |= MIIF_TX_DELAY;
329*349eddbdSMike Karels 		break;
330*349eddbdSMike Karels 	default:
331*349eddbdSMike Karels 		break;
332*349eddbdSMike Karels 	}
3332cd0c529SMike Karels 	error = mii_attach(dev, &sc->miibus, sc->ifp, gen_media_change,
3342cd0c529SMike Karels 	    gen_media_status, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY,
335*349eddbdSMike Karels 	    mii_flags);
3362cd0c529SMike Karels 	if (error != 0) {
3372cd0c529SMike Karels 		device_printf(dev, "cannot attach PHY\n");
3382cd0c529SMike Karels 		goto fail;
3392cd0c529SMike Karels 	}
3402cd0c529SMike Karels 
3412cd0c529SMike Karels 	/* If address was not found, create one based on the hostid and name. */
3422cd0c529SMike Karels 	if (eaddr_found == 0)
3432cd0c529SMike Karels 		ether_gen_addr(sc->ifp, &eaddr);
3442cd0c529SMike Karels 	/* Attach ethernet interface */
3452cd0c529SMike Karels 	ether_ifattach(sc->ifp, eaddr.octet);
3462cd0c529SMike Karels 
3472cd0c529SMike Karels fail:
3482cd0c529SMike Karels 	if (error)
3492cd0c529SMike Karels 		gen_destroy(sc);
3502cd0c529SMike Karels 	return (error);
3512cd0c529SMike Karels }
3522cd0c529SMike Karels 
3532cd0c529SMike Karels /* Free resources after failed attach.  This is not a complete detach. */
3542cd0c529SMike Karels static void
3552cd0c529SMike Karels gen_destroy(struct gen_softc *sc)
3562cd0c529SMike Karels {
3572cd0c529SMike Karels 
3582cd0c529SMike Karels 	if (sc->miibus) {	/* can't happen */
3592cd0c529SMike Karels 		device_delete_child(sc->dev, sc->miibus);
3602cd0c529SMike Karels 		sc->miibus = NULL;
3612cd0c529SMike Karels 	}
3622cd0c529SMike Karels 	bus_teardown_intr(sc->dev, sc->res[_RES_IRQ1], sc->ih);
3632cd0c529SMike Karels 	bus_teardown_intr(sc->dev, sc->res[_RES_IRQ2], sc->ih2);
3642cd0c529SMike Karels 	gen_bus_dma_teardown(sc);
3652cd0c529SMike Karels 	callout_drain(&sc->stat_ch);
3662cd0c529SMike Karels 	if (mtx_initialized(&sc->mtx))
3672cd0c529SMike Karels 		mtx_destroy(&sc->mtx);
3682cd0c529SMike Karels 	bus_release_resources(sc->dev, gen_spec, sc->res);
3692cd0c529SMike Karels 	if (sc->ifp != NULL) {
3702cd0c529SMike Karels 		if_free(sc->ifp);
3712cd0c529SMike Karels 		sc->ifp = NULL;
3722cd0c529SMike Karels 	}
3732cd0c529SMike Karels }
3742cd0c529SMike Karels 
3752cd0c529SMike Karels static int
3762cd0c529SMike Karels gen_get_phy_mode(device_t dev)
3772cd0c529SMike Karels {
3782cd0c529SMike Karels 	struct gen_softc *sc;
3792cd0c529SMike Karels 	phandle_t node;
3802cd0c529SMike Karels 	mii_contype_t type;
3812cd0c529SMike Karels 	int error = 0;
3822cd0c529SMike Karels 
3832cd0c529SMike Karels 	sc = device_get_softc(dev);
3842cd0c529SMike Karels 	node = ofw_bus_get_node(dev);
3852cd0c529SMike Karels 	type = mii_fdt_get_contype(node);
3862cd0c529SMike Karels 
3872cd0c529SMike Karels 	switch (type) {
3882cd0c529SMike Karels 	case MII_CONTYPE_RGMII:
389*349eddbdSMike Karels 	case MII_CONTYPE_RGMII_ID:
3902cd0c529SMike Karels 	case MII_CONTYPE_RGMII_RXID:
3912cd0c529SMike Karels 	case MII_CONTYPE_RGMII_TXID:
3922cd0c529SMike Karels 		sc->phy_mode = type;
3932cd0c529SMike Karels 		break;
3942cd0c529SMike Karels 	default:
3952cd0c529SMike Karels 		device_printf(dev, "unknown phy-mode '%s'\n",
3962cd0c529SMike Karels 		    mii_fdt_contype_to_name(type));
3972cd0c529SMike Karels 		error = ENXIO;
3982cd0c529SMike Karels 		break;
3992cd0c529SMike Karels 	}
4002cd0c529SMike Karels 
4012cd0c529SMike Karels 	return (error);
4022cd0c529SMike Karels }
4032cd0c529SMike Karels 
4042cd0c529SMike Karels static bool
4052cd0c529SMike Karels gen_get_eaddr(device_t dev, struct ether_addr *eaddr)
4062cd0c529SMike Karels {
4072cd0c529SMike Karels 	struct gen_softc *sc;
4082cd0c529SMike Karels 	uint32_t maclo, machi, val;
4092cd0c529SMike Karels 	phandle_t node;
4102cd0c529SMike Karels 
4112cd0c529SMike Karels 	sc = device_get_softc(dev);
4122cd0c529SMike Karels 
4132cd0c529SMike Karels 	node = ofw_bus_get_node(dev);
4142cd0c529SMike Karels 	if (OF_getprop(node, "mac-address", eaddr->octet,
4152cd0c529SMike Karels 	    ETHER_ADDR_LEN) != -1 ||
4162cd0c529SMike Karels 	    OF_getprop(node, "local-mac-address", eaddr->octet,
4172cd0c529SMike Karels 	    ETHER_ADDR_LEN) != -1 ||
4182cd0c529SMike Karels 	    OF_getprop(node, "address", eaddr->octet, ETHER_ADDR_LEN) != -1)
4192cd0c529SMike Karels 		return (true);
4202cd0c529SMike Karels 
4212cd0c529SMike Karels 	device_printf(dev, "No Ethernet address found in fdt!\n");
4222cd0c529SMike Karels 	maclo = machi = 0;
4232cd0c529SMike Karels 
4242cd0c529SMike Karels 	val = RD4(sc, GENET_SYS_RBUF_FLUSH_CTRL);
4252cd0c529SMike Karels 	if ((val & GENET_SYS_RBUF_FLUSH_RESET) == 0) {
4262cd0c529SMike Karels 		maclo = htobe32(RD4(sc, GENET_UMAC_MAC0));
4272cd0c529SMike Karels 		machi = htobe16(RD4(sc, GENET_UMAC_MAC1) & 0xffff);
4282cd0c529SMike Karels 	}
4292cd0c529SMike Karels 
4302cd0c529SMike Karels 	if (maclo == 0 && machi == 0) {
4312cd0c529SMike Karels 		if (bootverbose)
4322cd0c529SMike Karels 			device_printf(dev,
4332cd0c529SMike Karels 			    "No Ethernet address found in controller\n");
4342cd0c529SMike Karels 		return (false);
4352cd0c529SMike Karels 	} else {
4362cd0c529SMike Karels 		eaddr->octet[0] = maclo & 0xff;
4372cd0c529SMike Karels 		eaddr->octet[1] = (maclo >> 8) & 0xff;
4382cd0c529SMike Karels 		eaddr->octet[2] = (maclo >> 16) & 0xff;
4392cd0c529SMike Karels 		eaddr->octet[3] = (maclo >> 24) & 0xff;
4402cd0c529SMike Karels 		eaddr->octet[4] = machi & 0xff;
4412cd0c529SMike Karels 		eaddr->octet[5] = (machi >> 8) & 0xff;
4422cd0c529SMike Karels 		return (true);
4432cd0c529SMike Karels 	}
4442cd0c529SMike Karels }
4452cd0c529SMike Karels 
4462cd0c529SMike Karels static void
4472cd0c529SMike Karels gen_reset(struct gen_softc *sc)
4482cd0c529SMike Karels {
4492cd0c529SMike Karels 	uint32_t val;
4502cd0c529SMike Karels 
4512cd0c529SMike Karels 	val = RD4(sc, GENET_SYS_RBUF_FLUSH_CTRL);
4522cd0c529SMike Karels 	val |= GENET_SYS_RBUF_FLUSH_RESET;
4532cd0c529SMike Karels 	WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, val);
4542cd0c529SMike Karels 	DELAY(10);
4552cd0c529SMike Karels 
4562cd0c529SMike Karels 	val &= ~GENET_SYS_RBUF_FLUSH_RESET;
4572cd0c529SMike Karels 	WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, val);
4582cd0c529SMike Karels 	DELAY(10);
4592cd0c529SMike Karels 
4602cd0c529SMike Karels 	WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, 0);
4612cd0c529SMike Karels 	DELAY(10);
4622cd0c529SMike Karels 
4632cd0c529SMike Karels 	WR4(sc, GENET_UMAC_CMD, 0);
4642cd0c529SMike Karels 	WR4(sc, GENET_UMAC_CMD,
4652cd0c529SMike Karels 	    GENET_UMAC_CMD_LCL_LOOP_EN | GENET_UMAC_CMD_SW_RESET);
4662cd0c529SMike Karels 	DELAY(10);
4672cd0c529SMike Karels 	WR4(sc, GENET_UMAC_CMD, 0);
4682cd0c529SMike Karels 
4692cd0c529SMike Karels 	WR4(sc, GENET_UMAC_MIB_CTRL, GENET_UMAC_MIB_RESET_RUNT |
4702cd0c529SMike Karels 	    GENET_UMAC_MIB_RESET_RX | GENET_UMAC_MIB_RESET_TX);
4712cd0c529SMike Karels 	WR4(sc, GENET_UMAC_MIB_CTRL, 0);
4722cd0c529SMike Karels 
4732cd0c529SMike Karels 	WR4(sc, GENET_UMAC_MAX_FRAME_LEN, 1536);
4742cd0c529SMike Karels 
4752cd0c529SMike Karels 	val = RD4(sc, GENET_RBUF_CTRL);
4762cd0c529SMike Karels 	val |= GENET_RBUF_ALIGN_2B;
4772cd0c529SMike Karels 	WR4(sc, GENET_RBUF_CTRL, val);
4782cd0c529SMike Karels 
4792cd0c529SMike Karels 	WR4(sc, GENET_RBUF_TBUF_SIZE_CTRL, 1);
4802cd0c529SMike Karels }
4812cd0c529SMike Karels 
4822cd0c529SMike Karels static void
4832cd0c529SMike Karels gen_enable(struct gen_softc *sc)
4842cd0c529SMike Karels {
4852cd0c529SMike Karels 	u_int val;
4862cd0c529SMike Karels 
4872cd0c529SMike Karels 	/* Enable transmitter and receiver */
4882cd0c529SMike Karels 	val = RD4(sc, GENET_UMAC_CMD);
4892cd0c529SMike Karels 	val |= GENET_UMAC_CMD_TXEN;
4902cd0c529SMike Karels 	val |= GENET_UMAC_CMD_RXEN;
4912cd0c529SMike Karels 	WR4(sc, GENET_UMAC_CMD, val);
4922cd0c529SMike Karels 
4932cd0c529SMike Karels 	/* Enable interrupts */
4942cd0c529SMike Karels 	gen_enable_intr(sc);
4952cd0c529SMike Karels 	WR4(sc, GENET_INTRL2_CPU_CLEAR_MASK,
4962cd0c529SMike Karels 	    GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE);
4972cd0c529SMike Karels }
4982cd0c529SMike Karels 
4992cd0c529SMike Karels static void
5002cd0c529SMike Karels gen_enable_offload(struct gen_softc *sc)
5012cd0c529SMike Karels {
5022cd0c529SMike Karels 	uint32_t check_ctrl, buf_ctrl;
5032cd0c529SMike Karels 
5042cd0c529SMike Karels 	check_ctrl = RD4(sc, GENET_RBUF_CHECK_CTRL);
5052cd0c529SMike Karels 	buf_ctrl  = RD4(sc, GENET_RBUF_CTRL);
5062cd0c529SMike Karels 	if ((if_getcapenable(sc->ifp) & IFCAP_RXCSUM) != 0) {
5072cd0c529SMike Karels 		check_ctrl |= GENET_RBUF_CHECK_CTRL_EN;
5082cd0c529SMike Karels 		buf_ctrl |= GENET_RBUF_64B_EN;
5092cd0c529SMike Karels 	} else {
5102cd0c529SMike Karels 		check_ctrl &= ~GENET_RBUF_CHECK_CTRL_EN;
5112cd0c529SMike Karels 		buf_ctrl &= ~GENET_RBUF_64B_EN;
5122cd0c529SMike Karels 	}
5132cd0c529SMike Karels 	WR4(sc, GENET_RBUF_CHECK_CTRL, check_ctrl);
5142cd0c529SMike Karels 	WR4(sc, GENET_RBUF_CTRL, buf_ctrl);
5152cd0c529SMike Karels 
5162cd0c529SMike Karels 	buf_ctrl  = RD4(sc, GENET_TBUF_CTRL);
5172cd0c529SMike Karels 	if ((if_getcapenable(sc->ifp) & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) !=
5182cd0c529SMike Karels 	    0)
5192cd0c529SMike Karels 		buf_ctrl |= GENET_RBUF_64B_EN;
5202cd0c529SMike Karels 	else
5212cd0c529SMike Karels 		buf_ctrl &= ~GENET_RBUF_64B_EN;
5222cd0c529SMike Karels 	WR4(sc, GENET_TBUF_CTRL, buf_ctrl);
5232cd0c529SMike Karels }
5242cd0c529SMike Karels 
5252cd0c529SMike Karels static void
5262cd0c529SMike Karels gen_dma_disable(device_t dev)
5272cd0c529SMike Karels {
5282cd0c529SMike Karels 	struct gen_softc *sc = device_get_softc(dev);
5292cd0c529SMike Karels 	int val;
5302cd0c529SMike Karels 
5312cd0c529SMike Karels 	val = RD4(sc, GENET_TX_DMA_CTRL);
5322cd0c529SMike Karels 	val &= ~GENET_TX_DMA_CTRL_EN;
5332cd0c529SMike Karels 	val &= ~GENET_TX_DMA_CTRL_RBUF_EN(GENET_DMA_DEFAULT_QUEUE);
5342cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_CTRL, val);
5352cd0c529SMike Karels 
5362cd0c529SMike Karels 	val = RD4(sc, GENET_RX_DMA_CTRL);
5372cd0c529SMike Karels 	val &= ~GENET_RX_DMA_CTRL_EN;
5382cd0c529SMike Karels 	val &= ~GENET_RX_DMA_CTRL_RBUF_EN(GENET_DMA_DEFAULT_QUEUE);
5392cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_CTRL, val);
5402cd0c529SMike Karels }
5412cd0c529SMike Karels 
5422cd0c529SMike Karels static int
5432cd0c529SMike Karels gen_bus_dma_init(struct gen_softc *sc)
5442cd0c529SMike Karels {
5452cd0c529SMike Karels 	struct device *dev = sc->dev;
5462cd0c529SMike Karels 	int i, error;
5472cd0c529SMike Karels 
5482cd0c529SMike Karels 	error = bus_dma_tag_create(
5492cd0c529SMike Karels 	    bus_get_dma_tag(dev),	/* Parent tag */
5502cd0c529SMike Karels 	    4, 0,			/* alignment, boundary */
5512cd0c529SMike Karels 	    BUS_SPACE_MAXADDR_40BIT,	/* lowaddr */
5522cd0c529SMike Karels 	    BUS_SPACE_MAXADDR,		/* highaddr */
5532cd0c529SMike Karels 	    NULL, NULL,			/* filter, filterarg */
5542cd0c529SMike Karels 	    MCLBYTES, TX_MAX_SEGS,	/* maxsize, nsegs */
5552cd0c529SMike Karels 	    MCLBYTES,			/* maxsegsize */
5562cd0c529SMike Karels 	    0,				/* flags */
5572cd0c529SMike Karels 	    NULL, NULL,			/* lockfunc, lockarg */
5582cd0c529SMike Karels 	    &sc->tx_buf_tag);
5592cd0c529SMike Karels 	if (error != 0) {
5602cd0c529SMike Karels 		device_printf(dev, "cannot create TX buffer tag\n");
5612cd0c529SMike Karels 		return (error);
5622cd0c529SMike Karels 	}
5632cd0c529SMike Karels 
5642cd0c529SMike Karels 	for (i = 0; i < TX_DESC_COUNT; i++) {
5652cd0c529SMike Karels 		error = bus_dmamap_create(sc->tx_buf_tag, 0,
5662cd0c529SMike Karels 		    &sc->tx_ring_ent[i].map);
5672cd0c529SMike Karels 		if (error != 0) {
5682cd0c529SMike Karels 			device_printf(dev, "cannot create TX buffer map\n");
5692cd0c529SMike Karels 			return (error);
5702cd0c529SMike Karels 		}
5712cd0c529SMike Karels 	}
5722cd0c529SMike Karels 
5732cd0c529SMike Karels 	error = bus_dma_tag_create(
5742cd0c529SMike Karels 	    bus_get_dma_tag(dev),	/* Parent tag */
5752cd0c529SMike Karels 	    4, 0,			/* alignment, boundary */
5762cd0c529SMike Karels 	    BUS_SPACE_MAXADDR_40BIT,	/* lowaddr */
5772cd0c529SMike Karels 	    BUS_SPACE_MAXADDR,		/* highaddr */
5782cd0c529SMike Karels 	    NULL, NULL,			/* filter, filterarg */
5792cd0c529SMike Karels 	    MCLBYTES, 1,		/* maxsize, nsegs */
5802cd0c529SMike Karels 	    MCLBYTES,			/* maxsegsize */
5812cd0c529SMike Karels 	    0,				/* flags */
5822cd0c529SMike Karels 	    NULL, NULL,			/* lockfunc, lockarg */
5832cd0c529SMike Karels 	    &sc->rx_buf_tag);
5842cd0c529SMike Karels 	if (error != 0) {
5852cd0c529SMike Karels 		device_printf(dev, "cannot create RX buffer tag\n");
5862cd0c529SMike Karels 		return (error);
5872cd0c529SMike Karels 	}
5882cd0c529SMike Karels 
5892cd0c529SMike Karels 	for (i = 0; i < RX_DESC_COUNT; i++) {
5902cd0c529SMike Karels 		error = bus_dmamap_create(sc->rx_buf_tag, 0,
5912cd0c529SMike Karels 		    &sc->rx_ring_ent[i].map);
5922cd0c529SMike Karels 		if (error != 0) {
5932cd0c529SMike Karels 			device_printf(dev, "cannot create RX buffer map\n");
5942cd0c529SMike Karels 			return (error);
5952cd0c529SMike Karels 		}
5962cd0c529SMike Karels 	}
5972cd0c529SMike Karels 	return (0);
5982cd0c529SMike Karels }
5992cd0c529SMike Karels 
6002cd0c529SMike Karels static void
6012cd0c529SMike Karels gen_bus_dma_teardown(struct gen_softc *sc)
6022cd0c529SMike Karels {
6032cd0c529SMike Karels 	int i, error;
6042cd0c529SMike Karels 
6052cd0c529SMike Karels 	if (sc->tx_buf_tag != NULL) {
6062cd0c529SMike Karels 		for (i = 0; i < TX_DESC_COUNT; i++) {
6072cd0c529SMike Karels 			error = bus_dmamap_destroy(sc->tx_buf_tag,
6082cd0c529SMike Karels 			    sc->tx_ring_ent[i].map);
6092cd0c529SMike Karels 			sc->tx_ring_ent[i].map = NULL;
6102cd0c529SMike Karels 			if (error)
6112cd0c529SMike Karels 				device_printf(sc->dev,
6122cd0c529SMike Karels 				    "%s: bus_dmamap_destroy failed: %d\n",
6132cd0c529SMike Karels 				    __func__, error);
6142cd0c529SMike Karels 		}
6152cd0c529SMike Karels 		error = bus_dma_tag_destroy(sc->tx_buf_tag);
6162cd0c529SMike Karels 		sc->tx_buf_tag = NULL;
6172cd0c529SMike Karels 		if (error)
6182cd0c529SMike Karels 			device_printf(sc->dev,
6192cd0c529SMike Karels 			    "%s: bus_dma_tag_destroy failed: %d\n", __func__,
6202cd0c529SMike Karels 			    error);
6212cd0c529SMike Karels 	}
6222cd0c529SMike Karels 
6232cd0c529SMike Karels 	if (sc->tx_buf_tag != NULL) {
6242cd0c529SMike Karels 		for (i = 0; i < RX_DESC_COUNT; i++) {
6252cd0c529SMike Karels 			error = bus_dmamap_destroy(sc->rx_buf_tag,
6262cd0c529SMike Karels 			    sc->rx_ring_ent[i].map);
6272cd0c529SMike Karels 			sc->rx_ring_ent[i].map = NULL;
6282cd0c529SMike Karels 			if (error)
6292cd0c529SMike Karels 				device_printf(sc->dev,
6302cd0c529SMike Karels 				    "%s: bus_dmamap_destroy failed: %d\n",
6312cd0c529SMike Karels 				    __func__, error);
6322cd0c529SMike Karels 		}
6332cd0c529SMike Karels 		error = bus_dma_tag_destroy(sc->rx_buf_tag);
6342cd0c529SMike Karels 		sc->rx_buf_tag = NULL;
6352cd0c529SMike Karels 		if (error)
6362cd0c529SMike Karels 			device_printf(sc->dev,
6372cd0c529SMike Karels 			    "%s: bus_dma_tag_destroy failed: %d\n", __func__,
6382cd0c529SMike Karels 			    error);
6392cd0c529SMike Karels 	}
6402cd0c529SMike Karels }
6412cd0c529SMike Karels 
6422cd0c529SMike Karels static void
6432cd0c529SMike Karels gen_enable_intr(struct gen_softc *sc)
6442cd0c529SMike Karels {
6452cd0c529SMike Karels 
6462cd0c529SMike Karels 	WR4(sc, GENET_INTRL2_CPU_CLEAR_MASK,
6472cd0c529SMike Karels 	    GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE);
6482cd0c529SMike Karels }
6492cd0c529SMike Karels 
6502cd0c529SMike Karels /*
6512cd0c529SMike Karels  * "queue" is the software queue index (0-4); "qid" is the hardware index
6522cd0c529SMike Karels  * (0-16).  "base" is the starting index in the ring array.
6532cd0c529SMike Karels  */
6542cd0c529SMike Karels static void
6552cd0c529SMike Karels gen_init_txring(struct gen_softc *sc, int queue, int qid, int base,
6562cd0c529SMike Karels     int nentries)
6572cd0c529SMike Karels {
6582cd0c529SMike Karels 	struct tx_queue *q;
6592cd0c529SMike Karels 	uint32_t val;
6602cd0c529SMike Karels 
6612cd0c529SMike Karels 	q = &sc->tx_queue[queue];
6622cd0c529SMike Karels 	q->entries = &sc->tx_ring_ent[base];
6632cd0c529SMike Karels 	q->hwindex = qid;
6642cd0c529SMike Karels 	q->nentries = nentries;
6652cd0c529SMike Karels 
6662cd0c529SMike Karels 	/* TX ring */
6672cd0c529SMike Karels 
6682cd0c529SMike Karels 	q->queued = 0;
6692cd0c529SMike Karels 	q->cons_idx = q->prod_idx = 0;
6702cd0c529SMike Karels 
6712cd0c529SMike Karels 	WR4(sc, GENET_TX_SCB_BURST_SIZE, 0x08);
6722cd0c529SMike Karels 
6732cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_READ_PTR_LO(qid), 0);
6742cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_READ_PTR_HI(qid), 0);
6752cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_CONS_INDEX(qid), 0);
6762cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_PROD_INDEX(qid), 0);
6772cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_RING_BUF_SIZE(qid),
6782cd0c529SMike Karels 	    (nentries << GENET_TX_DMA_RING_BUF_SIZE_DESC_SHIFT) |
6792cd0c529SMike Karels 	    (MCLBYTES & GENET_TX_DMA_RING_BUF_SIZE_BUF_LEN_MASK));
6802cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_START_ADDR_LO(qid), 0);
6812cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_START_ADDR_HI(qid), 0);
6822cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_END_ADDR_LO(qid),
6832cd0c529SMike Karels 	    TX_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1);
6842cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_END_ADDR_HI(qid), 0);
6852cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_MBUF_DONE_THRES(qid), 1);
6862cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_FLOW_PERIOD(qid), 0);
6872cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_WRITE_PTR_LO(qid), 0);
6882cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_WRITE_PTR_HI(qid), 0);
6892cd0c529SMike Karels 
6902cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_RING_CFG, __BIT(qid));	/* enable */
6912cd0c529SMike Karels 
6922cd0c529SMike Karels 	/* Enable transmit DMA */
6932cd0c529SMike Karels 	val = RD4(sc, GENET_TX_DMA_CTRL);
6942cd0c529SMike Karels 	val |= GENET_TX_DMA_CTRL_EN;
6952cd0c529SMike Karels 	val |= GENET_TX_DMA_CTRL_RBUF_EN(qid);
6962cd0c529SMike Karels 	WR4(sc, GENET_TX_DMA_CTRL, val);
6972cd0c529SMike Karels }
6982cd0c529SMike Karels 
6992cd0c529SMike Karels /*
7002cd0c529SMike Karels  * "queue" is the software queue index (0-4); "qid" is the hardware index
7012cd0c529SMike Karels  * (0-16).  "base" is the starting index in the ring array.
7022cd0c529SMike Karels  */
7032cd0c529SMike Karels static void
7042cd0c529SMike Karels gen_init_rxring(struct gen_softc *sc, int queue, int qid, int base,
7052cd0c529SMike Karels     int nentries)
7062cd0c529SMike Karels {
7072cd0c529SMike Karels 	struct rx_queue *q;
7082cd0c529SMike Karels 	uint32_t val;
7092cd0c529SMike Karels 	int i;
7102cd0c529SMike Karels 
7112cd0c529SMike Karels 	q = &sc->rx_queue[queue];
7122cd0c529SMike Karels 	q->entries = &sc->rx_ring_ent[base];
7132cd0c529SMike Karels 	q->hwindex = qid;
7142cd0c529SMike Karels 	q->nentries = nentries;
7152cd0c529SMike Karels 	q->cons_idx = q->prod_idx = 0;
7162cd0c529SMike Karels 
7172cd0c529SMike Karels 	WR4(sc, GENET_RX_SCB_BURST_SIZE, 0x08);
7182cd0c529SMike Karels 
7192cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_WRITE_PTR_LO(qid), 0);
7202cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_WRITE_PTR_HI(qid), 0);
7212cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_PROD_INDEX(qid), 0);
7222cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_CONS_INDEX(qid), 0);
7232cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_RING_BUF_SIZE(qid),
7242cd0c529SMike Karels 	    (nentries << GENET_RX_DMA_RING_BUF_SIZE_DESC_SHIFT) |
7252cd0c529SMike Karels 	    (MCLBYTES & GENET_RX_DMA_RING_BUF_SIZE_BUF_LEN_MASK));
7262cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_START_ADDR_LO(qid), 0);
7272cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_START_ADDR_HI(qid), 0);
7282cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_END_ADDR_LO(qid),
7292cd0c529SMike Karels 	    RX_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1);
7302cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_END_ADDR_HI(qid), 0);
7312cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_XON_XOFF_THRES(qid),
7322cd0c529SMike Karels 	    (5 << GENET_RX_DMA_XON_XOFF_THRES_LO_SHIFT) | (RX_DESC_COUNT >> 4));
7332cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_READ_PTR_LO(qid), 0);
7342cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_READ_PTR_HI(qid), 0);
7352cd0c529SMike Karels 
7362cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_RING_CFG, __BIT(qid));	/* enable */
7372cd0c529SMike Karels 
7382cd0c529SMike Karels 	/* fill ring */
7392cd0c529SMike Karels 	for (i = 0; i < RX_DESC_COUNT; i++)
7402cd0c529SMike Karels 		gen_newbuf_rx(sc, &sc->rx_queue[DEF_RXQUEUE], i);
7412cd0c529SMike Karels 
7422cd0c529SMike Karels 	/* Enable receive DMA */
7432cd0c529SMike Karels 	val = RD4(sc, GENET_RX_DMA_CTRL);
7442cd0c529SMike Karels 	val |= GENET_RX_DMA_CTRL_EN;
7452cd0c529SMike Karels 	val |= GENET_RX_DMA_CTRL_RBUF_EN(qid);
7462cd0c529SMike Karels 	WR4(sc, GENET_RX_DMA_CTRL, val);
7472cd0c529SMike Karels }
7482cd0c529SMike Karels 
7492cd0c529SMike Karels static void
7502cd0c529SMike Karels gen_init_txrings(struct gen_softc *sc)
7512cd0c529SMike Karels {
7522cd0c529SMike Karels 	int base = 0;
7532cd0c529SMike Karels #ifdef PRI_RINGS
7542cd0c529SMike Karels 	int i;
7552cd0c529SMike Karels 
7562cd0c529SMike Karels 	/* init priority rings */
7572cd0c529SMike Karels 	for (i = 0; i < PRI_RINGS; i++) {
7582cd0c529SMike Karels 		gen_init_txring(sc, i, i, base, TX_DESC_PRICOUNT);
7592cd0c529SMike Karels 		sc->tx_queue[i].queue = i;
7602cd0c529SMike Karels 		base += TX_DESC_PRICOUNT;
7612cd0c529SMike Karels 		dma_ring_conf |= 1 << i;
7622cd0c529SMike Karels 		dma_control |= DMA_RENABLE(i);
7632cd0c529SMike Karels 	}
7642cd0c529SMike Karels #endif
7652cd0c529SMike Karels 
7662cd0c529SMike Karels 	/* init GENET_DMA_DEFAULT_QUEUE (16) */
7672cd0c529SMike Karels 	gen_init_txring(sc, DEF_TXQUEUE, GENET_DMA_DEFAULT_QUEUE, base,
7682cd0c529SMike Karels 	    TX_DESC_COUNT);
7692cd0c529SMike Karels 	sc->tx_queue[DEF_TXQUEUE].hwindex = GENET_DMA_DEFAULT_QUEUE;
7702cd0c529SMike Karels }
7712cd0c529SMike Karels 
7722cd0c529SMike Karels static void
7732cd0c529SMike Karels gen_init_rxrings(struct gen_softc *sc)
7742cd0c529SMike Karels {
7752cd0c529SMike Karels 	int base = 0;
7762cd0c529SMike Karels #ifdef PRI_RINGS
7772cd0c529SMike Karels 	int i;
7782cd0c529SMike Karels 
7792cd0c529SMike Karels 	/* init priority rings */
7802cd0c529SMike Karels 	for (i = 0; i < PRI_RINGS; i++) {
7812cd0c529SMike Karels 		gen_init_rxring(sc, i, i, base, TX_DESC_PRICOUNT);
7822cd0c529SMike Karels 		sc->rx_queue[i].queue = i;
7832cd0c529SMike Karels 		base += TX_DESC_PRICOUNT;
7842cd0c529SMike Karels 		dma_ring_conf |= 1 << i;
7852cd0c529SMike Karels 		dma_control |= DMA_RENABLE(i);
7862cd0c529SMike Karels 	}
7872cd0c529SMike Karels #endif
7882cd0c529SMike Karels 
7892cd0c529SMike Karels 	/* init GENET_DMA_DEFAULT_QUEUE (16) */
7902cd0c529SMike Karels 	gen_init_rxring(sc, DEF_RXQUEUE, GENET_DMA_DEFAULT_QUEUE, base,
7912cd0c529SMike Karels 	    RX_DESC_COUNT);
7922cd0c529SMike Karels 	sc->rx_queue[DEF_RXQUEUE].hwindex = GENET_DMA_DEFAULT_QUEUE;
7932cd0c529SMike Karels 
7942cd0c529SMike Karels }
7952cd0c529SMike Karels 
7962cd0c529SMike Karels static void
7972cd0c529SMike Karels gen_init_locked(struct gen_softc *sc)
7982cd0c529SMike Karels {
7992cd0c529SMike Karels 	struct mii_data *mii;
8002cd0c529SMike Karels 	if_t ifp;
8012cd0c529SMike Karels 
8022cd0c529SMike Karels 	mii = device_get_softc(sc->miibus);
8032cd0c529SMike Karels 	ifp = sc->ifp;
8042cd0c529SMike Karels 
8052cd0c529SMike Karels 	GEN_ASSERT_LOCKED(sc);
8062cd0c529SMike Karels 
8072cd0c529SMike Karels 	if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
8082cd0c529SMike Karels 		return;
8092cd0c529SMike Karels 
810*349eddbdSMike Karels 	switch (sc->phy_mode)
811*349eddbdSMike Karels 	{
812*349eddbdSMike Karels 	case MII_CONTYPE_RGMII:
813*349eddbdSMike Karels 	case MII_CONTYPE_RGMII_ID:
814*349eddbdSMike Karels 	case MII_CONTYPE_RGMII_RXID:
815*349eddbdSMike Karels 	case MII_CONTYPE_RGMII_TXID:
816*349eddbdSMike Karels 		WR4(sc, GENET_SYS_PORT_CTRL, GENET_SYS_PORT_MODE_EXT_GPHY);
817*349eddbdSMike Karels 		break;
818*349eddbdSMike Karels 	default:
819*349eddbdSMike Karels 		WR4(sc, GENET_SYS_PORT_CTRL, 0);
820*349eddbdSMike Karels 	}
8212cd0c529SMike Karels 
8222cd0c529SMike Karels 	gen_set_enaddr(sc);
8232cd0c529SMike Karels 
8242cd0c529SMike Karels 	/* Setup RX filter */
8252cd0c529SMike Karels 	gen_setup_rxfilter(sc);
8262cd0c529SMike Karels 
8272cd0c529SMike Karels 	gen_init_txrings(sc);
8282cd0c529SMike Karels 	gen_init_rxrings(sc);
8292cd0c529SMike Karels 	gen_enable(sc);
8302cd0c529SMike Karels 	gen_enable_offload(sc);
8312cd0c529SMike Karels 
8322cd0c529SMike Karels 	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
8332cd0c529SMike Karels 
8342cd0c529SMike Karels 	mii_mediachg(mii);
8352cd0c529SMike Karels 	callout_reset(&sc->stat_ch, hz, gen_tick, sc);
8362cd0c529SMike Karels }
8372cd0c529SMike Karels 
8382cd0c529SMike Karels static void
8392cd0c529SMike Karels gen_init(void *softc)
8402cd0c529SMike Karels {
8412cd0c529SMike Karels         struct gen_softc *sc;
8422cd0c529SMike Karels 
8432cd0c529SMike Karels         sc = softc;
8442cd0c529SMike Karels 	GEN_LOCK(sc);
8452cd0c529SMike Karels 	gen_init_locked(sc);
8462cd0c529SMike Karels 	GEN_UNLOCK(sc);
8472cd0c529SMike Karels }
8482cd0c529SMike Karels 
8492cd0c529SMike Karels static uint8_t ether_broadcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
8502cd0c529SMike Karels 
8512cd0c529SMike Karels static void
8522cd0c529SMike Karels gen_setup_rxfilter_mdf(struct gen_softc *sc, u_int n, const uint8_t *ea)
8532cd0c529SMike Karels {
8542cd0c529SMike Karels 	uint32_t addr0 = (ea[0] << 8) | ea[1];
8552cd0c529SMike Karels 	uint32_t addr1 = (ea[2] << 24) | (ea[3] << 16) | (ea[4] << 8) | ea[5];
8562cd0c529SMike Karels 
8572cd0c529SMike Karels 	WR4(sc, GENET_UMAC_MDF_ADDR0(n), addr0);
8582cd0c529SMike Karels 	WR4(sc, GENET_UMAC_MDF_ADDR1(n), addr1);
8592cd0c529SMike Karels }
8602cd0c529SMike Karels 
8612cd0c529SMike Karels static u_int
8622cd0c529SMike Karels gen_setup_multi(void *arg, struct sockaddr_dl *sdl, u_int count)
8632cd0c529SMike Karels {
8642cd0c529SMike Karels 	struct gen_softc *sc = arg;
8652cd0c529SMike Karels 
8662cd0c529SMike Karels 	/* "count + 2" to account for unicast and broadcast */
8672cd0c529SMike Karels 	gen_setup_rxfilter_mdf(sc, count + 2, LLADDR(sdl));
8682cd0c529SMike Karels 	return (1);		/* increment to count */
8692cd0c529SMike Karels }
8702cd0c529SMike Karels 
8712cd0c529SMike Karels static void
8722cd0c529SMike Karels gen_setup_rxfilter(struct gen_softc *sc)
8732cd0c529SMike Karels {
8742cd0c529SMike Karels 	struct ifnet *ifp = sc->ifp;
8752cd0c529SMike Karels 	uint32_t cmd, mdf_ctrl;
8762cd0c529SMike Karels 	u_int n;
8772cd0c529SMike Karels 
8782cd0c529SMike Karels 	GEN_ASSERT_LOCKED(sc);
8792cd0c529SMike Karels 
8802cd0c529SMike Karels 	cmd = RD4(sc, GENET_UMAC_CMD);
8812cd0c529SMike Karels 
8822cd0c529SMike Karels 	/*
8832cd0c529SMike Karels 	 * Count the required number of hardware filters. We need one
8842cd0c529SMike Karels 	 * for each multicast address, plus one for our own address and
8852cd0c529SMike Karels 	 * the broadcast address.
8862cd0c529SMike Karels 	 */
8872cd0c529SMike Karels 	n = if_llmaddr_count(ifp) + 2;
8882cd0c529SMike Karels 
8892cd0c529SMike Karels 	if (n > GENET_MAX_MDF_FILTER)
8902cd0c529SMike Karels 		ifp->if_flags |= IFF_ALLMULTI;
8912cd0c529SMike Karels 	else
8922cd0c529SMike Karels 		ifp->if_flags &= ~IFF_ALLMULTI;
8932cd0c529SMike Karels 
8942cd0c529SMike Karels 	if ((ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0) {
8952cd0c529SMike Karels 		cmd |= GENET_UMAC_CMD_PROMISC;
8962cd0c529SMike Karels 		mdf_ctrl = 0;
8972cd0c529SMike Karels 	} else {
8982cd0c529SMike Karels 		cmd &= ~GENET_UMAC_CMD_PROMISC;
8992cd0c529SMike Karels 		gen_setup_rxfilter_mdf(sc, 0, ether_broadcastaddr);
9002cd0c529SMike Karels 		gen_setup_rxfilter_mdf(sc, 1, IF_LLADDR(ifp));
9012cd0c529SMike Karels 		(void) if_foreach_llmaddr(ifp, gen_setup_multi, sc);
9022cd0c529SMike Karels 		mdf_ctrl = (__BIT(GENET_MAX_MDF_FILTER) - 1)  &~
9032cd0c529SMike Karels 		    (__BIT(GENET_MAX_MDF_FILTER - n) - 1);
9042cd0c529SMike Karels 	}
9052cd0c529SMike Karels 
9062cd0c529SMike Karels 	WR4(sc, GENET_UMAC_CMD, cmd);
9072cd0c529SMike Karels 	WR4(sc, GENET_UMAC_MDF_CTRL, mdf_ctrl);
9082cd0c529SMike Karels }
9092cd0c529SMike Karels 
9102cd0c529SMike Karels static void
9112cd0c529SMike Karels gen_set_enaddr(struct gen_softc *sc)
9122cd0c529SMike Karels {
9132cd0c529SMike Karels 	uint8_t *enaddr;
9142cd0c529SMike Karels 	uint32_t val;
9152cd0c529SMike Karels 	if_t ifp;
9162cd0c529SMike Karels 
9172cd0c529SMike Karels 	GEN_ASSERT_LOCKED(sc);
9182cd0c529SMike Karels 
9192cd0c529SMike Karels 	ifp = sc->ifp;
9202cd0c529SMike Karels 
9212cd0c529SMike Karels 	/* Write our unicast address */
9222cd0c529SMike Karels 	enaddr = IF_LLADDR(ifp);
9232cd0c529SMike Karels 	/* Write hardware address */
9242cd0c529SMike Karels 	val = enaddr[3] | (enaddr[2] << 8) | (enaddr[1] << 16) |
9252cd0c529SMike Karels 	    (enaddr[0] << 24);
9262cd0c529SMike Karels 	WR4(sc, GENET_UMAC_MAC0, val);
9272cd0c529SMike Karels 	val = enaddr[5] | (enaddr[4] << 8);
9282cd0c529SMike Karels 	WR4(sc, GENET_UMAC_MAC1, val);
9292cd0c529SMike Karels }
9302cd0c529SMike Karels 
9312cd0c529SMike Karels static void
9322cd0c529SMike Karels gen_start_locked(struct gen_softc *sc)
9332cd0c529SMike Karels {
9342cd0c529SMike Karels 	struct mbuf *m;
9352cd0c529SMike Karels 	if_t ifp;
9362cd0c529SMike Karels 	int cnt, err;
9372cd0c529SMike Karels 
9382cd0c529SMike Karels 	GEN_ASSERT_LOCKED(sc);
9392cd0c529SMike Karels 
9402cd0c529SMike Karels 	if (!sc->link)
9412cd0c529SMike Karels 		return;
9422cd0c529SMike Karels 
9432cd0c529SMike Karels 	ifp = sc->ifp;
9442cd0c529SMike Karels 
9452cd0c529SMike Karels 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) !=
9462cd0c529SMike Karels 	    IFF_DRV_RUNNING)
9472cd0c529SMike Karels 		return;
9482cd0c529SMike Karels 
9492cd0c529SMike Karels 	for (cnt = 0; ; cnt++) {
9502cd0c529SMike Karels 		m = if_dequeue(ifp);
9512cd0c529SMike Karels 		if (m == NULL)
9522cd0c529SMike Karels 			break;
9532cd0c529SMike Karels 
9542cd0c529SMike Karels 		err = gen_encap(sc, &m);
9552cd0c529SMike Karels 		if (err != 0) {
9562cd0c529SMike Karels 			if (err == ENOBUFS)
9572cd0c529SMike Karels 				if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
9582cd0c529SMike Karels 			if (m != NULL)
9592cd0c529SMike Karels 				if_sendq_prepend(ifp, m);
9602cd0c529SMike Karels 			break;
9612cd0c529SMike Karels 		}
9622cd0c529SMike Karels 		if_bpfmtap(ifp, m);
9632cd0c529SMike Karels 	}
9642cd0c529SMike Karels }
9652cd0c529SMike Karels 
9662cd0c529SMike Karels static void
9672cd0c529SMike Karels gen_start(if_t ifp)
9682cd0c529SMike Karels {
9692cd0c529SMike Karels 	struct gen_softc *sc;
9702cd0c529SMike Karels 
9712cd0c529SMike Karels 	sc = if_getsoftc(ifp);
9722cd0c529SMike Karels 
9732cd0c529SMike Karels 	GEN_LOCK(sc);
9742cd0c529SMike Karels 	gen_start_locked(sc);
9752cd0c529SMike Karels 	GEN_UNLOCK(sc);
9762cd0c529SMike Karels }
9772cd0c529SMike Karels 
9780add2a52SMike Karels /* Test for any delayed checksum */
9790add2a52SMike Karels #define CSUM_DELAY_ANY	(CSUM_TCP | CSUM_UDP | CSUM_IP6_TCP | CSUM_IP6_UDP)
9800add2a52SMike Karels 
9812cd0c529SMike Karels static int
9822cd0c529SMike Karels gen_encap(struct gen_softc *sc, struct mbuf **mp)
9832cd0c529SMike Karels {
9842cd0c529SMike Karels 	bus_dmamap_t map;
9852cd0c529SMike Karels 	bus_dma_segment_t segs[TX_MAX_SEGS];
9862cd0c529SMike Karels 	int error, nsegs, cur, first, i, index, offset;
9872cd0c529SMike Karels 	uint32_t csuminfo, length_status, csum_flags = 0, csumdata;
9882cd0c529SMike Karels 	struct mbuf *m;
9892cd0c529SMike Karels 	struct statusblock *sb = NULL;
9902cd0c529SMike Karels 	struct tx_queue *q;
9912cd0c529SMike Karels 	struct gen_ring_ent *ent;
9922cd0c529SMike Karels 
9932cd0c529SMike Karels 	GEN_ASSERT_LOCKED(sc);
9942cd0c529SMike Karels 
9952cd0c529SMike Karels 	q = &sc->tx_queue[DEF_TXQUEUE];
9962cd0c529SMike Karels 
9972cd0c529SMike Karels 	m = *mp;
99851cefda1SMike Karels #ifdef ICMPV6_HACK
99951cefda1SMike Karels 	/*
100051cefda1SMike Karels 	 * Reflected ICMPv6 packets, e.g. echo replies, tend to get laid
100151cefda1SMike Karels 	 * out with only the Ethernet header in the first mbuf, and this
100251cefda1SMike Karels 	 * doesn't seem to work.
100351cefda1SMike Karels 	 */
100451cefda1SMike Karels #define ICMP6_LEN (sizeof(struct ether_header) + sizeof(struct ip6_hdr) + \
100551cefda1SMike Karels 		    sizeof(struct icmp6_hdr))
100651cefda1SMike Karels 	if (m->m_len == sizeof(struct ether_header)) {
100751cefda1SMike Karels 		int ether_type = mtod(m, struct ether_header *)->ether_type;
100851cefda1SMike Karels 		if (ntohs(ether_type) == ETHERTYPE_IPV6 &&
100951cefda1SMike Karels 		    m->m_next->m_len >= sizeof(struct ip6_hdr)) {
101051cefda1SMike Karels 			struct ip6_hdr *ip6;
101151cefda1SMike Karels 
101251cefda1SMike Karels 			ip6 = mtod(m->m_next, struct ip6_hdr *);
101351cefda1SMike Karels 			if (ip6->ip6_nxt == IPPROTO_ICMPV6) {
101451cefda1SMike Karels 				m = m_pullup(m,
101551cefda1SMike Karels 				    MIN(m->m_pkthdr.len, ICMP6_LEN));
101651cefda1SMike Karels 				if (m == NULL) {
101751cefda1SMike Karels 					if (sc->ifp->if_flags & IFF_DEBUG)
101851cefda1SMike Karels 						device_printf(sc->dev,
101951cefda1SMike Karels 						    "ICMPV6 pullup fail\n");
102051cefda1SMike Karels 					*mp = NULL;
102151cefda1SMike Karels 					return (ENOMEM);
102251cefda1SMike Karels 				}
102351cefda1SMike Karels 			}
102451cefda1SMike Karels 		}
102551cefda1SMike Karels 	}
102651cefda1SMike Karels #undef ICMP6_LEN
102751cefda1SMike Karels #endif
10282cd0c529SMike Karels 	if ((if_getcapenable(sc->ifp) & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) !=
10292cd0c529SMike Karels 	    0) {
10302cd0c529SMike Karels 		csum_flags = m->m_pkthdr.csum_flags;
10312cd0c529SMike Karels 		csumdata = m->m_pkthdr.csum_data;
10322cd0c529SMike Karels 		M_PREPEND(m, sizeof(struct statusblock), M_NOWAIT);
10332cd0c529SMike Karels 		if (m == NULL) {
10342cd0c529SMike Karels 			if (sc->ifp->if_flags & IFF_DEBUG)
10352cd0c529SMike Karels 				device_printf(sc->dev, "prepend fail\n");
10362cd0c529SMike Karels 			*mp = NULL;
10372cd0c529SMike Karels 			return (ENOMEM);
10382cd0c529SMike Karels 		}
10392cd0c529SMike Karels 		offset = gen_parse_tx(m, csum_flags);
10402cd0c529SMike Karels 		sb = mtod(m, struct statusblock *);
10410add2a52SMike Karels 		if ((csum_flags & CSUM_DELAY_ANY) != 0) {
10422cd0c529SMike Karels 			csuminfo = (offset << TXCSUM_OFF_SHIFT) |
10432cd0c529SMike Karels 			    (offset + csumdata);
10442cd0c529SMike Karels 			csuminfo |= TXCSUM_LEN_VALID;
10450add2a52SMike Karels 			if (csum_flags & (CSUM_UDP | CSUM_IP6_UDP))
10462cd0c529SMike Karels 				csuminfo |= TXCSUM_UDP;
10472cd0c529SMike Karels 			sb->txcsuminfo = csuminfo;
10482cd0c529SMike Karels 		} else
10492cd0c529SMike Karels 			sb->txcsuminfo = 0;
10502cd0c529SMike Karels 	}
10512cd0c529SMike Karels 
10522cd0c529SMike Karels 	*mp = m;
10532cd0c529SMike Karels 
10542cd0c529SMike Karels 	cur = first = q->cur;
10552cd0c529SMike Karels 	ent = &q->entries[cur];
10562cd0c529SMike Karels 	map = ent->map;
10572cd0c529SMike Karels 	error = bus_dmamap_load_mbuf_sg(sc->tx_buf_tag, map, m, segs,
10582cd0c529SMike Karels 	    &nsegs, BUS_DMA_NOWAIT);
10592cd0c529SMike Karels 	if (error == EFBIG) {
10602cd0c529SMike Karels 		m = m_collapse(m, M_NOWAIT, TX_MAX_SEGS);
10612cd0c529SMike Karels 		if (m == NULL) {
10622cd0c529SMike Karels 			device_printf(sc->dev,
10632cd0c529SMike Karels 			    "gen_encap: m_collapse failed\n");
10642cd0c529SMike Karels 			m_freem(*mp);
10652cd0c529SMike Karels 			*mp = NULL;
10662cd0c529SMike Karels 			return (ENOMEM);
10672cd0c529SMike Karels 		}
10682cd0c529SMike Karels 		*mp = m;
10692cd0c529SMike Karels 		error = bus_dmamap_load_mbuf_sg(sc->tx_buf_tag, map, m,
10702cd0c529SMike Karels 		    segs, &nsegs, BUS_DMA_NOWAIT);
10712cd0c529SMike Karels 		if (error != 0) {
10722cd0c529SMike Karels 			m_freem(*mp);
10732cd0c529SMike Karels 			*mp = NULL;
10742cd0c529SMike Karels 		}
10752cd0c529SMike Karels 	}
10762cd0c529SMike Karels 	if (error != 0) {
10772cd0c529SMike Karels 		device_printf(sc->dev,
10782cd0c529SMike Karels 		    "gen_encap: bus_dmamap_load_mbuf_sg failed\n");
10792cd0c529SMike Karels 		return (error);
10802cd0c529SMike Karels 	}
10812cd0c529SMike Karels 	if (nsegs == 0) {
10822cd0c529SMike Karels 		m_freem(*mp);
10832cd0c529SMike Karels 		*mp = NULL;
10842cd0c529SMike Karels 		return (EIO);
10852cd0c529SMike Karels 	}
10862cd0c529SMike Karels 
10872cd0c529SMike Karels 	/* Remove statusblock after mapping, before possible requeue or bpf. */
10882cd0c529SMike Karels 	if (sb != NULL) {
10892cd0c529SMike Karels 		m->m_data += sizeof(struct statusblock);
10902cd0c529SMike Karels 		m->m_len -= sizeof(struct statusblock);
10912cd0c529SMike Karels 		m->m_pkthdr.len -= sizeof(struct statusblock);
10922cd0c529SMike Karels 	}
10932cd0c529SMike Karels 	if (q->queued + nsegs > q->nentries) {
10942cd0c529SMike Karels 		bus_dmamap_unload(sc->tx_buf_tag, map);
10952cd0c529SMike Karels 		return (ENOBUFS);
10962cd0c529SMike Karels 	}
10972cd0c529SMike Karels 
10982cd0c529SMike Karels 	bus_dmamap_sync(sc->tx_buf_tag, map, BUS_DMASYNC_PREWRITE);
10992cd0c529SMike Karels 
11002cd0c529SMike Karels 	index = q->prod_idx & (q->nentries - 1);
11012cd0c529SMike Karels 	for (i = 0; i < nsegs; i++) {
11022cd0c529SMike Karels 		ent = &q->entries[cur];
11032cd0c529SMike Karels 		length_status = GENET_TX_DESC_STATUS_QTAG_MASK;
11042cd0c529SMike Karels 		if (i == 0) {
11052cd0c529SMike Karels 			length_status |= GENET_TX_DESC_STATUS_SOP |
11062cd0c529SMike Karels 			    GENET_TX_DESC_STATUS_CRC;
11070add2a52SMike Karels 			if ((csum_flags & CSUM_DELAY_ANY) != 0)
11082cd0c529SMike Karels 				length_status |= GENET_TX_DESC_STATUS_CKSUM;
11092cd0c529SMike Karels 		}
11102cd0c529SMike Karels 		if (i == nsegs - 1)
11112cd0c529SMike Karels 			length_status |= GENET_TX_DESC_STATUS_EOP;
11122cd0c529SMike Karels 
11132cd0c529SMike Karels 		length_status |= segs[i].ds_len <<
11142cd0c529SMike Karels 		    GENET_TX_DESC_STATUS_BUFLEN_SHIFT;
11152cd0c529SMike Karels 
11162cd0c529SMike Karels 		WR4(sc, GENET_TX_DESC_ADDRESS_LO(index),
11172cd0c529SMike Karels 		    (uint32_t)segs[i].ds_addr);
11182cd0c529SMike Karels 		WR4(sc, GENET_TX_DESC_ADDRESS_HI(index),
11192cd0c529SMike Karels 		    (uint32_t)(segs[i].ds_addr >> 32));
11202cd0c529SMike Karels 		WR4(sc, GENET_TX_DESC_STATUS(index), length_status);
11212cd0c529SMike Karels 
11222cd0c529SMike Karels 		++q->queued;
11232cd0c529SMike Karels 		cur = TX_NEXT(cur, q->nentries);
11242cd0c529SMike Karels 		index = TX_NEXT(index, q->nentries);
11252cd0c529SMike Karels 	}
11262cd0c529SMike Karels 
11272cd0c529SMike Karels 	q->prod_idx += nsegs;
11282cd0c529SMike Karels 	q->prod_idx &= GENET_TX_DMA_PROD_CONS_MASK;
11292cd0c529SMike Karels 	/* We probably don't need to write the producer index on every iter */
11302cd0c529SMike Karels 	if (nsegs != 0)
11312cd0c529SMike Karels 		WR4(sc, GENET_TX_DMA_PROD_INDEX(q->hwindex), q->prod_idx);
11322cd0c529SMike Karels 	q->cur = cur;
11332cd0c529SMike Karels 
11342cd0c529SMike Karels 	/* Store mbuf in the last segment */
11352cd0c529SMike Karels 	q->entries[first].mbuf = m;
11362cd0c529SMike Karels 
11372cd0c529SMike Karels 	return (0);
11382cd0c529SMike Karels }
11392cd0c529SMike Karels 
11402cd0c529SMike Karels /*
11412cd0c529SMike Karels  * Parse a packet to find the offset of the transport header for checksum
11422cd0c529SMike Karels  * offload.  Ensure that the link and network headers are contiguous with
11432cd0c529SMike Karels  * the status block, or transmission fails.
11442cd0c529SMike Karels  */
11452cd0c529SMike Karels static int
11462cd0c529SMike Karels gen_parse_tx(struct mbuf *m, int csum_flags)
11472cd0c529SMike Karels {
11482cd0c529SMike Karels 	int offset, off_in_m;
11490add2a52SMike Karels 	bool copy = false, shift = false;
11502cd0c529SMike Karels 	u_char *p, *copy_p = NULL;
11512cd0c529SMike Karels 	struct mbuf *m0 = m;
11522cd0c529SMike Karels 	uint16_t ether_type;
11532cd0c529SMike Karels 
11542cd0c529SMike Karels 	if (m->m_len == sizeof(struct statusblock)) {
11552cd0c529SMike Karels 		/* M_PREPEND placed statusblock at end; move to beginning */
11562cd0c529SMike Karels 		m->m_data = m->m_pktdat;
11572cd0c529SMike Karels 		copy_p = mtodo(m, sizeof(struct statusblock));
11582cd0c529SMike Karels 		m = m->m_next;
11592cd0c529SMike Karels 		off_in_m = 0;
11602cd0c529SMike Karels 		p = mtod(m, u_char *);
11610add2a52SMike Karels 		copy = true;
11622cd0c529SMike Karels 	} else {
11630add2a52SMike Karels 		/*
11640add2a52SMike Karels 		 * If statusblock is not at beginning of mbuf (likely),
11650add2a52SMike Karels 		 * then remember to move mbuf contents down before copying
11660add2a52SMike Karels 		 * after them.
11670add2a52SMike Karels 		 */
11680add2a52SMike Karels 		if ((m->m_flags & M_EXT) == 0 && m->m_data != m->m_pktdat)
11690add2a52SMike Karels 			shift = true;
11702cd0c529SMike Karels 		p = mtodo(m, sizeof(struct statusblock));
11712cd0c529SMike Karels 		off_in_m = sizeof(struct statusblock);
11722cd0c529SMike Karels 	}
11732cd0c529SMike Karels 
11740add2a52SMike Karels /*
11750add2a52SMike Karels  * If headers need to be copied contiguous to statusblock, do so.
11760add2a52SMike Karels  * If copying to the internal mbuf data area, and the status block
11770add2a52SMike Karels  * is not at the beginning of that area, shift the status block (which
11780add2a52SMike Karels  * is empty) and following data.
11790add2a52SMike Karels  */
11802cd0c529SMike Karels #define COPY(size) {							\
11812cd0c529SMike Karels 	int hsize = size;						\
11820add2a52SMike Karels 	if (copy) {							\
11830add2a52SMike Karels 		if (shift) {						\
11840add2a52SMike Karels 			u_char *p0;					\
11850add2a52SMike Karels 			shift = false;					\
11860add2a52SMike Karels 			p0 = mtodo(m0, sizeof(struct statusblock));	\
11870add2a52SMike Karels 			m0->m_data = m0->m_pktdat;			\
11880add2a52SMike Karels 			bcopy(p0, mtodo(m0, sizeof(struct statusblock)),\
11890add2a52SMike Karels 			    m0->m_len - sizeof(struct statusblock));	\
11900add2a52SMike Karels 			copy_p = mtodo(m0, sizeof(struct statusblock));	\
11910add2a52SMike Karels 		}							\
11922cd0c529SMike Karels 		bcopy(p, copy_p, hsize);				\
11932cd0c529SMike Karels 		m0->m_len += hsize;					\
11942cd0c529SMike Karels 		m0->m_pkthdr.len += hsize;	/* unneeded */		\
11952cd0c529SMike Karels 		m->m_len -= hsize;					\
11962cd0c529SMike Karels 		m->m_data += hsize;					\
11972cd0c529SMike Karels 	}								\
11980add2a52SMike Karels 	copy_p += hsize;						\
11992cd0c529SMike Karels }
12002cd0c529SMike Karels 
12012cd0c529SMike Karels 	KASSERT((sizeof(struct statusblock) + sizeof(struct ether_vlan_header) +
12022cd0c529SMike Karels 	    sizeof(struct ip6_hdr) <= MLEN), ("%s: mbuf too small", __func__));
12032cd0c529SMike Karels 
12042cd0c529SMike Karels 	if (((struct ether_header *)p)->ether_type == htons(ETHERTYPE_VLAN)) {
12052cd0c529SMike Karels 		offset = sizeof(struct ether_vlan_header);
12062cd0c529SMike Karels 		ether_type = ntohs(((struct ether_vlan_header *)p)->evl_proto);
12072cd0c529SMike Karels 		COPY(sizeof(struct ether_vlan_header));
12082cd0c529SMike Karels 		if (m->m_len == off_in_m + sizeof(struct ether_vlan_header)) {
12092cd0c529SMike Karels 			m = m->m_next;
12102cd0c529SMike Karels 			off_in_m = 0;
12112cd0c529SMike Karels 			p = mtod(m, u_char *);
12120add2a52SMike Karels 			copy = true;
12132cd0c529SMike Karels 		} else {
12142cd0c529SMike Karels 			off_in_m += sizeof(struct ether_vlan_header);
12152cd0c529SMike Karels 			p += sizeof(struct ether_vlan_header);
12162cd0c529SMike Karels 		}
12172cd0c529SMike Karels 	} else {
12182cd0c529SMike Karels 		offset = sizeof(struct ether_header);
12192cd0c529SMike Karels 		ether_type = ntohs(((struct ether_header *)p)->ether_type);
12202cd0c529SMike Karels 		COPY(sizeof(struct ether_header));
12212cd0c529SMike Karels 		if (m->m_len == off_in_m + sizeof(struct ether_header)) {
12222cd0c529SMike Karels 			m = m->m_next;
12232cd0c529SMike Karels 			off_in_m = 0;
12242cd0c529SMike Karels 			p = mtod(m, u_char *);
12250add2a52SMike Karels 			copy = true;
12262cd0c529SMike Karels 		} else {
12272cd0c529SMike Karels 			off_in_m += sizeof(struct ether_header);
12282cd0c529SMike Karels 			p += sizeof(struct ether_header);
12292cd0c529SMike Karels 		}
12302cd0c529SMike Karels 	}
12312cd0c529SMike Karels 	if (ether_type == ETHERTYPE_IP) {
12322cd0c529SMike Karels 		COPY(((struct ip *)p)->ip_hl << 2);
12332cd0c529SMike Karels 		offset += ((struct ip *)p)->ip_hl << 2;
12342cd0c529SMike Karels 	} else if (ether_type == ETHERTYPE_IPV6) {
12352cd0c529SMike Karels 		COPY(sizeof(struct ip6_hdr));
12362cd0c529SMike Karels 		offset += sizeof(struct ip6_hdr);
12372cd0c529SMike Karels 	} else {
12382cd0c529SMike Karels 		/*
12392cd0c529SMike Karels 		 * Unknown whether other cases require moving a header;
12402cd0c529SMike Karels 		 * ARP works without.
12412cd0c529SMike Karels 		 */
12422cd0c529SMike Karels 	}
12432cd0c529SMike Karels 	return (offset);
12442cd0c529SMike Karels #undef COPY
12452cd0c529SMike Karels }
12462cd0c529SMike Karels 
12472cd0c529SMike Karels static void
12482cd0c529SMike Karels gen_intr(void *arg)
12492cd0c529SMike Karels {
12502cd0c529SMike Karels 	struct gen_softc *sc = arg;
12512cd0c529SMike Karels 	uint32_t val;
12522cd0c529SMike Karels 
12532cd0c529SMike Karels 	GEN_LOCK(sc);
12542cd0c529SMike Karels 
12552cd0c529SMike Karels 	val = RD4(sc, GENET_INTRL2_CPU_STAT);
12562cd0c529SMike Karels 	val &= ~RD4(sc, GENET_INTRL2_CPU_STAT_MASK);
12572cd0c529SMike Karels 	WR4(sc, GENET_INTRL2_CPU_CLEAR, val);
12582cd0c529SMike Karels 
12592cd0c529SMike Karels 	if (val & GENET_IRQ_RXDMA_DONE)
12602cd0c529SMike Karels 		gen_rxintr(sc, &sc->rx_queue[DEF_RXQUEUE]);
12612cd0c529SMike Karels 
12622cd0c529SMike Karels 
12632cd0c529SMike Karels 	if (val & GENET_IRQ_TXDMA_DONE) {
12642cd0c529SMike Karels 		gen_txintr(sc, &sc->tx_queue[DEF_TXQUEUE]);
12652cd0c529SMike Karels 		if (!if_sendq_empty(sc->ifp))
12662cd0c529SMike Karels 			gen_start_locked(sc);
12672cd0c529SMike Karels 	}
12682cd0c529SMike Karels 
12692cd0c529SMike Karels 	GEN_UNLOCK(sc);
12702cd0c529SMike Karels }
12712cd0c529SMike Karels 
12722cd0c529SMike Karels static int
12732cd0c529SMike Karels gen_rxintr(struct gen_softc *sc, struct rx_queue *q)
12742cd0c529SMike Karels {
12752cd0c529SMike Karels 	if_t ifp;
12762cd0c529SMike Karels 	struct mbuf *m, *mh, *mt;
12772cd0c529SMike Karels 	struct statusblock *sb = NULL;
12782cd0c529SMike Karels 	int error, index, len, cnt, npkt, n;
12792cd0c529SMike Karels 	uint32_t status, prod_idx, total;
12802cd0c529SMike Karels 
12812cd0c529SMike Karels 	ifp = sc->ifp;
12822cd0c529SMike Karels 	mh = mt = NULL;
12832cd0c529SMike Karels 	cnt = 0;
12842cd0c529SMike Karels 	npkt = 0;
12852cd0c529SMike Karels 
12862cd0c529SMike Karels 	prod_idx = RD4(sc, GENET_RX_DMA_PROD_INDEX(q->hwindex)) &
12872cd0c529SMike Karels 	    GENET_RX_DMA_PROD_CONS_MASK;
12882cd0c529SMike Karels 	total = (prod_idx - q->cons_idx) & GENET_RX_DMA_PROD_CONS_MASK;
12892cd0c529SMike Karels 
12902cd0c529SMike Karels 	index = q->cons_idx & (RX_DESC_COUNT - 1);
12912cd0c529SMike Karels 	for (n = 0; n < total; n++) {
12922cd0c529SMike Karels 		bus_dmamap_sync(sc->rx_buf_tag, q->entries[index].map,
12932cd0c529SMike Karels 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
12942cd0c529SMike Karels 		bus_dmamap_unload(sc->rx_buf_tag, q->entries[index].map);
12952cd0c529SMike Karels 
12962cd0c529SMike Karels 		m = q->entries[index].mbuf;
12972cd0c529SMike Karels 
12982cd0c529SMike Karels 		if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) {
12992cd0c529SMike Karels 			sb = mtod(m, struct statusblock *);
13002cd0c529SMike Karels 			status = sb->status_buflen;
13012cd0c529SMike Karels 		} else
13022cd0c529SMike Karels 			status = RD4(sc, GENET_RX_DESC_STATUS(index));
13032cd0c529SMike Karels 
13042cd0c529SMike Karels 		len = (status & GENET_RX_DESC_STATUS_BUFLEN_MASK) >>
13052cd0c529SMike Karels 		    GENET_RX_DESC_STATUS_BUFLEN_SHIFT;
13062cd0c529SMike Karels 
13072cd0c529SMike Karels 		/* check for errors */
13082cd0c529SMike Karels 		if ((status &
13092cd0c529SMike Karels 		    (GENET_RX_DESC_STATUS_SOP | GENET_RX_DESC_STATUS_EOP |
13102cd0c529SMike Karels 		    GENET_RX_DESC_STATUS_RX_ERROR)) !=
13112cd0c529SMike Karels 		    (GENET_RX_DESC_STATUS_SOP | GENET_RX_DESC_STATUS_EOP)) {
13122cd0c529SMike Karels 			if (ifp->if_flags & IFF_DEBUG)
13132cd0c529SMike Karels 				device_printf(sc->dev,
13142cd0c529SMike Karels 				    "error/frag %x csum %x\n", status,
13152cd0c529SMike Karels 				    sb->rxcsum);
13162cd0c529SMike Karels 			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
13172cd0c529SMike Karels 			continue;
13182cd0c529SMike Karels 		}
13192cd0c529SMike Karels 
13202cd0c529SMike Karels 		error = gen_newbuf_rx(sc, q, index);
13212cd0c529SMike Karels 		if (error != 0) {
13222cd0c529SMike Karels 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
13232cd0c529SMike Karels 			if (ifp->if_flags & IFF_DEBUG)
13242cd0c529SMike Karels 				device_printf(sc->dev, "gen_newbuf_rx %d\n",
13252cd0c529SMike Karels 				    error);
13262cd0c529SMike Karels 			/* reuse previous mbuf */
13272cd0c529SMike Karels 			(void) gen_mapbuf_rx(sc, q, index, m);
13282cd0c529SMike Karels 			continue;
13292cd0c529SMike Karels 		}
13302cd0c529SMike Karels 
13312cd0c529SMike Karels 		if (sb != NULL) {
13322cd0c529SMike Karels 			if (status & GENET_RX_DESC_STATUS_CKSUM_OK) {
13332cd0c529SMike Karels 				/* L4 checksum checked; not sure about L3. */
13342cd0c529SMike Karels 				m->m_pkthdr.csum_flags = CSUM_DATA_VALID |
13352cd0c529SMike Karels 				    CSUM_PSEUDO_HDR;
13362cd0c529SMike Karels 				m->m_pkthdr.csum_data = 0xffff;
13372cd0c529SMike Karels 			}
13382cd0c529SMike Karels 			m->m_data += sizeof(struct statusblock);
13392cd0c529SMike Karels 			m->m_len -= sizeof(struct statusblock);
13402cd0c529SMike Karels 			len -= sizeof(struct statusblock);
13412cd0c529SMike Karels 		}
13422cd0c529SMike Karels 		if (len > ETHER_ALIGN) {
13432cd0c529SMike Karels 			m_adj(m, ETHER_ALIGN);
13442cd0c529SMike Karels 			len -= ETHER_ALIGN;
13452cd0c529SMike Karels 		}
13462cd0c529SMike Karels 
13472cd0c529SMike Karels 		m->m_pkthdr.rcvif = ifp;
13482cd0c529SMike Karels 		m->m_pkthdr.len = len;
13492cd0c529SMike Karels 		m->m_len = len;
13502cd0c529SMike Karels 		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
13512cd0c529SMike Karels 
13522cd0c529SMike Karels 		m->m_nextpkt = NULL;
13532cd0c529SMike Karels 		if (mh == NULL)
13542cd0c529SMike Karels 			mh = m;
13552cd0c529SMike Karels 		else
13562cd0c529SMike Karels 			mt->m_nextpkt = m;
13572cd0c529SMike Karels 		mt = m;
13582cd0c529SMike Karels 		++cnt;
13592cd0c529SMike Karels 		++npkt;
13602cd0c529SMike Karels 
13612cd0c529SMike Karels 		index = RX_NEXT(index, q->nentries);
13622cd0c529SMike Karels 
13632cd0c529SMike Karels 		q->cons_idx = (q->cons_idx + 1) & GENET_RX_DMA_PROD_CONS_MASK;
13642cd0c529SMike Karels 		WR4(sc, GENET_RX_DMA_CONS_INDEX(q->hwindex), q->cons_idx);
13652cd0c529SMike Karels 
13662cd0c529SMike Karels 		if (cnt == gen_rx_batch) {
13672cd0c529SMike Karels 			GEN_UNLOCK(sc);
13682cd0c529SMike Karels 			if_input(ifp, mh);
13692cd0c529SMike Karels 			GEN_LOCK(sc);
13702cd0c529SMike Karels 			mh = mt = NULL;
13712cd0c529SMike Karels 			cnt = 0;
13722cd0c529SMike Karels 		}
13732cd0c529SMike Karels 	}
13742cd0c529SMike Karels 
13752cd0c529SMike Karels 	if (mh != NULL) {
13762cd0c529SMike Karels 		GEN_UNLOCK(sc);
13772cd0c529SMike Karels 		if_input(ifp, mh);
13782cd0c529SMike Karels 		GEN_LOCK(sc);
13792cd0c529SMike Karels 	}
13802cd0c529SMike Karels 
13812cd0c529SMike Karels 	return (npkt);
13822cd0c529SMike Karels }
13832cd0c529SMike Karels 
13842cd0c529SMike Karels static void
13852cd0c529SMike Karels gen_txintr(struct gen_softc *sc, struct tx_queue *q)
13862cd0c529SMike Karels {
13872cd0c529SMike Karels 	uint32_t cons_idx, total;
13882cd0c529SMike Karels 	struct gen_ring_ent *ent;
13892cd0c529SMike Karels 	if_t ifp;
13902cd0c529SMike Karels 	int i, prog;
13912cd0c529SMike Karels 
13922cd0c529SMike Karels 	GEN_ASSERT_LOCKED(sc);
13932cd0c529SMike Karels 
13942cd0c529SMike Karels 	ifp = sc->ifp;
13952cd0c529SMike Karels 
13962cd0c529SMike Karels 	cons_idx = RD4(sc, GENET_TX_DMA_CONS_INDEX(q->hwindex)) &
13972cd0c529SMike Karels 	    GENET_TX_DMA_PROD_CONS_MASK;
13982cd0c529SMike Karels 	total = (cons_idx - q->cons_idx) & GENET_TX_DMA_PROD_CONS_MASK;
13992cd0c529SMike Karels 
14002cd0c529SMike Karels 	prog = 0;
14012cd0c529SMike Karels 	for (i = q->next; q->queued > 0 && total > 0;
14022cd0c529SMike Karels 	    i = TX_NEXT(i, q->nentries), total--) {
14032cd0c529SMike Karels 		/* XXX check for errors */
14042cd0c529SMike Karels 
14052cd0c529SMike Karels 		ent = &q->entries[i];
14062cd0c529SMike Karels 		if (ent->mbuf != NULL) {
14072cd0c529SMike Karels 			bus_dmamap_sync(sc->tx_buf_tag, ent->map,
14082cd0c529SMike Karels 			    BUS_DMASYNC_POSTWRITE);
14092cd0c529SMike Karels 			bus_dmamap_unload(sc->tx_buf_tag, ent->map);
14102cd0c529SMike Karels 			m_freem(ent->mbuf);
14112cd0c529SMike Karels 			ent->mbuf = NULL;
14122cd0c529SMike Karels 			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
14132cd0c529SMike Karels 		}
14142cd0c529SMike Karels 
14152cd0c529SMike Karels 		prog++;
14162cd0c529SMike Karels 		--q->queued;
14172cd0c529SMike Karels 	}
14182cd0c529SMike Karels 
14192cd0c529SMike Karels 	if (prog > 0) {
14202cd0c529SMike Karels 		q->next = i;
14212cd0c529SMike Karels 		if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
14222cd0c529SMike Karels 	}
14232cd0c529SMike Karels 
14242cd0c529SMike Karels 	q->cons_idx = cons_idx;
14252cd0c529SMike Karels }
14262cd0c529SMike Karels 
14272cd0c529SMike Karels static void
14282cd0c529SMike Karels gen_intr2(void *arg)
14292cd0c529SMike Karels {
14302cd0c529SMike Karels 	struct gen_softc *sc = arg;
14312cd0c529SMike Karels 
14322cd0c529SMike Karels 	device_printf(sc->dev, "gen_intr2\n");
14332cd0c529SMike Karels }
14342cd0c529SMike Karels 
14352cd0c529SMike Karels static int
14362cd0c529SMike Karels gen_newbuf_rx(struct gen_softc *sc, struct rx_queue *q, int index)
14372cd0c529SMike Karels {
14382cd0c529SMike Karels 	struct mbuf *m;
14392cd0c529SMike Karels 
14402cd0c529SMike Karels 	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
14412cd0c529SMike Karels 	if (m == NULL)
14422cd0c529SMike Karels 		return (ENOBUFS);
14432cd0c529SMike Karels 
14442cd0c529SMike Karels 	m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
14452cd0c529SMike Karels 	m_adj(m, ETHER_ALIGN);
14462cd0c529SMike Karels 
14472cd0c529SMike Karels 	return (gen_mapbuf_rx(sc, q, index, m));
14482cd0c529SMike Karels }
14492cd0c529SMike Karels 
14502cd0c529SMike Karels static int
14512cd0c529SMike Karels gen_mapbuf_rx(struct gen_softc *sc, struct rx_queue *q, int index,
14522cd0c529SMike Karels     struct mbuf *m)
14532cd0c529SMike Karels {
14542cd0c529SMike Karels 	bus_dma_segment_t seg;
14552cd0c529SMike Karels 	bus_dmamap_t map;
14562cd0c529SMike Karels 	int nsegs;
14572cd0c529SMike Karels 
14582cd0c529SMike Karels 	map = q->entries[index].map;
14592cd0c529SMike Karels 	if (bus_dmamap_load_mbuf_sg(sc->rx_buf_tag, map, m, &seg, &nsegs,
14602cd0c529SMike Karels 	    BUS_DMA_NOWAIT) != 0) {
14612cd0c529SMike Karels 		m_freem(m);
14622cd0c529SMike Karels 		return (ENOBUFS);
14632cd0c529SMike Karels 	}
14642cd0c529SMike Karels 
14652cd0c529SMike Karels 	bus_dmamap_sync(sc->rx_buf_tag, map, BUS_DMASYNC_PREREAD);
14662cd0c529SMike Karels 
14672cd0c529SMike Karels 	q->entries[index].mbuf = m;
14682cd0c529SMike Karels 	WR4(sc, GENET_RX_DESC_ADDRESS_LO(index), (uint32_t)seg.ds_addr);
14692cd0c529SMike Karels 	WR4(sc, GENET_RX_DESC_ADDRESS_HI(index), (uint32_t)(seg.ds_addr >> 32));
14702cd0c529SMike Karels 
14712cd0c529SMike Karels 	return (0);
14722cd0c529SMike Karels }
14732cd0c529SMike Karels 
14742cd0c529SMike Karels static int
14752cd0c529SMike Karels gen_ioctl(if_t ifp, u_long cmd, caddr_t data)
14762cd0c529SMike Karels {
14772cd0c529SMike Karels 	struct gen_softc *sc;
14782cd0c529SMike Karels 	struct mii_data *mii;
14792cd0c529SMike Karels 	struct ifreq *ifr;
14802cd0c529SMike Karels 	int flags, enable, error;
14812cd0c529SMike Karels 
14822cd0c529SMike Karels 	sc = if_getsoftc(ifp);
14832cd0c529SMike Karels 	mii = device_get_softc(sc->miibus);
14842cd0c529SMike Karels 	ifr = (struct ifreq *)data;
14852cd0c529SMike Karels 	error = 0;
14862cd0c529SMike Karels 
14872cd0c529SMike Karels 	switch (cmd) {
14882cd0c529SMike Karels 	case SIOCSIFFLAGS:
14892cd0c529SMike Karels 		GEN_LOCK(sc);
14902cd0c529SMike Karels 		if (if_getflags(ifp) & IFF_UP) {
14912cd0c529SMike Karels 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
14922cd0c529SMike Karels 				flags = if_getflags(ifp) ^ sc->if_flags;
14932cd0c529SMike Karels 				if ((flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0)
14942cd0c529SMike Karels 					gen_setup_rxfilter(sc);
14952cd0c529SMike Karels 			} else
14962cd0c529SMike Karels 				gen_init_locked(sc);
14972cd0c529SMike Karels 		} else {
14982cd0c529SMike Karels 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
14992cd0c529SMike Karels 				gen_reset(sc);
15002cd0c529SMike Karels 		}
15012cd0c529SMike Karels 		sc->if_flags = if_getflags(ifp);
15022cd0c529SMike Karels 		GEN_UNLOCK(sc);
15032cd0c529SMike Karels 		break;
15042cd0c529SMike Karels 
15052cd0c529SMike Karels 	case SIOCADDMULTI:
15062cd0c529SMike Karels 	case SIOCDELMULTI:
15072cd0c529SMike Karels 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
15082cd0c529SMike Karels 			GEN_LOCK(sc);
15092cd0c529SMike Karels 			gen_setup_rxfilter(sc);
15102cd0c529SMike Karels 			GEN_UNLOCK(sc);
15112cd0c529SMike Karels 		}
15122cd0c529SMike Karels 		break;
15132cd0c529SMike Karels 
15142cd0c529SMike Karels 	case SIOCSIFMEDIA:
15152cd0c529SMike Karels 	case SIOCGIFMEDIA:
15162cd0c529SMike Karels 		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
15172cd0c529SMike Karels 		break;
15182cd0c529SMike Karels 
15192cd0c529SMike Karels 	case SIOCSIFCAP:
15202cd0c529SMike Karels 		enable = if_getcapenable(ifp);
15212cd0c529SMike Karels 		flags = ifr->ifr_reqcap ^ enable;
15222cd0c529SMike Karels 		if (flags & IFCAP_RXCSUM)
15232cd0c529SMike Karels 			enable ^= IFCAP_RXCSUM;
15242cd0c529SMike Karels 		if (flags & IFCAP_RXCSUM_IPV6)
15252cd0c529SMike Karels 			enable ^= IFCAP_RXCSUM_IPV6;
15262cd0c529SMike Karels 		if (flags & IFCAP_TXCSUM)
15272cd0c529SMike Karels 			enable ^= IFCAP_TXCSUM;
15282cd0c529SMike Karels 		if (flags & IFCAP_TXCSUM_IPV6)
15292cd0c529SMike Karels 			enable ^= IFCAP_TXCSUM_IPV6;
15302cd0c529SMike Karels 		if (enable & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6))
15312cd0c529SMike Karels 			if_sethwassist(ifp, GEN_CSUM_FEATURES);
15322cd0c529SMike Karels 		else
15332cd0c529SMike Karels 			if_sethwassist(ifp, 0);
15342cd0c529SMike Karels 		if_setcapenable(ifp, enable);
15352cd0c529SMike Karels 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
15362cd0c529SMike Karels 			gen_enable_offload(sc);
15372cd0c529SMike Karels 		break;
15382cd0c529SMike Karels 
15392cd0c529SMike Karels 	default:
15402cd0c529SMike Karels 		error = ether_ioctl(ifp, cmd, data);
15412cd0c529SMike Karels 		break;
15422cd0c529SMike Karels 	}
15432cd0c529SMike Karels 	return (error);
15442cd0c529SMike Karels }
15452cd0c529SMike Karels 
15462cd0c529SMike Karels static void
15472cd0c529SMike Karels gen_tick(void *softc)
15482cd0c529SMike Karels {
15492cd0c529SMike Karels 	struct gen_softc *sc;
15502cd0c529SMike Karels 	struct mii_data *mii;
15512cd0c529SMike Karels 	if_t ifp;
15522cd0c529SMike Karels 	int link;
15532cd0c529SMike Karels 
15542cd0c529SMike Karels 	sc = softc;
15552cd0c529SMike Karels 	ifp = sc->ifp;
15562cd0c529SMike Karels 	mii = device_get_softc(sc->miibus);
15572cd0c529SMike Karels 
15582cd0c529SMike Karels 	GEN_ASSERT_LOCKED(sc);
15592cd0c529SMike Karels 
15602cd0c529SMike Karels 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
15612cd0c529SMike Karels 		return;
15622cd0c529SMike Karels 
15632cd0c529SMike Karels 	link = sc->link;
15642cd0c529SMike Karels 	mii_tick(mii);
15652cd0c529SMike Karels 	if (sc->link && !link)
15662cd0c529SMike Karels 		gen_start_locked(sc);
15672cd0c529SMike Karels 
15682cd0c529SMike Karels 	callout_reset(&sc->stat_ch, hz, gen_tick, sc);
15692cd0c529SMike Karels }
15702cd0c529SMike Karels 
15712cd0c529SMike Karels #define	MII_BUSY_RETRY		1000
15722cd0c529SMike Karels 
15732cd0c529SMike Karels static int
15742cd0c529SMike Karels gen_miibus_readreg(device_t dev, int phy, int reg)
15752cd0c529SMike Karels {
15762cd0c529SMike Karels 	struct gen_softc *sc;
15772cd0c529SMike Karels 	int retry, val;
15782cd0c529SMike Karels 
15792cd0c529SMike Karels 	sc = device_get_softc(dev);
15802cd0c529SMike Karels 	val = 0;
15812cd0c529SMike Karels 
15822cd0c529SMike Karels 	WR4(sc, GENET_MDIO_CMD, GENET_MDIO_READ |
15832cd0c529SMike Karels 	    (phy << GENET_MDIO_ADDR_SHIFT) | (reg << GENET_MDIO_REG_SHIFT));
15842cd0c529SMike Karels 	val = RD4(sc, GENET_MDIO_CMD);
15852cd0c529SMike Karels 	WR4(sc, GENET_MDIO_CMD, val | GENET_MDIO_START_BUSY);
15862cd0c529SMike Karels 	for (retry = MII_BUSY_RETRY; retry > 0; retry--) {
15872cd0c529SMike Karels 		if (((val = RD4(sc, GENET_MDIO_CMD)) &
15882cd0c529SMike Karels 		    GENET_MDIO_START_BUSY) == 0) {
15892cd0c529SMike Karels 			if (val & GENET_MDIO_READ_FAILED)
15902cd0c529SMike Karels 				return (0);	/* -1? */
15912cd0c529SMike Karels 			val &= GENET_MDIO_VAL_MASK;
15922cd0c529SMike Karels 			break;
15932cd0c529SMike Karels 		}
15942cd0c529SMike Karels 		DELAY(10);
15952cd0c529SMike Karels 	}
15962cd0c529SMike Karels 
15972cd0c529SMike Karels 	if (retry == 0)
15982cd0c529SMike Karels 		device_printf(dev, "phy read timeout, phy=%d reg=%d\n",
15992cd0c529SMike Karels 		    phy, reg);
16002cd0c529SMike Karels 
16012cd0c529SMike Karels 	return (val);
16022cd0c529SMike Karels }
16032cd0c529SMike Karels 
16042cd0c529SMike Karels static int
16052cd0c529SMike Karels gen_miibus_writereg(device_t dev, int phy, int reg, int val)
16062cd0c529SMike Karels {
16072cd0c529SMike Karels 	struct gen_softc *sc;
16082cd0c529SMike Karels 	int retry;
16092cd0c529SMike Karels 
16102cd0c529SMike Karels 	sc = device_get_softc(dev);
16112cd0c529SMike Karels 
16122cd0c529SMike Karels 	WR4(sc, GENET_MDIO_CMD, GENET_MDIO_WRITE |
16132cd0c529SMike Karels 	    (phy << GENET_MDIO_ADDR_SHIFT) | (reg << GENET_MDIO_REG_SHIFT) |
16142cd0c529SMike Karels 	    (val & GENET_MDIO_VAL_MASK));
16152cd0c529SMike Karels 	val = RD4(sc, GENET_MDIO_CMD);
16162cd0c529SMike Karels 	WR4(sc, GENET_MDIO_CMD, val | GENET_MDIO_START_BUSY);
16172cd0c529SMike Karels 	for (retry = MII_BUSY_RETRY; retry > 0; retry--) {
16182cd0c529SMike Karels 		val = RD4(sc, GENET_MDIO_CMD);
16192cd0c529SMike Karels 		if ((val & GENET_MDIO_START_BUSY) == 0)
16202cd0c529SMike Karels 			break;
16212cd0c529SMike Karels 		DELAY(10);
16222cd0c529SMike Karels 	}
16232cd0c529SMike Karels 	if (retry == 0)
16242cd0c529SMike Karels 		device_printf(dev, "phy write timeout, phy=%d reg=%d\n",
16252cd0c529SMike Karels 		    phy, reg);
16262cd0c529SMike Karels 
16272cd0c529SMike Karels 	return (0);
16282cd0c529SMike Karels }
16292cd0c529SMike Karels 
16302cd0c529SMike Karels static void
16312cd0c529SMike Karels gen_update_link_locked(struct gen_softc *sc)
16322cd0c529SMike Karels {
16332cd0c529SMike Karels 	struct mii_data *mii;
16342cd0c529SMike Karels 	uint32_t val;
16352cd0c529SMike Karels 	u_int speed;
16362cd0c529SMike Karels 
16372cd0c529SMike Karels 	GEN_ASSERT_LOCKED(sc);
16382cd0c529SMike Karels 
16392cd0c529SMike Karels 	if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) == 0)
16402cd0c529SMike Karels 		return;
16412cd0c529SMike Karels 	mii = device_get_softc(sc->miibus);
16422cd0c529SMike Karels 
16432cd0c529SMike Karels 	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
16442cd0c529SMike Karels 	    (IFM_ACTIVE | IFM_AVALID)) {
16452cd0c529SMike Karels 		switch (IFM_SUBTYPE(mii->mii_media_active)) {
16462cd0c529SMike Karels 		case IFM_1000_T:
16472cd0c529SMike Karels 		case IFM_1000_SX:
16482cd0c529SMike Karels 			speed = GENET_UMAC_CMD_SPEED_1000;
16492cd0c529SMike Karels 			sc->link = 1;
16502cd0c529SMike Karels 			break;
16512cd0c529SMike Karels 		case IFM_100_TX:
16522cd0c529SMike Karels 			speed = GENET_UMAC_CMD_SPEED_100;
16532cd0c529SMike Karels 			sc->link = 1;
16542cd0c529SMike Karels 			break;
16552cd0c529SMike Karels 		case IFM_10_T:
16562cd0c529SMike Karels 			speed = GENET_UMAC_CMD_SPEED_10;
16572cd0c529SMike Karels 			sc->link = 1;
16582cd0c529SMike Karels 			break;
16592cd0c529SMike Karels 		default:
16602cd0c529SMike Karels 			sc->link = 0;
16612cd0c529SMike Karels 			break;
16622cd0c529SMike Karels 		}
16632cd0c529SMike Karels 	} else
16642cd0c529SMike Karels 		sc->link = 0;
16652cd0c529SMike Karels 
16662cd0c529SMike Karels 	if (sc->link == 0)
16672cd0c529SMike Karels 		return;
16682cd0c529SMike Karels 
16692cd0c529SMike Karels 	val = RD4(sc, GENET_EXT_RGMII_OOB_CTRL);
16702cd0c529SMike Karels 	val &= ~GENET_EXT_RGMII_OOB_OOB_DISABLE;
16712cd0c529SMike Karels 	val |= GENET_EXT_RGMII_OOB_RGMII_LINK;
16722cd0c529SMike Karels 	val |= GENET_EXT_RGMII_OOB_RGMII_MODE_EN;
16732cd0c529SMike Karels 	if (sc->phy_mode == MII_CONTYPE_RGMII)
16742cd0c529SMike Karels 		val |= GENET_EXT_RGMII_OOB_ID_MODE_DISABLE;
1675*349eddbdSMike Karels 	else
1676*349eddbdSMike Karels 		val &= ~GENET_EXT_RGMII_OOB_ID_MODE_DISABLE;
16772cd0c529SMike Karels 	WR4(sc, GENET_EXT_RGMII_OOB_CTRL, val);
16782cd0c529SMike Karels 
16792cd0c529SMike Karels 	val = RD4(sc, GENET_UMAC_CMD);
16802cd0c529SMike Karels 	val &= ~GENET_UMAC_CMD_SPEED;
16812cd0c529SMike Karels 	val |= speed;
16822cd0c529SMike Karels 	WR4(sc, GENET_UMAC_CMD, val);
16832cd0c529SMike Karels }
16842cd0c529SMike Karels 
16852cd0c529SMike Karels static void
16862cd0c529SMike Karels gen_link_task(void *arg, int pending)
16872cd0c529SMike Karels {
16882cd0c529SMike Karels 	struct gen_softc *sc;
16892cd0c529SMike Karels 
16902cd0c529SMike Karels 	sc = arg;
16912cd0c529SMike Karels 
16922cd0c529SMike Karels 	GEN_LOCK(sc);
16932cd0c529SMike Karels 	gen_update_link_locked(sc);
16942cd0c529SMike Karels 	GEN_UNLOCK(sc);
16952cd0c529SMike Karels }
16962cd0c529SMike Karels 
16972cd0c529SMike Karels static void
16982cd0c529SMike Karels gen_miibus_statchg(device_t dev)
16992cd0c529SMike Karels {
17002cd0c529SMike Karels 	struct gen_softc *sc;
17012cd0c529SMike Karels 
17022cd0c529SMike Karels 	sc = device_get_softc(dev);
17032cd0c529SMike Karels 
17042cd0c529SMike Karels 	taskqueue_enqueue(taskqueue_swi, &sc->link_task);
17052cd0c529SMike Karels }
17062cd0c529SMike Karels 
17072cd0c529SMike Karels static void
17082cd0c529SMike Karels gen_media_status(if_t ifp, struct ifmediareq *ifmr)
17092cd0c529SMike Karels {
17102cd0c529SMike Karels 	struct gen_softc *sc;
17112cd0c529SMike Karels 	struct mii_data *mii;
17122cd0c529SMike Karels 
17132cd0c529SMike Karels 	sc = if_getsoftc(ifp);
17142cd0c529SMike Karels 	mii = device_get_softc(sc->miibus);
17152cd0c529SMike Karels 
17162cd0c529SMike Karels 	GEN_LOCK(sc);
17172cd0c529SMike Karels 	mii_pollstat(mii);
17182cd0c529SMike Karels 	ifmr->ifm_active = mii->mii_media_active;
17192cd0c529SMike Karels 	ifmr->ifm_status = mii->mii_media_status;
17202cd0c529SMike Karels 	GEN_UNLOCK(sc);
17212cd0c529SMike Karels }
17222cd0c529SMike Karels 
17232cd0c529SMike Karels static int
17242cd0c529SMike Karels gen_media_change(if_t ifp)
17252cd0c529SMike Karels {
17262cd0c529SMike Karels 	struct gen_softc *sc;
17272cd0c529SMike Karels 	struct mii_data *mii;
17282cd0c529SMike Karels 	int error;
17292cd0c529SMike Karels 
17302cd0c529SMike Karels 	sc = if_getsoftc(ifp);
17312cd0c529SMike Karels 	mii = device_get_softc(sc->miibus);
17322cd0c529SMike Karels 
17332cd0c529SMike Karels 	GEN_LOCK(sc);
17342cd0c529SMike Karels 	error = mii_mediachg(mii);
17352cd0c529SMike Karels 	GEN_UNLOCK(sc);
17362cd0c529SMike Karels 
17372cd0c529SMike Karels 	return (error);
17382cd0c529SMike Karels }
17392cd0c529SMike Karels 
17402cd0c529SMike Karels static device_method_t gen_methods[] = {
17412cd0c529SMike Karels 	/* Device interface */
17422cd0c529SMike Karels 	DEVMETHOD(device_probe,		gen_probe),
17432cd0c529SMike Karels 	DEVMETHOD(device_attach,	gen_attach),
17442cd0c529SMike Karels 
17452cd0c529SMike Karels 	/* MII interface */
17462cd0c529SMike Karels 	DEVMETHOD(miibus_readreg,	gen_miibus_readreg),
17472cd0c529SMike Karels 	DEVMETHOD(miibus_writereg,	gen_miibus_writereg),
17482cd0c529SMike Karels 	DEVMETHOD(miibus_statchg,	gen_miibus_statchg),
17492cd0c529SMike Karels 
17502cd0c529SMike Karels 	DEVMETHOD_END
17512cd0c529SMike Karels };
17522cd0c529SMike Karels 
17532cd0c529SMike Karels static driver_t gen_driver = {
17542cd0c529SMike Karels 	"genet",
17552cd0c529SMike Karels 	gen_methods,
17562cd0c529SMike Karels 	sizeof(struct gen_softc),
17572cd0c529SMike Karels };
17582cd0c529SMike Karels 
17592cd0c529SMike Karels static devclass_t gen_devclass;
17602cd0c529SMike Karels 
17612cd0c529SMike Karels DRIVER_MODULE(genet, simplebus, gen_driver, gen_devclass, 0, 0);
17622cd0c529SMike Karels DRIVER_MODULE(miibus, genet, miibus_driver, miibus_devclass, 0, 0);
17632cd0c529SMike Karels MODULE_DEPEND(genet, ether, 1, 1, 1);
17642cd0c529SMike Karels MODULE_DEPEND(genet, miibus, 1, 1, 1);
1765