Page MenuHomeFreeBSD

D7238.diff
No OneTemporary

D7238.diff

Index: head/sys/arm/conf/RT1310
===================================================================
--- head/sys/arm/conf/RT1310
+++ head/sys/arm/conf/RT1310
@@ -0,0 +1,80 @@
+#
+# Custom kernel for RT1310 boards.
+#
+# $FreeBSD$
+#
+
+ident RT1310
+include "std.arm"
+hints "RT1310.hints"
+
+# Flattened Device Tree
+options FDT
+options FDT_DTB_STATIC
+makeoptions FDT_DTS_FILE=wzr2-g300n.dts
+
+makeoptions MODULES_OVERRIDE=""
+
+#makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols
+makeoptions WERROR="-Werror"
+
+options SCHED_4BSD # 4BSD scheduler
+options INET # InterNETworking
+options FFS # Berkeley Fast Filesystem
+options TMPFS # Efficient memory filesystem
+options MSDOSFS
+
+options ROOTDEVNAME=\"cd9660:/dev/cfid0s.rootfs.uzip\"
+
+options SYSVSHM # SYSV-style shared memory
+options SYSVMSG # SYSV-style message queues
+options SYSVSEM # SYSV-style semaphores
+options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B real-time extensions
+options MUTEX_NOINLINE
+options RWLOCK_NOINLINE
+options NO_FFS_SNAPSHOT
+options NO_SWAPPING
+
+# Debugging
+options ALT_BREAK_TO_DEBUGGER
+options DDB
+#options DEADLKRES # Enable the deadlock resolver
+#options DIAGNOSTIC
+#options INVARIANTS # Enable calls of extra sanity checking
+#options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS
+options KDB
+options WITNESS # Enable checks to detect deadlocks and cycles
+options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed
+#options WITNESS_KDB
+
+# Pseudo devices
+device loop
+device md
+device pty
+device random
+
+# Serial ports
+device uart
+device uart_ns8250
+
+# Flash
+device cfi
+device cfid
+
+# Networking
+device ether
+device mii
+device bpf
+device fv
+
+# etherswitch
+device mdio
+device etherswitch
+device miiproxy
+device ip17x
+
+# GPIO
+device gpio
+device gpioled
+device rt1310gpio
+
Index: head/sys/arm/ralink/files.ralink
===================================================================
--- head/sys/arm/ralink/files.ralink
+++ head/sys/arm/ralink/files.ralink
@@ -0,0 +1,9 @@
+# $FreeBSD$
+arm/ralink/rt1310_machdep.c standard
+arm/ralink/rt1310_intc.c standard
+arm/ralink/rt1310_gpio.c optional rt1310gpio
+arm/ralink/rt1310_timer.c standard
+arm/ralink/if_fv.c optional fv
+
+kern/kern_clocksource.c standard
+
Index: head/sys/arm/ralink/if_fv.c
===================================================================
--- head/sys/arm/ralink/if_fv.c
+++ head/sys/arm/ralink/if_fv.c
@@ -0,0 +1,1873 @@
+/*-
+ * Copyright (c) 2016 Hiroki Mori. All rights reserved.
+ * Copyright (C) 2007
+ * Oleksandr Tymoshenko <gonzo@freebsd.org>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWFV IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE FV DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWFV, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: $
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * FV Ethernet interface driver
+ * copy from mips/idt/if_kr.c and netbsd code
+ */
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/socket.h>
+#include <sys/taskqueue.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+
+#include <net/bpf.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+/* Todo: move to options.arm */
+/*#define FV_MDIO*/
+
+#ifdef FV_MDIO
+#include <dev/mdio/mdio.h>
+#include <dev/etherswitch/miiproxy.h>
+#include "mdio_if.h"
+#endif
+
+MODULE_DEPEND(are, ether, 1, 1, 1);
+MODULE_DEPEND(are, miibus, 1, 1, 1);
+#ifdef FV_MDIO
+MODULE_DEPEND(are, mdio, 1, 1, 1);
+#endif
+
+#include "miibus_if.h"
+
+#include <arm/ralink/if_fvreg.h>
+
+#ifdef FV_DEBUG
+void dump_txdesc(struct fv_softc *, int);
+void dump_status_reg(struct fv_softc *);
+#endif
+
+static int fv_attach(device_t);
+static int fv_detach(device_t);
+static int fv_ifmedia_upd(struct ifnet *);
+static void fv_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int fv_ioctl(struct ifnet *, u_long, caddr_t);
+static void fv_init(void *);
+static void fv_init_locked(struct fv_softc *);
+static void fv_link_task(void *, int);
+static int fv_miibus_readreg(device_t, int, int);
+static void fv_miibus_statchg(device_t);
+static int fv_miibus_writereg(device_t, int, int, int);
+static int fv_probe(device_t);
+static void fv_reset(struct fv_softc *);
+static int fv_resume(device_t);
+static int fv_rx_ring_init(struct fv_softc *);
+static int fv_tx_ring_init(struct fv_softc *);
+static int fv_shutdown(device_t);
+static void fv_start(struct ifnet *);
+static void fv_start_locked(struct ifnet *);
+static void fv_stop(struct fv_softc *);
+static int fv_suspend(device_t);
+
+static void fv_rx(struct fv_softc *);
+static void fv_tx(struct fv_softc *);
+static void fv_intr(void *);
+static void fv_tick(void *);
+
+static void fv_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+static int fv_dma_alloc(struct fv_softc *);
+static void fv_dma_free(struct fv_softc *);
+static int fv_newbuf(struct fv_softc *, int);
+static __inline void fv_fixup_rx(struct mbuf *);
+
+static void fv_hinted_child(device_t bus, const char *dname, int dunit);
+
+static void fv_setfilt(struct fv_softc *sc);
+
+static device_method_t fv_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, fv_probe),
+ DEVMETHOD(device_attach, fv_attach),
+ DEVMETHOD(device_detach, fv_detach),
+ DEVMETHOD(device_suspend, fv_suspend),
+ DEVMETHOD(device_resume, fv_resume),
+ DEVMETHOD(device_shutdown, fv_shutdown),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, fv_miibus_readreg),
+ DEVMETHOD(miibus_writereg, fv_miibus_writereg),
+#if !defined(FV_MDIO)
+ DEVMETHOD(miibus_statchg, fv_miibus_statchg),
+#endif
+
+ /* bus interface */
+ DEVMETHOD(bus_add_child, device_add_child_ordered),
+ DEVMETHOD(bus_hinted_child, fv_hinted_child),
+
+ DEVMETHOD_END
+};
+
+static driver_t fv_driver = {
+ "fv",
+ fv_methods,
+ sizeof(struct fv_softc)
+};
+
+static devclass_t fv_devclass;
+
+DRIVER_MODULE(fv, simplebus, fv_driver, fv_devclass, 0, 0);
+#ifdef MII
+DRIVER_MODULE(miibus, fv, miibus_driver, miibus_devclass, 0, 0);
+#endif
+
+static struct mtx miibus_mtx;
+MTX_SYSINIT(miibus_mtx, &miibus_mtx, "are mii lock", MTX_DEF);
+
+#ifdef FV_MDIO
+static int fvmdio_probe(device_t);
+static int fvmdio_attach(device_t);
+static int fvmdio_detach(device_t);
+
+/*
+ * Declare an additional, separate driver for accessing the MDIO bus.
+ */
+static device_method_t fvmdio_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, fvmdio_probe),
+ DEVMETHOD(device_attach, fvmdio_attach),
+ DEVMETHOD(device_detach, fvmdio_detach),
+
+ /* bus interface */
+ DEVMETHOD(bus_add_child, device_add_child_ordered),
+
+ /* MDIO access */
+ DEVMETHOD(mdio_readreg, fv_miibus_readreg),
+ DEVMETHOD(mdio_writereg, fv_miibus_writereg),
+};
+
+DEFINE_CLASS_0(fvmdio, fvmdio_driver, fvmdio_methods,
+ sizeof(struct fv_softc));
+static devclass_t fvmdio_devclass;
+
+DRIVER_MODULE(miiproxy, fv, miiproxy_driver, miiproxy_devclass, 0, 0);
+DRIVER_MODULE(fvmdio, simplebus, fvmdio_driver, fvmdio_devclass, 0, 0);
+DRIVER_MODULE(mdio, fvmdio, mdio_driver, mdio_devclass, 0, 0);
+#endif
+
+/* setup frame code refer dc code */
+
+static void
+fv_setfilt(struct fv_softc *sc)
+{
+ uint16_t eaddr[(ETHER_ADDR_LEN+1)/2];
+ struct fv_desc *sframe;
+ int i;
+ struct ifnet *ifp;
+ struct ifmultiaddr *ifma;
+ uint16_t *sp;
+ uint8_t *ma;
+
+ ifp = sc->fv_ifp;
+
+ i = sc->fv_cdata.fv_tx_prod;
+ FV_INC(sc->fv_cdata.fv_tx_prod, FV_TX_RING_CNT);
+ sc->fv_cdata.fv_tx_cnt++;
+ sframe = &sc->fv_rdata.fv_tx_ring[i];
+ sp = (uint16_t *)sc->fv_cdata.fv_sf_buff;
+ memset(sp, 0xff, FV_SFRAME_LEN);
+
+ sframe->fv_addr = sc->fv_rdata.fv_sf_paddr;
+ sframe->fv_devcs = ADCTL_Tx_SETUP | FV_DMASIZE(FV_SFRAME_LEN);
+
+ i = 0;
+ if_maddr_rlock(ifp);
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ ma = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
+ sp[i] = sp[i+1] = (ma[1] << 8 | ma[0]);
+ i += 2;
+ sp[i] = sp[i+1] = (ma[3] << 8 | ma[2]);
+ i += 2;
+ sp[i] = sp[i+1] = (ma[5] << 8 | ma[4]);
+ i += 2;
+ }
+ if_maddr_runlock(ifp);
+
+ bcopy(IF_LLADDR(sc->fv_ifp), eaddr, ETHER_ADDR_LEN);
+ sp[90] = sp[91] = eaddr[0];
+ sp[92] = sp[93] = eaddr[1];
+ sp[94] = sp[95] = eaddr[2];
+
+ sframe->fv_stat = ADSTAT_OWN;
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map, BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->fv_cdata.fv_sf_tag,
+ sc->fv_cdata.fv_sf_buff_map, BUS_DMASYNC_PREWRITE);
+ CSR_WRITE_4(sc, CSR_TXPOLL, 0xFFFFFFFF);
+ DELAY(10000);
+}
+
+static int
+fv_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "fv,ethernet"))
+ return (ENXIO);
+
+ device_set_desc(dev, "FV Ethernet interface");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+fv_attach(device_t dev)
+{
+ struct ifnet *ifp;
+ struct fv_softc *sc;
+ int error = 0, rid;
+ int unit;
+ int i;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ sc->fv_dev = dev;
+ sc->fv_ofw = ofw_bus_get_node(dev);
+
+ i = OF_getprop(sc->fv_ofw, "local-mac-address", (void *)&sc->fv_eaddr, 6);
+ if (i != 6) {
+ /* hardcode macaddress */
+ sc->fv_eaddr[0] = 0x00;
+ sc->fv_eaddr[1] = 0x0C;
+ sc->fv_eaddr[2] = 0x42;
+ sc->fv_eaddr[3] = 0x09;
+ sc->fv_eaddr[4] = 0x5E;
+ sc->fv_eaddr[5] = 0x6B;
+ }
+
+ mtx_init(&sc->fv_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF);
+ callout_init_mtx(&sc->fv_stat_callout, &sc->fv_mtx, 0);
+ TASK_INIT(&sc->fv_link_task, 0, fv_link_task, sc);
+
+ /* Map control/status registers. */
+ sc->fv_rid = 0;
+ sc->fv_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->fv_rid,
+ RF_ACTIVE | RF_SHAREABLE);
+
+ if (sc->fv_res == NULL) {
+ device_printf(dev, "couldn't map memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->fv_btag = rman_get_bustag(sc->fv_res);
+ sc->fv_bhandle = rman_get_bushandle(sc->fv_res);
+
+ /* Allocate interrupts */
+ rid = 0;
+ sc->fv_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->fv_irq == NULL) {
+ device_printf(dev, "couldn't map interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Allocate ifnet structure. */
+ ifp = sc->fv_ifp = if_alloc(IFT_ETHER);
+
+ if (ifp == NULL) {
+ device_printf(dev, "couldn't allocate ifnet structure\n");
+ error = ENOSPC;
+ goto fail;
+ }
+ ifp->if_softc = sc;
+ if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = fv_ioctl;
+ ifp->if_start = fv_start;
+ ifp->if_init = fv_init;
+
+ /* ifqmaxlen is sysctl value in net/if.c */
+ IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ ifp->if_capenable = ifp->if_capabilities;
+
+ if (fv_dma_alloc(sc) != 0) {
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* TODO: calculate prescale */
+/*
+ CSR_WRITE_4(sc, FV_ETHMCP, (165000000 / (1250000 + 1)) & ~1);
+
+ CSR_WRITE_4(sc, FV_MIIMCFG, FV_MIIMCFG_R);
+ DELAY(1000);
+ CSR_WRITE_4(sc, FV_MIIMCFG, 0);
+*/
+ CSR_WRITE_4(sc, CSR_BUSMODE, BUSMODE_SWR);
+ DELAY(1000);
+
+#ifdef FV_MDIO
+ sc->fv_miiproxy = mii_attach_proxy(sc->fv_dev);
+#endif
+
+#ifdef MII
+ /* Do MII setup. */
+ error = mii_attach(dev, &sc->fv_miibus, ifp, fv_ifmedia_upd,
+ fv_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0);
+ if (error != 0) {
+ device_printf(dev, "attaching PHYs failed\n");
+ goto fail;
+ }
+#else
+ ifmedia_init(&sc->fv_ifmedia, 0, fv_ifmedia_upd, fv_ifmedia_sts);
+
+ ifmedia_add(&sc->fv_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
+ ifmedia_set(&sc->fv_ifmedia, IFM_ETHER | IFM_AUTO);
+#endif
+
+ /* Call MI attach routine. */
+ ether_ifattach(ifp, sc->fv_eaddr);
+
+ /* Hook interrupt last to avoid having to lock softc */
+ error = bus_setup_intr(dev, sc->fv_irq, INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, fv_intr, sc, &sc->fv_intrhand);
+
+ if (error) {
+ device_printf(dev, "couldn't set up irq\n");
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+
+fail:
+ if (error)
+ fv_detach(dev);
+
+ return (error);
+}
+
+static int
+fv_detach(device_t dev)
+{
+ struct fv_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = sc->fv_ifp;
+
+ KASSERT(mtx_initialized(&sc->fv_mtx), ("vr mutex not initialized"));
+
+ /* These should only be active if attach succeeded */
+ if (device_is_attached(dev)) {
+ FV_LOCK(sc);
+ sc->fv_detach = 1;
+ fv_stop(sc);
+ FV_UNLOCK(sc);
+ taskqueue_drain(taskqueue_swi, &sc->fv_link_task);
+ ether_ifdetach(ifp);
+ }
+#ifdef MII
+ if (sc->fv_miibus)
+ device_delete_child(dev, sc->fv_miibus);
+#endif
+ bus_generic_detach(dev);
+
+ if (sc->fv_intrhand)
+ bus_teardown_intr(dev, sc->fv_irq, sc->fv_intrhand);
+ if (sc->fv_irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->fv_irq);
+
+ if (sc->fv_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->fv_rid,
+ sc->fv_res);
+
+ if (ifp)
+ if_free(ifp);
+
+ fv_dma_free(sc);
+
+ mtx_destroy(&sc->fv_mtx);
+
+ return (0);
+
+}
+
+static int
+fv_suspend(device_t dev)
+{
+
+ panic("%s", __func__);
+ return 0;
+}
+
+static int
+fv_resume(device_t dev)
+{
+
+ panic("%s", __func__);
+ return 0;
+}
+
+static int
+fv_shutdown(device_t dev)
+{
+ struct fv_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ FV_LOCK(sc);
+ fv_stop(sc);
+ FV_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+fv_miibus_readbits(struct fv_softc *sc, int count)
+{
+ int result;
+
+ result = 0;
+ while(count--) {
+ result <<= 1;
+ CSR_WRITE_4(sc, CSR_MIIMNG, MII_RD);
+ DELAY(10);
+ CSR_WRITE_4(sc, CSR_MIIMNG, MII_RD | MII_CLK);
+ DELAY(10);
+ if (CSR_READ_4(sc, CSR_MIIMNG) & MII_DIN)
+ result |= 1;
+ }
+
+ return (result);
+}
+
+static int
+fv_miibus_writebits(struct fv_softc *sc, int data, int count)
+{
+ int bit;
+
+ while(count--) {
+ bit = ((data) >> count) & 0x1 ? MII_DOUT : 0;
+ CSR_WRITE_4(sc, CSR_MIIMNG, bit | MII_WR);
+ DELAY(10);
+ CSR_WRITE_4(sc, CSR_MIIMNG, bit | MII_WR | MII_CLK);
+ DELAY(10);
+ }
+
+ return (0);
+}
+
+static void
+fv_miibus_turnaround(struct fv_softc *sc, int cmd)
+{
+ if (cmd == MII_WRCMD) {
+ fv_miibus_writebits(sc, 0x02, 2);
+ } else {
+ fv_miibus_readbits(sc, 1);
+ }
+}
+
+static int
+fv_miibus_readreg(device_t dev, int phy, int reg)
+{
+ struct fv_softc * sc = device_get_softc(dev);
+ int result;
+
+ mtx_lock(&miibus_mtx);
+ fv_miibus_writebits(sc, MII_PREAMBLE, 32);
+ fv_miibus_writebits(sc, MII_RDCMD, 4);
+ fv_miibus_writebits(sc, phy, 5);
+ fv_miibus_writebits(sc, reg, 5);
+ fv_miibus_turnaround(sc, MII_RDCMD);
+ result = fv_miibus_readbits(sc, 16);
+ fv_miibus_turnaround(sc, MII_RDCMD);
+ mtx_unlock(&miibus_mtx);
+
+ return (result);
+}
+
+static int
+fv_miibus_writereg(device_t dev, int phy, int reg, int data)
+{
+ struct fv_softc * sc = device_get_softc(dev);
+
+ mtx_lock(&miibus_mtx);
+ fv_miibus_writebits(sc, MII_PREAMBLE, 32);
+ fv_miibus_writebits(sc, MII_WRCMD, 4);
+ fv_miibus_writebits(sc, phy, 5);
+ fv_miibus_writebits(sc, reg, 5);
+ fv_miibus_turnaround(sc, MII_WRCMD);
+ fv_miibus_writebits(sc, data, 16);
+ mtx_unlock(&miibus_mtx);
+
+ return (0);
+}
+
+#if !defined(FV_MDIO)
+static void
+fv_miibus_statchg(device_t dev)
+{
+ struct fv_softc *sc;
+
+ sc = device_get_softc(dev);
+ taskqueue_enqueue(taskqueue_swi, &sc->fv_link_task);
+}
+#endif
+
+static void
+fv_link_task(void *arg, int pending)
+{
+#ifdef MII
+ struct fv_softc *sc;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ /* int lfdx, mfdx; */
+
+ sc = (struct fv_softc *)arg;
+
+ FV_LOCK(sc);
+ mii = device_get_softc(sc->fv_miibus);
+ ifp = sc->fv_ifp;
+ if (mii == NULL || ifp == NULL ||
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ FV_UNLOCK(sc);
+ return;
+ }
+
+ if (mii->mii_media_status & IFM_ACTIVE) {
+ if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
+ sc->fv_link_status = 1;
+ } else
+ sc->fv_link_status = 0;
+
+ FV_UNLOCK(sc);
+#endif
+}
+
+static void
+fv_reset(struct fv_softc *sc)
+{
+ int i;
+
+ CSR_WRITE_4(sc, CSR_BUSMODE, BUSMODE_SWR);
+
+ /*
+ * The chip doesn't take itself out of reset automatically.
+ * We need to do so after 2us.
+ */
+ DELAY(1000);
+ CSR_WRITE_4(sc, CSR_BUSMODE, 0);
+
+ for (i = 0; i < 1000; i++) {
+ /*
+ * Wait a bit for the reset to complete before peeking
+ * at the chip again.
+ */
+ DELAY(1000);
+ if ((CSR_READ_4(sc, CSR_BUSMODE) & BUSMODE_SWR) == 0)
+ break;
+ }
+
+ if (CSR_READ_4(sc, CSR_BUSMODE) & BUSMODE_SWR)
+ device_printf(sc->fv_dev, "reset time out\n");
+
+ DELAY(1000);
+}
+
+static void
+fv_init(void *xsc)
+{
+ struct fv_softc *sc = xsc;
+
+ FV_LOCK(sc);
+ fv_init_locked(sc);
+ FV_UNLOCK(sc);
+}
+
+static void
+fv_init_locked(struct fv_softc *sc)
+{
+ struct ifnet *ifp = sc->fv_ifp;
+#ifdef MII
+ struct mii_data *mii;
+#endif
+
+ FV_LOCK_ASSERT(sc);
+
+#ifdef MII
+ mii = device_get_softc(sc->fv_miibus);
+#endif
+
+ fv_stop(sc);
+ fv_reset(sc);
+
+ /* Init circular RX list. */
+ if (fv_rx_ring_init(sc) != 0) {
+ device_printf(sc->fv_dev,
+ "initialization failed: no memory for rx buffers\n");
+ fv_stop(sc);
+ return;
+ }
+
+ /* Init tx descriptors. */
+ fv_tx_ring_init(sc);
+
+ /*
+ * Initialize the BUSMODE register.
+ */
+ CSR_WRITE_4(sc, CSR_BUSMODE,
+ /* XXX: not sure if this is a good thing or not... */
+ BUSMODE_BAR | BUSMODE_PBL_32LW);
+
+ /*
+ * Initialize the interrupt mask and enable interrupts.
+ */
+ /* normal interrupts */
+ sc->sc_inten = STATUS_TI | STATUS_TU | STATUS_RI | STATUS_NIS;
+
+ /* abnormal interrupts */
+ sc->sc_inten |= STATUS_TPS | STATUS_TJT | STATUS_UNF |
+ STATUS_RU | STATUS_RPS | STATUS_SE | STATUS_AIS;
+
+ sc->sc_rxint_mask = STATUS_RI|STATUS_RU;
+ sc->sc_txint_mask = STATUS_TI|STATUS_UNF|STATUS_TJT;
+
+ sc->sc_rxint_mask &= sc->sc_inten;
+ sc->sc_txint_mask &= sc->sc_inten;
+
+ CSR_WRITE_4(sc, CSR_INTEN, sc->sc_inten);
+ CSR_WRITE_4(sc, CSR_STATUS, 0xffffffff);
+
+ /*
+ * Give the transmit and receive rings to the chip.
+ */
+ CSR_WRITE_4(sc, CSR_TXLIST, FV_TX_RING_ADDR(sc, 0));
+ CSR_WRITE_4(sc, CSR_RXLIST, FV_RX_RING_ADDR(sc, 0));
+
+ /*
+ * Set the station address.
+ */
+ fv_setfilt(sc);
+
+
+ /*
+ * Write out the opmode.
+ */
+ CSR_WRITE_4(sc, CSR_OPMODE, OPMODE_SR | OPMODE_ST |
+ OPMODE_TR_128 | OPMODE_FDX | OPMODE_SPEED);
+ /*
+ * Start the receive process.
+ */
+ CSR_WRITE_4(sc, CSR_RXPOLL, RXPOLL_RPD);
+
+ sc->fv_link_status = 1;
+#ifdef MII
+ mii_mediachg(mii);
+#endif
+
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ callout_reset(&sc->fv_stat_callout, hz, fv_tick, sc);
+}
+
+static void
+fv_start(struct ifnet *ifp)
+{
+ struct fv_softc *sc;
+
+ sc = ifp->if_softc;
+
+ FV_LOCK(sc);
+ fv_start_locked(ifp);
+ FV_UNLOCK(sc);
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ * Use Implicit Chain implementation.
+ */
+static int
+fv_encap(struct fv_softc *sc, struct mbuf **m_head)
+{
+ struct fv_txdesc *txd;
+ struct fv_desc *desc;
+ struct mbuf *m;
+ bus_dma_segment_t txsegs[FV_MAXFRAGS];
+ int error, i, nsegs, prod, si;
+ int padlen;
+ int txstat;
+
+ FV_LOCK_ASSERT(sc);
+
+ /*
+ * Some VIA Rhine wants packet buffers to be longword
+ * aligned, but very often our mbufs aren't. Rather than
+ * waste time trying to decide when to copy and when not
+ * to copy, just do it all the time.
+ */
+ m = m_defrag(*m_head, M_NOWAIT);
+ if (m == NULL) {
+ device_printf(sc->fv_dev, "fv_encap m_defrag error\n");
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (ENOBUFS);
+ }
+ *m_head = m;
+
+ /*
+ * The Rhine chip doesn't auto-pad, so we have to make
+ * sure to pad short frames out to the minimum frame length
+ * ourselves.
+ */
+ if ((*m_head)->m_pkthdr.len < FV_MIN_FRAMELEN) {
+ m = *m_head;
+ padlen = FV_MIN_FRAMELEN - m->m_pkthdr.len;
+ if (M_WRITABLE(m) == 0) {
+ /* Get a writable copy. */
+ m = m_dup(*m_head, M_NOWAIT);
+ m_freem(*m_head);
+ if (m == NULL) {
+ device_printf(sc->fv_dev, "fv_encap m_dup error\n");
+ *m_head = NULL;
+ return (ENOBUFS);
+ }
+ *m_head = m;
+ }
+ if (m->m_next != NULL || M_TRAILINGSPACE(m) < padlen) {
+ m = m_defrag(m, M_NOWAIT);
+ if (m == NULL) {
+ device_printf(sc->fv_dev, "fv_encap m_defrag error\n");
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (ENOBUFS);
+ }
+ }
+ /*
+ * Manually pad short frames, and zero the pad space
+ * to avoid leaking data.
+ */
+ bzero(mtod(m, char *) + m->m_pkthdr.len, padlen);
+ m->m_pkthdr.len += padlen;
+ m->m_len = m->m_pkthdr.len;
+ *m_head = m;
+ }
+
+ prod = sc->fv_cdata.fv_tx_prod;
+ txd = &sc->fv_cdata.fv_txdesc[prod];
+ error = bus_dmamap_load_mbuf_sg(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap,
+ *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
+ if (error == EFBIG) {
+ device_printf(sc->fv_dev, "fv_encap EFBIG error\n");
+ m = m_defrag(*m_head, M_NOWAIT);
+ if (m == NULL) {
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (ENOBUFS);
+ }
+ *m_head = m;
+ error = bus_dmamap_load_mbuf_sg(sc->fv_cdata.fv_tx_tag,
+ txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (error);
+ }
+
+ } else if (error != 0)
+ return (error);
+ if (nsegs == 0) {
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (EIO);
+ }
+
+ /* Check number of available descriptors. */
+ if (sc->fv_cdata.fv_tx_cnt + nsegs >= (FV_TX_RING_CNT - 1)) {
+ bus_dmamap_unload(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap);
+ return (ENOBUFS);
+ }
+
+ txd->tx_m = *m_head;
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_PREWRITE);
+
+ si = prod;
+
+ /*
+ * Make a list of descriptors for this packet.
+ */
+ desc = NULL;
+ for (i = 0; i < nsegs; i++) {
+ desc = &sc->fv_rdata.fv_tx_ring[prod];
+ desc->fv_stat = ADSTAT_OWN;
+ desc->fv_devcs = txsegs[i].ds_len;
+ /* end of descriptor */
+ if (prod == FV_TX_RING_CNT - 1)
+ desc->fv_devcs |= ADCTL_ER;
+ desc->fv_addr = txsegs[i].ds_addr;
+
+ ++sc->fv_cdata.fv_tx_cnt;
+ FV_INC(prod, FV_TX_RING_CNT);
+ }
+
+ /*
+ * Set mark last fragment with Last/Intr flag
+ */
+ if (desc) {
+ desc->fv_devcs |= ADCTL_Tx_IC;
+ desc->fv_devcs |= ADCTL_Tx_LS;
+ }
+
+ /* Update producer index. */
+ sc->fv_cdata.fv_tx_prod = prod;
+
+ /* Sync descriptors. */
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7;
+ if (txstat == 0 || txstat == 6) {
+ /* Transmit Process Stat is stop or suspended */
+ desc = &sc->fv_rdata.fv_tx_ring[si];
+ desc->fv_devcs |= ADCTL_Tx_FS;
+ }
+ else {
+ /* Get previous descriptor */
+ si = (si + FV_TX_RING_CNT - 1) % FV_TX_RING_CNT;
+ desc = &sc->fv_rdata.fv_tx_ring[si];
+ /* join remain data and flugs */
+ desc->fv_devcs &= ~ADCTL_Tx_IC;
+ desc->fv_devcs &= ~ADCTL_Tx_LS;
+ }
+
+
+ return (0);
+}
+
+static void
+fv_start_locked(struct ifnet *ifp)
+{
+ struct fv_softc *sc;
+ struct mbuf *m_head;
+ int enq;
+ int txstat;
+
+ sc = ifp->if_softc;
+
+ FV_LOCK_ASSERT(sc);
+
+ if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING || sc->fv_link_status == 0 )
+ return;
+
+ for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
+ sc->fv_cdata.fv_tx_cnt < FV_TX_RING_CNT - 2; ) {
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+ /*
+ * Pack the data into the transmit ring. If we
+ * don't have room, set the OACTIVE flag and wait
+ * for the NIC to drain the ring.
+ */
+ if (fv_encap(sc, &m_head)) {
+ if (m_head == NULL)
+ break;
+ IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ break;
+ }
+
+ enq++;
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ ETHER_BPF_MTAP(ifp, m_head);
+ }
+
+ if (enq > 0) {
+ txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7;
+ if (txstat == 0 || txstat == 6)
+ CSR_WRITE_4(sc, CSR_TXPOLL, TXPOLL_TPD);
+ }
+}
+
+static void
+fv_stop(struct fv_softc *sc)
+{
+ struct ifnet *ifp;
+
+ FV_LOCK_ASSERT(sc);
+
+ ifp = sc->fv_ifp;
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ callout_stop(&sc->fv_stat_callout);
+
+ /* Disable interrupts. */
+ CSR_WRITE_4(sc, CSR_INTEN, 0);
+
+ /* Stop the transmit and receive processes. */
+ CSR_WRITE_4(sc, CSR_OPMODE, 0);
+ CSR_WRITE_4(sc, CSR_RXLIST, 0);
+ CSR_WRITE_4(sc, CSR_TXLIST, 0);
+
+}
+
+
+static int
+fv_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct fv_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+#ifdef MII
+ struct mii_data *mii;
+#endif
+ int error;
+ int csr;
+
+ switch (command) {
+ case SIOCSIFFLAGS:
+ FV_LOCK(sc);
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ if ((ifp->if_flags ^ sc->fv_if_flags) &
+ IFF_PROMISC) {
+ csr = CSR_READ_4(sc, CSR_OPMODE);
+ CSR_WRITE_4(sc, CSR_OPMODE, csr |
+ OPMODE_PM | OPMODE_PR);
+ }
+ if ((ifp->if_flags ^ sc->fv_if_flags) &
+ IFF_ALLMULTI) {
+ csr = CSR_READ_4(sc, CSR_OPMODE);
+ CSR_WRITE_4(sc, CSR_OPMODE, csr |
+ OPMODE_PM);
+ }
+ } else {
+ if (sc->fv_detach == 0)
+ fv_init_locked(sc);
+ }
+ } else {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ fv_stop(sc);
+ }
+ sc->fv_if_flags = ifp->if_flags;
+ FV_UNLOCK(sc);
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+#if 0
+ FV_LOCK(sc);
+ fv_set_filter(sc);
+ FV_UNLOCK(sc);
+#endif
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+#ifdef MII
+ mii = device_get_softc(sc->fv_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+#else
+ error = ifmedia_ioctl(ifp, ifr, &sc->fv_ifmedia, command);
+#endif
+ break;
+ case SIOCSIFCAP:
+ error = 0;
+#if 0
+ mask = ifr->ifr_reqcap ^ ifp->if_capenable;
+ if ((mask & IFCAP_HWCSUM) != 0) {
+ ifp->if_capenable ^= IFCAP_HWCSUM;
+ if ((IFCAP_HWCSUM & ifp->if_capenable) &&
+ (IFCAP_HWCSUM & ifp->if_capabilities))
+ ifp->if_hwassist = FV_CSUM_FEATURES;
+ else
+ ifp->if_hwassist = 0;
+ }
+ if ((mask & IFCAP_VLAN_HWTAGGING) != 0) {
+ ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+ if (IFCAP_VLAN_HWTAGGING & ifp->if_capenable &&
+ IFCAP_VLAN_HWTAGGING & ifp->if_capabilities &&
+ ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ FV_LOCK(sc);
+ fv_vlan_setup(sc);
+ FV_UNLOCK(sc);
+ }
+ }
+ VLAN_CAPABILITIES(ifp);
+#endif
+ break;
+ default:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ }
+
+ return (error);
+}
+
+/*
+ * Set media options.
+ */
+static int
+fv_ifmedia_upd(struct ifnet *ifp)
+{
+#ifdef MII
+ struct fv_softc *sc;
+ struct mii_data *mii;
+ struct mii_softc *miisc;
+ int error;
+
+ sc = ifp->if_softc;
+ FV_LOCK(sc);
+ mii = device_get_softc(sc->fv_miibus);
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ PHY_RESET(miisc);
+ error = mii_mediachg(mii);
+ FV_UNLOCK(sc);
+
+ return (error);
+#else
+ return (0);
+#endif
+}
+
+/*
+ * Report current media status.
+ */
+static void
+fv_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+#ifdef MII
+ struct fv_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+
+ mii = device_get_softc(sc->fv_miibus);
+ FV_LOCK(sc);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+ FV_UNLOCK(sc);
+#else
+ ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
+#endif
+}
+
+struct fv_dmamap_arg {
+ bus_addr_t fv_busaddr;
+};
+
+static void
+fv_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct fv_dmamap_arg *ctx;
+
+ if (error != 0)
+ return;
+ ctx = arg;
+ ctx->fv_busaddr = segs[0].ds_addr;
+}
+
+static int
+fv_dma_alloc(struct fv_softc *sc)
+{
+ struct fv_dmamap_arg ctx;
+ struct fv_txdesc *txd;
+ struct fv_rxdesc *rxd;
+ int error, i;
+
+ /* Create parent DMA tag. */
+ error = bus_dma_tag_create(
+ bus_get_dma_tag(sc->fv_dev), /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ BUS_SPACE_MAXSIZE_32BIT, /* maxsize */
+ 0, /* nsegments */
+ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fv_cdata.fv_parent_tag);
+ if (error != 0) {
+ device_printf(sc->fv_dev, "failed to create parent DMA tag\n");
+ goto fail;
+ }
+ /* Create tag for Tx ring. */
+ error = bus_dma_tag_create(
+ sc->fv_cdata.fv_parent_tag, /* parent */
+ FV_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ FV_TX_RING_SIZE, /* maxsize */
+ 1, /* nsegments */
+ FV_TX_RING_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fv_cdata.fv_tx_ring_tag);
+ if (error != 0) {
+ device_printf(sc->fv_dev, "failed to create Tx ring DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Rx ring. */
+ error = bus_dma_tag_create(
+ sc->fv_cdata.fv_parent_tag, /* parent */
+ FV_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ FV_RX_RING_SIZE, /* maxsize */
+ 1, /* nsegments */
+ FV_RX_RING_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fv_cdata.fv_rx_ring_tag);
+ if (error != 0) {
+ device_printf(sc->fv_dev, "failed to create Rx ring DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Tx buffers. */
+ error = bus_dma_tag_create(
+ sc->fv_cdata.fv_parent_tag, /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MCLBYTES * FV_MAXFRAGS, /* maxsize */
+ FV_MAXFRAGS, /* nsegments */
+ MCLBYTES, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fv_cdata.fv_tx_tag);
+ if (error != 0) {
+ device_printf(sc->fv_dev, "failed to create Tx DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Rx buffers. */
+ error = bus_dma_tag_create(
+ sc->fv_cdata.fv_parent_tag, /* parent */
+ FV_RX_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MCLBYTES, /* maxsize */
+ 1, /* nsegments */
+ MCLBYTES, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fv_cdata.fv_rx_tag);
+ if (error != 0) {
+ device_printf(sc->fv_dev, "failed to create Rx DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for setup frame buffers. */
+ error = bus_dma_tag_create(
+ sc->fv_cdata.fv_parent_tag, /* parent */
+ sizeof(uint32_t), 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ FV_SFRAME_LEN + FV_MIN_FRAMELEN, /* maxsize */
+ 1, /* nsegments */
+ FV_SFRAME_LEN + FV_MIN_FRAMELEN, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fv_cdata.fv_sf_tag);
+ if (error != 0) {
+ device_printf(sc->fv_dev, "failed to create setup frame DMA tag\n");
+ goto fail;
+ }
+
+ /* Allocate DMA'able memory and load the DMA map for Tx ring. */
+ error = bus_dmamem_alloc(sc->fv_cdata.fv_tx_ring_tag,
+ (void **)&sc->fv_rdata.fv_tx_ring, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->fv_cdata.fv_tx_ring_map);
+ if (error != 0) {
+ device_printf(sc->fv_dev,
+ "failed to allocate DMA'able memory for Tx ring\n");
+ goto fail;
+ }
+
+ ctx.fv_busaddr = 0;
+ error = bus_dmamap_load(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map, sc->fv_rdata.fv_tx_ring,
+ FV_TX_RING_SIZE, fv_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.fv_busaddr == 0) {
+ device_printf(sc->fv_dev,
+ "failed to load DMA'able memory for Tx ring\n");
+ goto fail;
+ }
+ sc->fv_rdata.fv_tx_ring_paddr = ctx.fv_busaddr;
+
+ /* Allocate DMA'able memory and load the DMA map for Rx ring. */
+ error = bus_dmamem_alloc(sc->fv_cdata.fv_rx_ring_tag,
+ (void **)&sc->fv_rdata.fv_rx_ring, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->fv_cdata.fv_rx_ring_map);
+ if (error != 0) {
+ device_printf(sc->fv_dev,
+ "failed to allocate DMA'able memory for Rx ring\n");
+ goto fail;
+ }
+
+ ctx.fv_busaddr = 0;
+ error = bus_dmamap_load(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_cdata.fv_rx_ring_map, sc->fv_rdata.fv_rx_ring,
+ FV_RX_RING_SIZE, fv_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.fv_busaddr == 0) {
+ device_printf(sc->fv_dev,
+ "failed to load DMA'able memory for Rx ring\n");
+ goto fail;
+ }
+ sc->fv_rdata.fv_rx_ring_paddr = ctx.fv_busaddr;
+
+ /* Allocate DMA'able memory and load the DMA map for setup frame. */
+ error = bus_dmamem_alloc(sc->fv_cdata.fv_sf_tag,
+ (void **)&sc->fv_cdata.fv_sf_buff, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->fv_cdata.fv_sf_buff_map);
+ if (error != 0) {
+ device_printf(sc->fv_dev,
+ "failed to allocate DMA'able memory for setup frame\n");
+ goto fail;
+ }
+
+ ctx.fv_busaddr = 0;
+ error = bus_dmamap_load(sc->fv_cdata.fv_sf_tag,
+ sc->fv_cdata.fv_sf_buff_map, sc->fv_cdata.fv_sf_buff,
+ FV_SFRAME_LEN, fv_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.fv_busaddr == 0) {
+ device_printf(sc->fv_dev,
+ "failed to load DMA'able memory for setup frame\n");
+ goto fail;
+ }
+ sc->fv_rdata.fv_sf_paddr = ctx.fv_busaddr;
+
+ /* Create DMA maps for Tx buffers. */
+ for (i = 0; i < FV_TX_RING_CNT; i++) {
+ txd = &sc->fv_cdata.fv_txdesc[i];
+ txd->tx_m = NULL;
+ txd->tx_dmamap = NULL;
+ error = bus_dmamap_create(sc->fv_cdata.fv_tx_tag, 0,
+ &txd->tx_dmamap);
+ if (error != 0) {
+ device_printf(sc->fv_dev,
+ "failed to create Tx dmamap\n");
+ goto fail;
+ }
+ }
+ /* Create DMA maps for Rx buffers. */
+ if ((error = bus_dmamap_create(sc->fv_cdata.fv_rx_tag, 0,
+ &sc->fv_cdata.fv_rx_sparemap)) != 0) {
+ device_printf(sc->fv_dev,
+ "failed to create spare Rx dmamap\n");
+ goto fail;
+ }
+ for (i = 0; i < FV_RX_RING_CNT; i++) {
+ rxd = &sc->fv_cdata.fv_rxdesc[i];
+ rxd->rx_m = NULL;
+ rxd->rx_dmamap = NULL;
+ error = bus_dmamap_create(sc->fv_cdata.fv_rx_tag, 0,
+ &rxd->rx_dmamap);
+ if (error != 0) {
+ device_printf(sc->fv_dev,
+ "failed to create Rx dmamap\n");
+ goto fail;
+ }
+ }
+
+fail:
+ return (error);
+}
+
+static void
+fv_dma_free(struct fv_softc *sc)
+{
+ struct fv_txdesc *txd;
+ struct fv_rxdesc *rxd;
+ int i;
+
+ /* Tx ring. */
+ if (sc->fv_cdata.fv_tx_ring_tag) {
+ if (sc->fv_rdata.fv_tx_ring_paddr)
+ bus_dmamap_unload(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map);
+ if (sc->fv_rdata.fv_tx_ring)
+ bus_dmamem_free(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_rdata.fv_tx_ring,
+ sc->fv_cdata.fv_tx_ring_map);
+ sc->fv_rdata.fv_tx_ring = NULL;
+ sc->fv_rdata.fv_tx_ring_paddr = 0;
+ bus_dma_tag_destroy(sc->fv_cdata.fv_tx_ring_tag);
+ sc->fv_cdata.fv_tx_ring_tag = NULL;
+ }
+ /* Rx ring. */
+ if (sc->fv_cdata.fv_rx_ring_tag) {
+ if (sc->fv_rdata.fv_rx_ring_paddr)
+ bus_dmamap_unload(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_cdata.fv_rx_ring_map);
+ if (sc->fv_rdata.fv_rx_ring)
+ bus_dmamem_free(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_rdata.fv_rx_ring,
+ sc->fv_cdata.fv_rx_ring_map);
+ sc->fv_rdata.fv_rx_ring = NULL;
+ sc->fv_rdata.fv_rx_ring_paddr = 0;
+ bus_dma_tag_destroy(sc->fv_cdata.fv_rx_ring_tag);
+ sc->fv_cdata.fv_rx_ring_tag = NULL;
+ }
+ /* Tx buffers. */
+ if (sc->fv_cdata.fv_tx_tag) {
+ for (i = 0; i < FV_TX_RING_CNT; i++) {
+ txd = &sc->fv_cdata.fv_txdesc[i];
+ if (txd->tx_dmamap) {
+ bus_dmamap_destroy(sc->fv_cdata.fv_tx_tag,
+ txd->tx_dmamap);
+ txd->tx_dmamap = NULL;
+ }
+ }
+ bus_dma_tag_destroy(sc->fv_cdata.fv_tx_tag);
+ sc->fv_cdata.fv_tx_tag = NULL;
+ }
+ /* Rx buffers. */
+ if (sc->fv_cdata.fv_rx_tag) {
+ for (i = 0; i < FV_RX_RING_CNT; i++) {
+ rxd = &sc->fv_cdata.fv_rxdesc[i];
+ if (rxd->rx_dmamap) {
+ bus_dmamap_destroy(sc->fv_cdata.fv_rx_tag,
+ rxd->rx_dmamap);
+ rxd->rx_dmamap = NULL;
+ }
+ }
+ if (sc->fv_cdata.fv_rx_sparemap) {
+ bus_dmamap_destroy(sc->fv_cdata.fv_rx_tag,
+ sc->fv_cdata.fv_rx_sparemap);
+ sc->fv_cdata.fv_rx_sparemap = 0;
+ }
+ bus_dma_tag_destroy(sc->fv_cdata.fv_rx_tag);
+ sc->fv_cdata.fv_rx_tag = NULL;
+ }
+
+ if (sc->fv_cdata.fv_parent_tag) {
+ bus_dma_tag_destroy(sc->fv_cdata.fv_parent_tag);
+ sc->fv_cdata.fv_parent_tag = NULL;
+ }
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int
+fv_tx_ring_init(struct fv_softc *sc)
+{
+ struct fv_ring_data *rd;
+ struct fv_txdesc *txd;
+ bus_addr_t addr;
+ int i;
+
+ sc->fv_cdata.fv_tx_prod = 0;
+ sc->fv_cdata.fv_tx_cons = 0;
+ sc->fv_cdata.fv_tx_cnt = 0;
+ sc->fv_cdata.fv_tx_pkts = 0;
+
+ rd = &sc->fv_rdata;
+ bzero(rd->fv_tx_ring, FV_TX_RING_SIZE);
+ for (i = 0; i < FV_TX_RING_CNT; i++) {
+ if (i == FV_TX_RING_CNT - 1)
+ addr = FV_TX_RING_ADDR(sc, 0);
+ else
+ addr = FV_TX_RING_ADDR(sc, i + 1);
+ rd->fv_tx_ring[i].fv_stat = 0;
+ rd->fv_tx_ring[i].fv_devcs = 0;
+ rd->fv_tx_ring[i].fv_addr = 0;
+ rd->fv_tx_ring[i].fv_link = addr;
+ txd = &sc->fv_cdata.fv_txdesc[i];
+ txd->tx_m = NULL;
+ }
+
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them. Note that
+ * we arrange the descriptors in a closed ring, so that the last descriptor
+ * points back to the first.
+ */
+static int
+fv_rx_ring_init(struct fv_softc *sc)
+{
+ struct fv_ring_data *rd;
+ struct fv_rxdesc *rxd;
+ int i;
+
+ sc->fv_cdata.fv_rx_cons = 0;
+
+ rd = &sc->fv_rdata;
+ bzero(rd->fv_rx_ring, FV_RX_RING_SIZE);
+ for (i = 0; i < FV_RX_RING_CNT; i++) {
+ rxd = &sc->fv_cdata.fv_rxdesc[i];
+ rxd->rx_m = NULL;
+ rxd->desc = &rd->fv_rx_ring[i];
+ rd->fv_rx_ring[i].fv_stat = ADSTAT_OWN;
+ rd->fv_rx_ring[i].fv_devcs = 0;
+ if (i == FV_RX_RING_CNT - 1)
+ rd->fv_rx_ring[i].fv_devcs |= ADCTL_ER;
+ rd->fv_rx_ring[i].fv_addr = 0;
+ if (fv_newbuf(sc, i) != 0)
+ return (ENOBUFS);
+ }
+
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_cdata.fv_rx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int
+fv_newbuf(struct fv_softc *sc, int idx)
+{
+ struct fv_desc *desc;
+ struct fv_rxdesc *rxd;
+ struct mbuf *m;
+ bus_dma_segment_t segs[1];
+ bus_dmamap_t map;
+ int nsegs;
+
+ m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL)
+ return (ENOBUFS);
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+
+ /* tcp header boundary alignment margin */
+ m_adj(m, 4);
+
+ if (bus_dmamap_load_mbuf_sg(sc->fv_cdata.fv_rx_tag,
+ sc->fv_cdata.fv_rx_sparemap, m, segs, &nsegs, 0) != 0) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
+
+ rxd = &sc->fv_cdata.fv_rxdesc[idx];
+ if (rxd->rx_m != NULL) {
+/* This code make bug. Make scranble on buffer data.
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_POSTREAD);
+*/
+ bus_dmamap_unload(sc->fv_cdata.fv_rx_tag, rxd->rx_dmamap);
+ }
+ map = rxd->rx_dmamap;
+ rxd->rx_dmamap = sc->fv_cdata.fv_rx_sparemap;
+ sc->fv_cdata.fv_rx_sparemap = map;
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_PREREAD);
+ rxd->rx_m = m;
+ desc = rxd->desc;
+ desc->fv_addr = segs[0].ds_addr;
+ desc->fv_devcs |= FV_DMASIZE(segs[0].ds_len);
+ rxd->saved_ca = desc->fv_addr ;
+ rxd->saved_ctl = desc->fv_stat ;
+
+ return (0);
+}
+
+static __inline void
+fv_fixup_rx(struct mbuf *m)
+{
+ int i;
+ uint16_t *src, *dst;
+
+ src = mtod(m, uint16_t *);
+ dst = src - 1;
+
+ for (i = 0; i < m->m_len / sizeof(uint16_t); i++) {
+ *dst++ = *src++;
+ }
+
+ if (m->m_len % sizeof(uint16_t))
+ *(uint8_t *)dst = *(uint8_t *)src;
+
+ m->m_data -= ETHER_ALIGN;
+}
+
+
+static void
+fv_tx(struct fv_softc *sc)
+{
+ struct fv_txdesc *txd;
+ struct fv_desc *cur_tx;
+ struct ifnet *ifp;
+ uint32_t ctl, devcs;
+ int cons, prod, prev_cons;
+
+ FV_LOCK_ASSERT(sc);
+
+ cons = sc->fv_cdata.fv_tx_cons;
+ prod = sc->fv_cdata.fv_tx_prod;
+ if (cons == prod)
+ return;
+
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ ifp = sc->fv_ifp;
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ prev_cons = cons;
+ for (; cons != prod; FV_INC(cons, FV_TX_RING_CNT)) {
+ cur_tx = &sc->fv_rdata.fv_tx_ring[cons];
+ ctl = cur_tx->fv_stat;
+ devcs = cur_tx->fv_devcs;
+ /* Check if descriptor has "finished" flag */
+ if (FV_DMASIZE(devcs) == 0)
+ break;
+
+ sc->fv_cdata.fv_tx_cnt--;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ txd = &sc->fv_cdata.fv_txdesc[cons];
+
+ if ((ctl & ADSTAT_Tx_ES) == 0)
+ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
+ else if (ctl & ADSTAT_Tx_UF) { /* only underflow not check collision */
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ }
+
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap);
+
+ /* Free only if it's first descriptor in list */
+ if (txd->tx_m)
+ m_freem(txd->tx_m);
+ txd->tx_m = NULL;
+
+ /* reset descriptor */
+ cur_tx->fv_stat = 0;
+ cur_tx->fv_devcs = 0;
+ cur_tx->fv_addr = 0;
+ }
+
+ sc->fv_cdata.fv_tx_cons = cons;
+
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map, BUS_DMASYNC_PREWRITE);
+}
+
+
+static void
+fv_rx(struct fv_softc *sc)
+{
+ struct fv_rxdesc *rxd;
+ struct ifnet *ifp = sc->fv_ifp;
+ int cons, prog, packet_len, error;
+ struct fv_desc *cur_rx;
+ struct mbuf *m;
+
+ FV_LOCK_ASSERT(sc);
+
+ cons = sc->fv_cdata.fv_rx_cons;
+
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_cdata.fv_rx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ for (prog = 0; prog < FV_RX_RING_CNT; FV_INC(cons, FV_RX_RING_CNT)) {
+ cur_rx = &sc->fv_rdata.fv_rx_ring[cons];
+ rxd = &sc->fv_cdata.fv_rxdesc[cons];
+ m = rxd->rx_m;
+
+ if ((cur_rx->fv_stat & ADSTAT_OWN) == ADSTAT_OWN)
+ break;
+
+ prog++;
+
+ if (cur_rx->fv_stat & (ADSTAT_ES | ADSTAT_Rx_TL)) {
+ device_printf(sc->fv_dev,
+ "Receive Descriptor error %x\n", cur_rx->fv_stat);
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+ packet_len = 0;
+ } else {
+ packet_len = ADSTAT_Rx_LENGTH(cur_rx->fv_stat);
+ }
+
+ /* Assume it's error */
+ error = 1;
+
+ if (packet_len < 64)
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+ else if ((cur_rx->fv_stat & ADSTAT_Rx_DE) == 0) {
+ error = 0;
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ m = rxd->rx_m;
+ /* Skip 4 bytes of CRC */
+ m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN;
+
+ fv_fixup_rx(m);
+ m->m_pkthdr.rcvif = ifp;
+ if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
+
+ FV_UNLOCK(sc);
+ (*ifp->if_input)(ifp, m);
+ FV_LOCK(sc);
+ }
+
+ if (error) {
+ /* Restore CONTROL and CA values, reset DEVCS */
+ cur_rx->fv_stat = rxd->saved_ctl;
+ cur_rx->fv_addr = rxd->saved_ca;
+ cur_rx->fv_devcs = 0;
+ }
+ else {
+ /* Reinit descriptor */
+ cur_rx->fv_stat = ADSTAT_OWN;
+ cur_rx->fv_devcs = 0;
+ if (cons == FV_RX_RING_CNT - 1)
+ cur_rx->fv_devcs |= ADCTL_ER;
+ cur_rx->fv_addr = 0;
+ if (fv_newbuf(sc, cons) != 0) {
+ device_printf(sc->fv_dev,
+ "Failed to allocate buffer\n");
+ break;
+ }
+ }
+
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_cdata.fv_rx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ }
+
+ if (prog > 0) {
+ sc->fv_cdata.fv_rx_cons = cons;
+
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_cdata.fv_rx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ }
+}
+
+static void
+fv_intr(void *arg)
+{
+ struct fv_softc *sc = arg;
+ uint32_t status;
+ struct ifnet *ifp = sc->fv_ifp;
+
+ FV_LOCK(sc);
+
+ status = CSR_READ_4(sc, CSR_STATUS);
+ /* mask out interrupts */
+ while((status & sc->sc_inten) != 0) {
+ if (status) {
+ CSR_WRITE_4(sc, CSR_STATUS, status);
+ }
+ if (status & STATUS_UNF) {
+ device_printf(sc->fv_dev, "Transmit Underflow\n");
+ }
+ if (status & sc->sc_rxint_mask) {
+ fv_rx(sc);
+ }
+ if (status & sc->sc_txint_mask) {
+ fv_tx(sc);
+ }
+ if (status & STATUS_AIS) {
+ device_printf(sc->fv_dev, "Abnormal Interrupt %x\n",
+ status);
+ }
+ CSR_WRITE_4(sc, CSR_FULLDUP, FULLDUP_CS |
+ (1 << FULLDUP_TT_SHIFT) | (3 << FULLDUP_NTP_SHIFT) |
+ (2 << FULLDUP_RT_SHIFT) | (2 << FULLDUP_NRP_SHIFT));
+
+
+ status = CSR_READ_4(sc, CSR_STATUS);
+ }
+
+ /* Try to get more packets going. */
+ if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ fv_start_locked(ifp);
+
+ FV_UNLOCK(sc);
+}
+
+static void
+fv_tick(void *xsc)
+{
+ struct fv_softc *sc = xsc;
+#ifdef MII
+ struct mii_data *mii;
+
+ FV_LOCK_ASSERT(sc);
+
+ mii = device_get_softc(sc->fv_miibus);
+ mii_tick(mii);
+#endif
+ callout_reset(&sc->fv_stat_callout, hz, fv_tick, sc);
+}
+
+static void
+fv_hinted_child(device_t bus, const char *dname, int dunit)
+{
+ BUS_ADD_CHILD(bus, 0, dname, dunit);
+ device_printf(bus, "hinted child %s%d\n", dname, dunit);
+}
+
+#ifdef FV_MDIO
+static int
+fvmdio_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "fv,mdio"))
+ return (ENXIO);
+
+ device_set_desc(dev, "FV built-in ethernet interface, MDIO controller");
+ return(0);
+}
+
+static int
+fvmdio_attach(device_t dev)
+{
+ struct fv_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+ sc->fv_dev = dev;
+ sc->fv_rid = 0;
+ sc->fv_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->fv_rid, RF_ACTIVE | RF_SHAREABLE);
+ if (sc->fv_res == NULL) {
+ device_printf(dev, "couldn't map memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->fv_btag = rman_get_bustag(sc->fv_res);
+ sc->fv_bhandle = rman_get_bushandle(sc->fv_res);
+
+ bus_generic_probe(dev);
+ bus_enumerate_hinted_children(dev);
+ error = bus_generic_attach(dev);
+fail:
+ return(error);
+}
+
+static int
+fvmdio_detach(device_t dev)
+{
+ return(0);
+}
+#endif
+
+#ifdef FV_DEBUG
+void
+dump_txdesc(struct fv_softc *sc, int pos)
+{
+ struct fv_desc *desc;
+
+ desc = &sc->fv_rdata.fv_tx_ring[pos];
+ device_printf(sc->fv_dev, "CSR_TXLIST %08x\n", CSR_READ_4(sc, CSR_TXLIST));
+ device_printf(sc->fv_dev, "%d TDES0:%08x TDES1:%08x TDES2:%08x TDES3:%08x\n",
+ pos, desc->fv_stat, desc->fv_devcs, desc->fv_addr, desc->fv_link);
+}
+
+void
+dump_status_reg(struct fv_softc *sc)
+{
+ uint32_t status;
+
+ /* mask out interrupts */
+
+ status = CSR_READ_4(sc, CSR_STATUS);
+ device_printf(sc->fv_dev, "CSR5 Status Register EB:%d TS:%d RS:%d NIS:%d AIS:%d ER:%d SE:%d LNF:%d TM:%d RWT:%d RPS:%d RU:%d RI:%d UNF:%d LNP/ANC:%d TJT:%d TU:%d TPS:%d TI:%d\n",
+ (status >> 23 ) & 7,
+ (status >> 20 ) & 7,
+ (status >> 17 ) & 7,
+ (status >> 16 ) & 1,
+ (status >> 15 ) & 1,
+ (status >> 14 ) & 1,
+ (status >> 13 ) & 1,
+ (status >> 12 ) & 1,
+ (status >> 11 ) & 1,
+ (status >> 9 ) & 1,
+ (status >> 8 ) & 1,
+ (status >> 7 ) & 1,
+ (status >> 6 ) & 1,
+ (status >> 5 ) & 1,
+ (status >> 4 ) & 1,
+ (status >> 3 ) & 1,
+ (status >> 2 ) & 1,
+ (status >> 1 ) & 1,
+ (status >> 0 ) & 1);
+
+}
+#endif
Index: head/sys/arm/ralink/if_fvreg.h
===================================================================
--- head/sys/arm/ralink/if_fvreg.h
+++ head/sys/arm/ralink/if_fvreg.h
@@ -0,0 +1,452 @@
+/*-
+ * Copyright (C) 2007
+ * Oleksandr Tymoshenko <gonzo@freebsd.org>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWFV IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE FV DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWFV, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef __IF_FVREG_H__
+#define __IF_FVREG_H__
+
+struct fv_desc {
+ uint32_t fv_stat;
+ uint32_t fv_devcs;
+ uint32_t fv_addr;
+ uint32_t fv_link;
+};
+
+#define FV_DMASIZE(len) ((len) & ((1 << 11)-1))
+#define FV_PKTSIZE(len) ((len & 0xffff0000) >> 16)
+
+#define FV_RX_RING_CNT 128
+#define FV_TX_RING_CNT 128
+#define FV_TX_RING_SIZE sizeof(struct fv_desc) * FV_TX_RING_CNT
+#define FV_RX_RING_SIZE sizeof(struct fv_desc) * FV_RX_RING_CNT
+#define FV_RING_ALIGN sizeof(struct fv_desc)
+#define FV_RX_ALIGN sizeof(uint32_t)
+#define FV_MAXFRAGS 8
+#define FV_TX_INTR_THRESH 8
+
+#define FV_TX_RING_ADDR(sc, i) \
+ ((sc)->fv_rdata.fv_tx_ring_paddr + sizeof(struct fv_desc) * (i))
+#define FV_RX_RING_ADDR(sc, i) \
+ ((sc)->fv_rdata.fv_rx_ring_paddr + sizeof(struct fv_desc) * (i))
+#define FV_INC(x,y) (x) = (((x) + 1) % y)
+
+struct fv_txdesc {
+ struct mbuf *tx_m;
+ bus_dmamap_t tx_dmamap;
+};
+
+struct fv_rxdesc {
+ struct mbuf *rx_m;
+ bus_dmamap_t rx_dmamap;
+ struct fv_desc *desc;
+ /* Use this values on error instead of allocating new mbuf */
+ uint32_t saved_ctl, saved_ca;
+};
+
+struct fv_chain_data {
+ bus_dma_tag_t fv_parent_tag;
+ bus_dma_tag_t fv_tx_tag;
+ struct fv_txdesc fv_txdesc[FV_TX_RING_CNT];
+ bus_dma_tag_t fv_rx_tag;
+ struct fv_rxdesc fv_rxdesc[FV_RX_RING_CNT];
+ bus_dma_tag_t fv_tx_ring_tag;
+ bus_dma_tag_t fv_rx_ring_tag;
+ bus_dmamap_t fv_tx_ring_map;
+ bus_dmamap_t fv_rx_ring_map;
+ bus_dmamap_t fv_rx_sparemap;
+ int fv_tx_pkts;
+ int fv_tx_prod;
+ int fv_tx_cons;
+ int fv_tx_cnt;
+ int fv_rx_cons;
+
+ bus_dma_tag_t fv_sf_tag;
+ bus_dmamap_t fv_sf_buff_map;
+ uint32_t *fv_sf_buff;
+};
+
+struct fv_ring_data {
+ struct fv_desc *fv_rx_ring;
+ struct fv_desc *fv_tx_ring;
+ bus_addr_t fv_rx_ring_paddr;
+ bus_addr_t fv_tx_ring_paddr;
+ bus_addr_t fv_sf_paddr;
+};
+
+struct fv_softc {
+ struct ifnet *fv_ifp; /* interface info */
+ bus_space_handle_t fv_bhandle; /* bus space handle */
+ bus_space_tag_t fv_btag; /* bus space tag */
+ device_t fv_dev;
+ uint8_t fv_eaddr[ETHER_ADDR_LEN];
+ struct resource *fv_res;
+ int fv_rid;
+ struct resource *fv_irq;
+ void *fv_intrhand;
+ u_int32_t sc_inten; /* copy of CSR_INTEN */
+ u_int32_t sc_rxint_mask; /* mask of Rx interrupts we want */
+ u_int32_t sc_txint_mask; /* mask of Tx interrupts we want */
+#ifdef MII
+ device_t fv_miibus;
+#else
+ struct ifmedia fv_ifmedia;
+#endif
+#ifdef FV_MDIO
+ device_t fv_miiproxy;
+#endif
+ int fv_if_flags;
+ bus_dma_tag_t fv_parent_tag;
+ bus_dma_tag_t fv_tag;
+ struct mtx fv_mtx;
+ phandle_t fv_ofw;
+ struct callout fv_stat_callout;
+ struct task fv_link_task;
+ struct fv_chain_data fv_cdata;
+ struct fv_ring_data fv_rdata;
+ int fv_link_status;
+ int fv_detach;
+};
+
+#define FV_LOCK(_sc) mtx_lock(&(_sc)->fv_mtx)
+#define FV_UNLOCK(_sc) mtx_unlock(&(_sc)->fv_mtx)
+#define FV_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->fv_mtx, MA_OWNED)
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->fv_btag, sc->fv_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->fv_btag, sc->fv_bhandle, reg)
+
+
+/* $NetBSD: aereg.h,v 1.2 2008/04/28 20:23:28 martin Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWFV IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE FV DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWFV, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Descriptor Status bits common to transmit and receive.
+ */
+#define ADSTAT_OWN 0x80000000 /* Tulip owns descriptor */
+#define ADSTAT_ES 0x00008000 /* Error Summary */
+
+/*
+ * Descriptor Status bits for Receive Descriptor.
+ */
+#define ADSTAT_Rx_FF 0x40000000 /* Filtering Fail */
+#define ADSTAT_Rx_FL 0x3fff0000 /* Frame Length including CRC */
+#define ADSTAT_Rx_DE 0x00004000 /* Descriptor Error */
+#define ADSTAT_Rx_LE 0x00001000 /* Length Error */
+#define ADSTAT_Rx_RF 0x00000800 /* Runt Frame */
+#define ADSTAT_Rx_MF 0x00000400 /* Multicast Frame */
+#define ADSTAT_Rx_FS 0x00000200 /* First Descriptor */
+#define ADSTAT_Rx_LS 0x00000100 /* Last Descriptor */
+#define ADSTAT_Rx_TL 0x00000080 /* Frame Too Long */
+#define ADSTAT_Rx_CS 0x00000040 /* Collision Seen */
+#define ADSTAT_Rx_RT 0x00000020 /* Frame Type */
+#define ADSTAT_Rx_RW 0x00000010 /* Receive Watchdog */
+#define ADSTAT_Rx_RE 0x00000008 /* Report on MII Error */
+#define ADSTAT_Rx_DB 0x00000004 /* Dribbling Bit */
+#define ADSTAT_Rx_CE 0x00000002 /* CRC Error */
+#define ADSTAT_Rx_ZER 0x00000001 /* Zero (always 0) */
+
+#define ADSTAT_Rx_LENGTH(x) (((x) & ADSTAT_Rx_FL) >> 16)
+
+/*
+ * Descriptor Status bits for Transmit Descriptor.
+ */
+#define ADSTAT_Tx_ES 0x00008000 /* Error Summary */
+#define ADSTAT_Tx_TO 0x00004000 /* Transmit Jabber Timeout */
+#define ADSTAT_Tx_LO 0x00000800 /* Loss of Carrier */
+#define ADSTAT_Tx_NC 0x00000400 /* No Carrier */
+#define ADSTAT_Tx_LC 0x00000200 /* Late Collision */
+#define ADSTAT_Tx_EC 0x00000100 /* Excessive Collisions */
+#define ADSTAT_Tx_HF 0x00000080 /* Heartbeat Fail */
+#define ADSTAT_Tx_CC 0x00000078 /* Collision Count */
+#define ADSTAT_Tx_ED 0x00000004 /* Excessive Deferral */
+#define ADSTAT_Tx_UF 0x00000002 /* Underflow Error */
+#define ADSTAT_Tx_DE 0x00000001 /* Deferred */
+
+#define ADSTAT_Tx_COLLISIONS(x) (((x) & ADSTAT_Tx_CC) >> 3)
+
+/*
+ * Descriptor Control bits common to transmit and receive.
+ */
+#define ADCTL_SIZE1 0x000007ff /* Size of buffer 1 */
+#define ADCTL_SIZE1_SHIFT 0
+
+#define ADCTL_SIZE2 0x003ff800 /* Size of buffer 2 */
+#define ADCTL_SIZE2_SHIFT 11
+
+#define ADCTL_ER 0x02000000 /* End of Ring */
+#define ADCTL_CH 0x01000000 /* Second Address Chained */
+
+/*
+ * Descriptor Control bits for Transmit Descriptor.
+ */
+#define ADCTL_Tx_IC 0x80000000 /* Interrupt on Completion */
+#define ADCTL_Tx_LS 0x40000000 /* Last Segment */
+#define ADCTL_Tx_FS 0x20000000 /* First Segment */
+#define ADCTL_Tx_SETUP 0x08000000 /* Setup frame */
+#define ADCTL_Tx_AC 0x04000000 /* Add CRC Disable */
+#define ADCTL_Tx_DPD 0x00800000 /* Disabled Padding */
+
+/*
+ * Control registers.
+ */
+
+/* tese are registers only found on this part */
+#ifdef NOTUSE
+#define CSR_MACCTL 0x0000 /* mac control */
+#define CSR_MACHI 0x0004
+#define CSR_MACLO 0x0008
+#define CSR_HTHI 0x000C /* multicast table high */
+#define CSR_HTLO 0x0010 /* multicast table low */
+#define CSR_MIIADDR 0x0014 /* mii address */
+#define CSR_MIIDATA 0x0018 /* mii data */
+#define CSR_FLOWC 0x001C /* flow control */
+#define CSR_VL1 0x0020 /* vlan 1 tag */
+#endif
+
+/* these are more or less normal Tulip registers */
+#define CSR_BUSMODE (0x08*0) /* bus mode */
+#define CSR_TXPOLL (0x08*1) /* tx poll demand */
+#define CSR_RXPOLL (0x08*2) /* rx poll demand */
+#define CSR_RXLIST (0x08*3) /* rx base descriptor address */
+#define CSR_TXLIST (0x08*4) /* tx base descriptor address */
+#define CSR_STATUS (0x08*5) /* (interrupt) status */
+#define CSR_OPMODE (0x08*6) /* operation mode */
+#define CSR_INTEN (0x08*7) /* interrupt enable */
+#define CSR_MISSED (0x08*8) /* missed frame counter */
+
+#ifdef NOTUSE
+#define CSR_HTBA 0x1050 /* host tx buffer address (ro) */
+#define CSR_HRBA 0x1054 /* host rx buffer address (ro) */
+#endif
+
+#define CSR_MIIMNG (0x08*9) /* MII Management Register */
+#define CSR_FULLDUP (0x08*11) /* Full Duplex Register */
+
+/* 21143 like register */
+#define FULLDUP_CS 0x80000000 /* Cycle Size */
+#define FULLDUP_TT_SHIFT 27 /* Transmit Timer */
+#define FULLDUP_NTP_SHIFT 24 /* Number of Transmit Packets */
+#define FULLDUP_RT_SHIFT 20 /* Receive Timer */
+#define FULLDUP_NRP_SHIFT 17 /* Number of Receive Packets */
+#define FULLDUP_CON_MODE 0x00010000 /* Continuous Mode */
+#define FULLDUP_TIM_SHIFT 0 /* Timer Value */
+
+/* CSR_MACCTL - Mac Control */
+#define MACCTL_RE 0x00000004 /* rx enable */
+#define MACCTL_TE 0x00000008 /* tx enable */
+#define MACCTL_DC 0x00000020 /* deferral check */
+#define MACCTL_PSTR 0x00000100 /* automatic pad strip */
+#define MACCTL_DTRY 0x00000400 /* disable retry */
+#define MACCTL_DBF 0x00000800 /* disable broadcast frames */
+#define MACCTL_LCC 0x00001000 /* late collision control */
+#define MACCTL_HASH 0x00002000 /* hash filtering enable */
+#define MACCTL_HO 0x00008000 /* disable perfect filtering */
+#define MACCTL_PB 0x00010000 /* pass bad frames */
+#define MACCTL_IF 0x00020000 /* inverse filtering */
+#define MACCTL_PR 0x00040000 /* promiscuous mode */
+#define MACCTL_PM 0x00080000 /* pass all multicast */
+#define MACCTL_FDX 0x00100000 /* full duplex mode */
+#define MACCTL_LOOP 0x00600000 /* loopback mask */
+#define MACCTL_LOOP_INT 0x00200000 /* internal loopback */
+#define MACCTL_LOOP_EXT 0x00400000 /* external loopback */
+#define MACCTL_LOOP_NONE 0x00000000
+#define MACCTL_DRO 0x00800000 /* disable receive own */
+#define MACCTL_PS 0x08000000 /* port select, 0 = mii */
+#define MACCTL_HBD 0x10000000 /* heartbeat disable */
+#define MACCTL_BLE 0x40000000 /* mac big endian */
+#define MACCTL_RA 0x80000000 /* receive all packets */
+
+/* CSR_MIIADDR - MII Addess */
+#define MIIADDR_BUSY 0x00000001 /* mii busy */
+#define MIIADDR_WRITE 0x00000002 /* mii write */
+#define MIIADDR_REG_MASK 0x000007C0 /* mii register */
+#define MIIADDR_REG_SHIFT 6
+#define MIIADDR_PHY_MASK 0x0000F800 /* mii phy */
+#define MIIADDR_PHY_SHIFT 11
+
+#define MIIADDR_GETREG(x) (((x) & MIIADDR_REG) >> 6)
+#define MIIADDR_PUTREG(x) (((x) << 6) & MIIADR_REG)
+#define MIIADDR_GETPHY(x) (((x) & MIIADDR_PHY) >> 11)
+#define MIIADDR_PUTPHY(x) (((x) << 6) & MIIADR_PHY)
+
+/* CSR_FLOWC - Flow Control */
+#define FLOWC_FCB 0x00000001 /* flow control busy */
+#define FLOWC_FCE 0x00000002 /* flow control enable */
+#define FLOWC_PCF 0x00000004 /* pass control frames */
+#define FLOWC_PT 0xffff0000 /* pause time */
+
+/* CSR_BUSMODE - Bus Mode */
+#define BUSMODE_SWR 0x00000001 /* software reset */
+#define BUSMODE_BAR 0x00000002 /* bus arbitration */
+#define BUSMODE_DSL 0x0000007c /* descriptor skip length */
+#define BUSMODE_BLE 0x00000080 /* data buf endian */
+ /* programmable burst length */
+#define BUSMODE_PBL_DEFAULT 0x00000000 /* default value */
+#define BUSMODE_PBL_1LW 0x00000100 /* 1 longword */
+#define BUSMODE_PBL_2LW 0x00000200 /* 2 longwords */
+#define BUSMODE_PBL_4LW 0x00000400 /* 4 longwords */
+#define BUSMODE_PBL_8LW 0x00000800 /* 8 longwords */
+#define BUSMODE_PBL_16LW 0x00001000 /* 16 longwords */
+#define BUSMODE_PBL_32LW 0x00002000 /* 32 longwords */
+#define BUSMODE_TAP_SHIFT 17 /* Transmit Automatic Polling */
+#define BUSMODE_DBO 0x00100000 /* descriptor endian */
+#define BUSMODE_ALIGN_16B 0x01000000 /* force oddhw rx buf align */
+
+/* CSR_TXPOLL - Transmit Poll Demand */
+#define TXPOLL_TPD 0x00000001 /* transmit poll demand */
+
+
+/* CSR_RXPOLL - Receive Poll Demand */
+#define RXPOLL_RPD 0x00000001 /* receive poll demand */
+
+/* CSR_STATUS - Status */
+#define STATUS_TI 0x00000001 /* transmit interrupt */
+#define STATUS_TPS 0x00000002 /* transmit process stopped */
+#define STATUS_TU 0x00000004 /* transmit buffer unavail */
+#define STATUS_TJT 0x00000008 /* transmit jabber timeout */
+#define STATUS_UNF 0x00000020 /* transmit underflow */
+#define STATUS_RI 0x00000040 /* receive interrupt */
+#define STATUS_RU 0x00000080 /* receive buffer unavail */
+#define STATUS_RPS 0x00000100 /* receive process stopped */
+#define STATUS_ETI 0x00000400 /* early transmit interrupt */
+#define STATUS_SE 0x00002000 /* system error */
+#define STATUS_ER 0x00004000 /* early receive (21041) */
+#define STATUS_AIS 0x00008000 /* abnormal intr summary */
+#define STATUS_NIS 0x00010000 /* normal interrupt summary */
+#define STATUS_RS 0x000e0000 /* receive process state */
+#define STATUS_RS_STOPPED 0x00000000 /* Stopped */
+#define STATUS_RS_FETCH 0x00020000 /* Running - fetch receive
+ descriptor */
+#define STATUS_RS_CHECK 0x00040000 /* Running - check for end
+ of receive */
+#define STATUS_RS_WAIT 0x00060000 /* Running - wait for packet */
+#define STATUS_RS_SUSPENDED 0x00080000 /* Suspended */
+#define STATUS_RS_CLOSE 0x000a0000 /* Running - close receive
+ descriptor */
+#define STATUS_RS_FLUSH 0x000c0000 /* Running - flush current
+ frame from FIFO */
+#define STATUS_RS_QUEUE 0x000e0000 /* Running - queue current
+ frame from FIFO into
+ buffer */
+#define STATUS_TS 0x00700000 /* transmit process state */
+#define STATUS_TS_STOPPED 0x00000000 /* Stopped */
+#define STATUS_TS_FETCH 0x00100000 /* Running - fetch transmit
+ descriptor */
+#define STATUS_TS_WAIT 0x00200000 /* Running - wait for end
+ of transmission */
+#define STATUS_TS_READING 0x00300000 /* Running - read buffer from
+ memory and queue into
+ FIFO */
+#define STATUS_TS_SUSPENDED 0x00600000 /* Suspended */
+#define STATUS_TS_CLOSE 0x00700000 /* Running - close transmit
+ descriptor */
+#define STATUS_TX_ABORT 0x00800000 /* Transmit bus abort */
+#define STATUS_RX_ABORT 0x01000000 /* Transmit bus abort */
+
+/* CSR_OPMODE - Operation Mode */
+#define OPMODE_SR 0x00000002 /* start receive */
+#define OPMODE_OSF 0x00000004 /* operate on second frame */
+#define OPMODE_PR 0x00000040 /* promiscuous mode */
+#define OPMODE_PM 0x00000080 /* pass all multicast */
+#define OPMODE_FDX 0x00000200 /* full duplex mode */
+#define OPMODE_ST 0x00002000 /* start transmitter */
+#define OPMODE_TR 0x0000c000 /* threshold control */
+#define OPMODE_TR_32 0x00000000 /* 32 words */
+#define OPMODE_TR_64 0x00004000 /* 64 words */
+#define OPMODE_TR_128 0x00008000 /* 128 words */
+#define OPMODE_TR_256 0x0000c000 /* 256 words */
+#define OPMODE_SF 0x00200000 /* store and forward mode */
+#define OPMODE_SPEED 0x80000000 /* speed 100M:1 10M:0 */
+
+/* CSR_INTEN - Interrupt Enable */
+ /* See bits for CSR_STATUS -- Status */
+
+
+/* CSR_MISSED - Missed Frames */
+#define MISSED_MFC 0xffff0000 /* missed packet count */
+#define MISSED_FOC 0x0000ffff /* fifo overflow counter */
+
+#define MISSED_GETMFC(x) ((x) & MISSED_MFC)
+#define MISSED_GETFOC(x) (((x) & MISSED_FOC) >> 16)
+
+/* setup frame code refer dc code */
+
+#define FV_SFRAME_LEN 192
+#define FV_MIN_FRAMELEN 60
+
+/*
+ * MII Definitions for the 21041 and 21140/21140A/21142
+ * copy from if_devar.h
+ */
+#define MII_PREAMBLE (~0)
+#define MII_TEST 0xAAAAAAAA
+#define MII_RDCMD 0x06
+#define MII_WRCMD 0x05
+#define MII_DIN 0x00080000
+#define MII_RD 0x00040000
+#define MII_WR 0x00000000
+#define MII_DOUT 0x00020000
+#define MII_CLK 0x00010000
+#define MII_CLKON MII_CLK
+#define MII_CLKOFF MII_CLK
+
+#endif /* __IF_FVREG_H__ */
Index: head/sys/arm/ralink/rt1310_gpio.c
===================================================================
--- head/sys/arm/ralink/rt1310_gpio.c
+++ head/sys/arm/ralink/rt1310_gpio.c
@@ -0,0 +1,480 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org>
+ * Copyright (c) 2015 Hiroki Mori
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * GPIO on RT1310A consist of 2 ports:
+ * - PortA with 8 input/output pins
+ * - PortB with 4 input/output pins
+ *
+ * Pins are mapped to logical pin number as follows:
+ * [0..7] -> GPI_00..GPI_07 (port A)
+ * [8..11] -> GPI_08..GPI_11 (port B)
+ *
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+#include <machine/fdt.h>
+
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ralink/rt1310reg.h>
+#include <arm/ralink/rt1310var.h>
+
+#include "gpio_if.h"
+
+struct rt1310_gpio_softc
+{
+ device_t lg_dev;
+ device_t lg_busdev;
+ struct resource * lg_res;
+ bus_space_tag_t lg_bst;
+ bus_space_handle_t lg_bsh;
+};
+
+struct rt1310_gpio_pinmap
+{
+ int lp_start_idx;
+ int lp_pin_count;
+ int lp_port;
+ int lp_start_bit;
+ int lp_flags;
+};
+
+static const struct rt1310_gpio_pinmap rt1310_gpio_pins[] = {
+ { 0, 8, RT_GPIO_PORTA, 0, GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
+ { 8, 4, RT_GPIO_PORTB, 0, GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
+ { -1, -1, -1, -1, -1 },
+};
+
+#define RT_GPIO_NPINS 12
+
+#define RT_GPIO_PIN_IDX(_map, _idx) \
+ (_idx - _map->lp_start_idx)
+
+#define RT_GPIO_PIN_BIT(_map, _idx) \
+ (_map->lp_start_bit + RT_GPIO_PIN_IDX(_map, _idx))
+
+static int rt1310_gpio_probe(device_t);
+static int rt1310_gpio_attach(device_t);
+static int rt1310_gpio_detach(device_t);
+
+static device_t rt1310_gpio_get_bus(device_t);
+static int rt1310_gpio_pin_max(device_t, int *);
+static int rt1310_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);
+static int rt1310_gpio_pin_getflags(device_t, uint32_t, uint32_t *);
+static int rt1310_gpio_pin_setflags(device_t, uint32_t, uint32_t);
+static int rt1310_gpio_pin_getname(device_t, uint32_t, char *);
+static int rt1310_gpio_pin_get(device_t, uint32_t, uint32_t *);
+static int rt1310_gpio_pin_set(device_t, uint32_t, uint32_t);
+static int rt1310_gpio_pin_toggle(device_t, uint32_t);
+
+static const struct rt1310_gpio_pinmap *rt1310_gpio_get_pinmap(int);
+
+static struct rt1310_gpio_softc *rt1310_gpio_sc = NULL;
+
+#define rt1310_gpio_read_4(_sc, _reg) \
+ bus_space_read_4(_sc->lg_bst, _sc->lg_bsh, _reg)
+#define rt1310_gpio_write_4(_sc, _reg, _val) \
+ bus_space_write_4(_sc->lg_bst, _sc->lg_bsh, _reg, _val)
+
+static int
+rt1310_gpio_probe(device_t dev)
+{
+ phandle_t node;
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "ralink,rt1310-gpio"))
+ return (ENXIO);
+
+ node = ofw_bus_get_node(dev);
+ if (!OF_hasprop(node, "gpio-controller"))
+ return (ENXIO);
+
+ device_set_desc(dev, "RT1310 GPIO");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+rt1310_gpio_attach(device_t dev)
+{
+ struct rt1310_gpio_softc *sc = device_get_softc(dev);
+ int rid;
+
+ sc->lg_dev = dev;
+
+ rid = 0;
+ sc->lg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->lg_res) {
+ device_printf(dev, "cannot allocate memory window\n");
+ return (ENXIO);
+ }
+
+ sc->lg_bst = rman_get_bustag(sc->lg_res);
+ sc->lg_bsh = rman_get_bushandle(sc->lg_res);
+
+ rt1310_gpio_sc = sc;
+
+ sc->lg_busdev = gpiobus_attach_bus(dev);
+ if (sc->lg_busdev == NULL) {
+ bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->lg_res);
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+rt1310_gpio_detach(device_t dev)
+{
+ return (EBUSY);
+}
+
+static device_t
+rt1310_gpio_get_bus(device_t dev)
+{
+ struct rt1310_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ return (sc->lg_busdev);
+}
+
+static int
+rt1310_gpio_pin_max(device_t dev, int *npins)
+{
+ *npins = RT_GPIO_NPINS - 1;
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+ const struct rt1310_gpio_pinmap *map;
+
+ if (pin > RT_GPIO_NPINS)
+ return (ENODEV);
+
+ map = rt1310_gpio_get_pinmap(pin);
+
+ *caps = map->lp_flags;
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+ struct rt1310_gpio_softc *sc = device_get_softc(dev);
+ const struct rt1310_gpio_pinmap *map;
+ uint32_t state;
+ int dir;
+
+ if (pin > RT_GPIO_NPINS)
+ return (ENODEV);
+
+ map = rt1310_gpio_get_pinmap(pin);
+
+ /* Check whether it's bidirectional pin */
+ if ((map->lp_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) !=
+ (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
+ *flags = map->lp_flags;
+ return (0);
+ }
+
+ switch (map->lp_port) {
+ case RT_GPIO_PORTA:
+ state = rt1310_gpio_read_4(sc, RT_GPIO_OFF_PADIR);
+ dir = (state & (1 << RT_GPIO_PIN_BIT(map, pin)));
+ break;
+ case RT_GPIO_PORTB:
+ state = rt1310_gpio_read_4(sc, RT_GPIO_OFF_PBDIR);
+ dir = (state & (1 << RT_GPIO_PIN_BIT(map, pin)));
+ break;
+ default:
+ panic("unknown GPIO port");
+ }
+
+ *flags = dir ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
+
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+ struct rt1310_gpio_softc *sc = device_get_softc(dev);
+ const struct rt1310_gpio_pinmap *map;
+ uint32_t dir, state;
+ uint32_t port;
+
+ if (pin > RT_GPIO_NPINS)
+ return (ENODEV);
+
+ map = rt1310_gpio_get_pinmap(pin);
+
+ /* Check whether it's bidirectional pin */
+ if ((map->lp_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) !=
+ (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
+ return (ENOTSUP);
+
+ if (flags & GPIO_PIN_INPUT)
+ dir = 0;
+
+ if (flags & GPIO_PIN_OUTPUT)
+ dir = 1;
+
+ switch (map->lp_port) {
+ case RT_GPIO_PORTA:
+ port = RT_GPIO_OFF_PADIR;
+ break;
+ case RT_GPIO_PORTB:
+ port = RT_GPIO_OFF_PBDIR;
+ break;
+ }
+
+ state = rt1310_gpio_read_4(sc, port);
+ if (flags & GPIO_PIN_INPUT) {
+ state &= ~(1 << RT_GPIO_PIN_IDX(map, pin));
+ } else {
+ state |= (1 << RT_GPIO_PIN_IDX(map, pin));
+ }
+ rt1310_gpio_write_4(sc, port, state);
+
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+ snprintf(name, GPIOMAXNAME - 1, "GPIO_%02d", pin);
+
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *value)
+{
+ struct rt1310_gpio_softc *sc = device_get_softc(dev);
+ const struct rt1310_gpio_pinmap *map;
+ uint32_t state, flags;
+ int dir;
+
+ map = rt1310_gpio_get_pinmap(pin);
+
+ if (rt1310_gpio_pin_getflags(dev, pin, &flags))
+ return (ENXIO);
+
+ if (flags & GPIO_PIN_OUTPUT)
+ dir = 1;
+
+ if (flags & GPIO_PIN_INPUT)
+ dir = 0;
+
+ switch (map->lp_port) {
+ case RT_GPIO_PORTA:
+ state = rt1310_gpio_read_4(sc, RT_GPIO_OFF_PADR);
+ *value = !!(state & (1 << RT_GPIO_PIN_BIT(map, pin)));
+ break;
+ case RT_GPIO_PORTB:
+ state = rt1310_gpio_read_4(sc, RT_GPIO_OFF_PBDR);
+ *value = !!(state & (1 << RT_GPIO_PIN_BIT(map, pin)));
+ break;
+ }
+
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_set(device_t dev, uint32_t pin, uint32_t value)
+{
+ struct rt1310_gpio_softc *sc = device_get_softc(dev);
+ const struct rt1310_gpio_pinmap *map;
+ uint32_t state, flags;
+ uint32_t port;
+
+ map = rt1310_gpio_get_pinmap(pin);
+
+ if (rt1310_gpio_pin_getflags(dev, pin, &flags))
+ return (ENXIO);
+
+ if ((flags & GPIO_PIN_OUTPUT) == 0)
+ return (EINVAL);
+
+ switch (map->lp_port) {
+ case RT_GPIO_PORTA:
+ port = RT_GPIO_OFF_PADR;
+ break;
+ case RT_GPIO_PORTB:
+ port = RT_GPIO_OFF_PBDR;
+ break;
+ }
+
+ state = rt1310_gpio_read_4(sc, port);
+ if (value == 1) {
+ state |= (1 << RT_GPIO_PIN_BIT(map, pin));
+ } else {
+ state &= ~(1 << RT_GPIO_PIN_BIT(map, pin));
+ }
+ rt1310_gpio_write_4(sc, port, state);
+
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+ const struct rt1310_gpio_pinmap *map;
+ uint32_t flags;
+
+ map = rt1310_gpio_get_pinmap(pin);
+
+ if (rt1310_gpio_pin_getflags(dev, pin, &flags))
+ return (ENXIO);
+
+ if ((flags & GPIO_PIN_OUTPUT) == 0)
+ return (EINVAL);
+
+ panic("not implemented yet");
+
+ return (0);
+
+}
+
+static const struct rt1310_gpio_pinmap *
+rt1310_gpio_get_pinmap(int pin)
+{
+ const struct rt1310_gpio_pinmap *map;
+
+ for (map = &rt1310_gpio_pins[0]; map->lp_start_idx != -1; map++) {
+ if (pin >= map->lp_start_idx &&
+ pin < map->lp_start_idx + map->lp_pin_count)
+ return map;
+ }
+
+ panic("pin number %d out of range", pin);
+}
+
+int
+rt1310_gpio_set_flags(device_t dev, int pin, int flags)
+{
+ if (rt1310_gpio_sc == NULL)
+ return (ENXIO);
+
+ return rt1310_gpio_pin_setflags(rt1310_gpio_sc->lg_dev, pin, flags);
+}
+
+int
+rt1310_gpio_set_state(device_t dev, int pin, int state)
+{
+ if (rt1310_gpio_sc == NULL)
+ return (ENXIO);
+
+ return rt1310_gpio_pin_set(rt1310_gpio_sc->lg_dev, pin, state);
+}
+
+int
+rt1310_gpio_get_state(device_t dev, int pin, int *state)
+{
+ if (rt1310_gpio_sc == NULL)
+ return (ENXIO);
+
+ return rt1310_gpio_pin_get(rt1310_gpio_sc->lg_dev, pin, state);
+}
+
+static phandle_t
+rt1310_gpio_get_node(device_t bus, device_t dev)
+{
+ /* We only have one child, the GPIO bus, which needs our own node. */
+ return (ofw_bus_get_node(bus));
+}
+
+static device_method_t rt1310_gpio_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, rt1310_gpio_probe),
+ DEVMETHOD(device_attach, rt1310_gpio_attach),
+ DEVMETHOD(device_detach, rt1310_gpio_detach),
+
+ /* GPIO interface */
+ DEVMETHOD(gpio_get_bus, rt1310_gpio_get_bus),
+ DEVMETHOD(gpio_pin_max, rt1310_gpio_pin_max),
+ DEVMETHOD(gpio_pin_getcaps, rt1310_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_getflags, rt1310_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_setflags, rt1310_gpio_pin_setflags),
+ DEVMETHOD(gpio_pin_getname, rt1310_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_set, rt1310_gpio_pin_set),
+ DEVMETHOD(gpio_pin_get, rt1310_gpio_pin_get),
+ DEVMETHOD(gpio_pin_toggle, rt1310_gpio_pin_toggle),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, rt1310_gpio_get_node),
+
+ { 0, 0 }
+};
+
+static devclass_t rt1310_gpio_devclass;
+
+static driver_t rt1310_gpio_driver = {
+ "gpio",
+ rt1310_gpio_methods,
+ sizeof(struct rt1310_gpio_softc),
+};
+
+DRIVER_MODULE(rt1310gpio, simplebus, rt1310_gpio_driver, rt1310_gpio_devclass, 0, 0);
+MODULE_VERSION(rt1310gpio, 1);
Index: head/sys/arm/ralink/rt1310_intc.c
===================================================================
--- head/sys/arm/ralink/rt1310_intc.c
+++ head/sys/arm/ralink/rt1310_intc.c
@@ -0,0 +1,441 @@
+/*-
+ * Copyright (c) 2010 Jakub Wojciech Klama <jceel@FreeBSD.org>
+ * Copyright (c) 2015 Hiroki Mori
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_platform.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/rman.h>
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ralink/rt1310reg.h>
+
+#define INTC_NIRQS 32
+
+#ifdef INTRNG
+#include "pic_if.h"
+
+struct rt1310_irqsrc {
+ struct intr_irqsrc ri_isrc;
+ u_int ri_irq;
+};
+#endif
+
+struct rt1310_intc_softc {
+ device_t dev;
+ struct resource * ri_res;
+ bus_space_tag_t ri_bst;
+ bus_space_handle_t ri_bsh;
+#ifdef INTRNG
+ struct rt1310_irqsrc ri_isrcs[INTC_NIRQS];
+#endif
+};
+
+static int rt1310_intc_probe(device_t);
+static int rt1310_intc_attach(device_t);
+#ifndef INTRNG
+static void rt1310_intc_eoi(void *);
+#else
+static int rt1310_pic_attach(struct rt1310_intc_softc *sc);
+#endif
+
+static struct rt1310_intc_softc *intc_softc = NULL;
+
+#define intc_read_4(_sc, _reg) \
+ bus_space_read_4((_sc)->ri_bst, (_sc)->ri_bsh, (_reg))
+#define intc_write_4(_sc, _reg, _val) \
+ bus_space_write_4((_sc)->ri_bst, (_sc)->ri_bsh, (_reg), (_val))
+
+struct rt1310_irqdef {
+ u_int ri_trig;
+ u_int ri_prio;
+};
+
+struct rt1310_irqdef irqdef[INTC_NIRQS] = {
+ {RT_INTC_TRIG_HIGH_LVL, 2}, /* 0 */
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 1},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 1},
+ {RT_INTC_TRIG_HIGH_LVL, 1},
+ {RT_INTC_TRIG_HIGH_LVL, 1},
+ {RT_INTC_TRIG_HIGH_LVL, 1}, /* 8 */
+ {RT_INTC_TRIG_HIGH_LVL, 1},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 4},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 2}, /* 16 */
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 2},
+ {RT_INTC_TRIG_NEG_EDGE, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 3},
+ {RT_INTC_TRIG_HIGH_LVL, 2}, /* 24 */
+ {RT_INTC_TRIG_POS_EDGE, 2},
+ {RT_INTC_TRIG_POS_EDGE, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_POS_EDGE, 2},
+ {RT_INTC_TRIG_POS_EDGE, 3},
+ {RT_INTC_TRIG_POS_EDGE, 3},
+};
+
+static int
+rt1310_intc_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "rt,pic"))
+ return (ENXIO);
+
+#ifdef INTRNG
+ device_set_desc(dev, "RT1310 INTRNG Interrupt Controller");
+#else
+ device_set_desc(dev, "RT1310 Interrupt Controller");
+#endif
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+rt1310_intc_attach(device_t dev)
+{
+ struct rt1310_intc_softc *sc = device_get_softc(dev);
+ int rid = 0;
+ int i;
+
+ if (intc_softc)
+ return (ENXIO);
+
+ sc->dev = dev;
+
+ sc->ri_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->ri_res) {
+ device_printf(dev, "could not alloc resources\n");
+ return (ENXIO);
+ }
+
+ sc->ri_bst = rman_get_bustag(sc->ri_res);
+ sc->ri_bsh = rman_get_bushandle(sc->ri_res);
+ intc_softc = sc;
+#ifndef INTRNG
+ arm_post_filter = rt1310_intc_eoi;
+#else
+ rt1310_pic_attach(sc);
+#endif
+
+ intc_write_4(sc, RT_INTC_IECR, 0);
+ intc_write_4(sc, RT_INTC_ICCR, ~0);
+
+ for (i = 0; i <= INTC_NIRQS; ++i) {
+ intc_write_4(sc, RT_INTC_SCR0+i*4,
+ (irqdef[i].ri_trig << RT_INTC_TRIG_SHIF) |
+ irqdef[i].ri_prio);
+ intc_write_4(sc, RT_INTC_SVR0+i*4, i);
+ }
+
+ /* Clear interrupt status registers and disable all interrupts */
+ intc_write_4(sc, RT_INTC_ICCR, ~0);
+ intc_write_4(sc, RT_INTC_IMR, 0);
+ return (0);
+}
+
+#ifndef INTRNG
+int
+arm_get_next_irq(int last)
+{
+ struct rt1310_intc_softc *sc = intc_softc;
+ uint32_t value;
+ int i;
+ value = intc_read_4(sc, RT_INTC_IPR);
+ for (i = 0; i < 32; i++) {
+ if (value & (1 << i))
+ return (i);
+ }
+
+ return (-1);
+}
+
+void
+arm_mask_irq(uintptr_t nb)
+{
+ struct rt1310_intc_softc *sc = intc_softc;
+ uint32_t value;
+
+ /* Make sure that interrupt isn't active already */
+ rt1310_intc_eoi((void *)nb);
+
+ /* Clear bit in ER register */
+ value = intc_read_4(sc, RT_INTC_IECR);
+ value &= ~(1 << nb);
+ intc_write_4(sc, RT_INTC_IECR, value);
+ intc_write_4(sc, RT_INTC_IMR, value);
+
+ intc_write_4(sc, RT_INTC_ICCR, 1 << nb);
+}
+
+void
+arm_unmask_irq(uintptr_t nb)
+{
+ struct rt1310_intc_softc *sc = intc_softc;
+ uint32_t value;
+
+ value = intc_read_4(sc, RT_INTC_IECR);
+
+ value |= (1 << nb);
+
+ intc_write_4(sc, RT_INTC_IMR, value);
+ intc_write_4(sc, RT_INTC_IECR, value);
+}
+
+static void
+rt1310_intc_eoi(void *data)
+{
+ struct rt1310_intc_softc *sc = intc_softc;
+ int nb = (int)data;
+
+ intc_write_4(sc, RT_INTC_ICCR, 1 << nb);
+ if (nb == 0) {
+ uint32_t value;
+ value = intc_read_4(sc, RT_INTC_IECR);
+ value &= ~(1 << nb);
+ intc_write_4(sc, RT_INTC_IECR, value);
+ intc_write_4(sc, RT_INTC_IMR, value);
+ }
+}
+
+#else
+
+static void
+rt1310_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq;
+ unsigned int value;
+ struct rt1310_intc_softc *sc;
+
+ sc = intc_softc;
+ irq = ((struct rt1310_irqsrc *)isrc)->ri_irq;
+
+ value = intc_read_4(sc, RT_INTC_IECR);
+
+ value |= (1 << irq);
+
+ intc_write_4(sc, RT_INTC_IMR, value);
+ intc_write_4(sc, RT_INTC_IECR, value);
+}
+
+static void
+rt1310_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq;
+ unsigned int value;
+ struct rt1310_intc_softc *sc;
+
+ sc = intc_softc;
+ irq = ((struct rt1310_irqsrc *)isrc)->ri_irq;
+
+ /* Clear bit in ER register */
+ value = intc_read_4(sc, RT_INTC_IECR);
+ value &= ~(1 << irq);
+ intc_write_4(sc, RT_INTC_IECR, value);
+ intc_write_4(sc, RT_INTC_IMR, value);
+
+ intc_write_4(sc, RT_INTC_ICCR, 1 << irq);
+}
+
+static int
+rt1310_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
+{
+ struct intr_map_data_fdt *daf;
+ struct rt1310_intc_softc *sc;
+
+ if (data->type != INTR_MAP_DATA_FDT)
+ return (ENOTSUP);
+
+ daf = (struct intr_map_data_fdt *)data;
+
+ if (daf->ncells != 1 || daf->cells[0] >= INTC_NIRQS)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ *isrcp = &sc->ri_isrcs[daf->cells[0]].ri_isrc;
+ return (0);
+}
+
+static void
+rt1310_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ arm_irq_memory_barrier(0);
+ rt1310_disable_intr(dev, isrc);
+}
+
+static void
+rt1310_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ arm_irq_memory_barrier(0);
+ rt1310_enable_intr(dev, isrc);
+}
+
+static void
+rt1310_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq;
+ struct rt1310_intc_softc *sc;
+
+ arm_irq_memory_barrier(0);
+ sc = intc_softc;
+ irq = ((struct rt1310_irqsrc *)isrc)->ri_irq;
+
+ intc_write_4(sc, RT_INTC_ICCR, 1 << irq);
+}
+
+static int
+rt1310_intr(void *arg)
+{
+ uint32_t irq;
+ struct rt1310_intc_softc *sc = arg;
+
+ irq = ffs(intc_read_4(sc, RT_INTC_IPR)) - 1;
+
+ if (intr_isrc_dispatch(&sc->ri_isrcs[irq].ri_isrc,
+ curthread->td_intr_frame) != 0) {
+ intc_write_4(sc, RT_INTC_ICCR, 1 << irq);
+ device_printf(sc->dev, "Stray irq %u disabled\n", irq);
+ }
+
+ arm_irq_memory_barrier(0);
+
+ return (FILTER_HANDLED);
+}
+
+static int
+rt1310_pic_attach(struct rt1310_intc_softc *sc)
+{
+ struct intr_pic *pic;
+ int error;
+ uint32_t irq;
+ const char *name;
+ intptr_t xref;
+
+ name = device_get_nameunit(sc->dev);
+ for (irq = 0; irq < INTC_NIRQS; irq++) {
+ sc->ri_isrcs[irq].ri_irq = irq;
+
+ error = intr_isrc_register(&sc->ri_isrcs[irq].ri_isrc,
+ sc->dev, 0, "%s,%u", name, irq);
+ if (error != 0)
+ return (error);
+ }
+
+ xref = OF_xref_from_node(ofw_bus_get_node(sc->dev));
+ pic = intr_pic_register(sc->dev, xref);
+ if (pic == NULL)
+ return (ENXIO);
+
+ return (intr_pic_claim_root(sc->dev, xref, rt1310_intr, sc, 0));
+}
+#endif
+
+struct fdt_fixup_entry fdt_fixup_table[] = {
+ { NULL, NULL }
+};
+
+#ifndef INTRNG
+static int
+fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
+ int *pol)
+{
+ if (!fdt_is_compatible(node, "lpc,pic"))
+ return (ENXIO);
+
+ *interrupt = fdt32_to_cpu(intr[0]);
+ *trig = INTR_TRIGGER_CONFORM;
+ *pol = INTR_POLARITY_CONFORM;
+ return (0);
+}
+
+fdt_pic_decode_t fdt_pic_table[] = {
+ &fdt_pic_decode_ic,
+ NULL
+};
+#endif
+
+static device_method_t rt1310_intc_methods[] = {
+ DEVMETHOD(device_probe, rt1310_intc_probe),
+ DEVMETHOD(device_attach, rt1310_intc_attach),
+#ifdef INTRNG
+ DEVMETHOD(pic_disable_intr, rt1310_disable_intr),
+ DEVMETHOD(pic_enable_intr, rt1310_enable_intr),
+ DEVMETHOD(pic_map_intr, rt1310_map_intr),
+ DEVMETHOD(pic_post_filter, rt1310_post_filter),
+ DEVMETHOD(pic_post_ithread, rt1310_post_ithread),
+ DEVMETHOD(pic_pre_ithread, rt1310_pre_ithread),
+#endif
+ { 0, 0 }
+};
+
+static driver_t rt1310_intc_driver = {
+ "pic",
+ rt1310_intc_methods,
+ sizeof(struct rt1310_intc_softc),
+};
+
+static devclass_t rt1310_intc_devclass;
+
+EARLY_DRIVER_MODULE(pic, simplebus, rt1310_intc_driver, rt1310_intc_devclass, 0, 0, BUS_PASS_INTERRUPT);
Index: head/sys/arm/ralink/rt1310_machdep.c
===================================================================
--- head/sys/arm/ralink/rt1310_machdep.c
+++ head/sys/arm/ralink/rt1310_machdep.c
@@ -0,0 +1,176 @@
+/*-
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: FreeBSD: sys/arm/lpc/lpc_machdep.c
+ */
+
+#include "opt_ddb.h"
+#include "opt_platform.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/reboot.h>
+#include <sys/devmap.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <machine/machdep.h>
+#include <machine/platform.h>
+#include <machine/cpu.h>
+
+#include <arm/ralink/rt1310reg.h>
+#include <arm/ralink/rt1310var.h>
+
+#include <dev/fdt/fdt_common.h>
+
+#ifdef EARLY_PRINTF
+early_putc_t *early_putc;
+#endif
+
+
+uint32_t rt1310_master_clock;
+
+vm_offset_t
+platform_lastaddr(void)
+{
+
+ return (devmap_lastaddr());
+}
+
+void
+platform_probe_and_attach(void)
+{
+}
+
+void
+platform_gpio_init(void)
+{
+
+ /*
+ * Set initial values of GPIO output ports
+ */
+}
+
+void
+platform_late_init(void)
+{
+ bootverbose = 1;
+}
+
+/*
+ * Add a single static device mapping.
+ * The values used were taken from the ranges property of the SoC node in the
+ * dts file when this code was converted to arm_devmap_add_entry().
+ */
+int
+platform_devmap_init(void)
+{
+ devmap_add_entry(0x19C00000, 0xE0000);
+ devmap_add_entry(0x1e800000, 0x800000);
+ devmap_add_entry(0x1f000000, 0x400000);
+ return (0);
+}
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+
+ return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+
+ return (0);
+}
+
+void
+cpu_reset(void)
+{
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+
+ bst = fdtbus_bs_tag;
+
+ /* Enable WDT */
+ /* Instant assert of RESETOUT_N with pulse length 1ms */
+ bus_space_map(bst, 0x1e8c0000, 0x20000, 0, &bsh);
+ bus_space_write_4(bst, bsh, 0, 13000);
+ bus_space_write_4(bst, bsh, 8, (1<<3) | (1<<4) | 7);
+ bus_space_unmap(bst, bsh, 0x20000);
+
+ for (;;)
+ continue;
+}
+
+#ifdef RALINK_BOOT_DEBUG
+void bootdebug1(int c);
+void bootdebug1(int c)
+{
+ /* direct put uart physical address */
+ uint8_t* uart_base_addr=(uint8_t*)0x1e840000;
+ *(uart_base_addr) = c;
+}
+
+void bootdebug2(int c);
+void bootdebug2(int c)
+{
+#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
+ /* direct put uart map address at locore-v4.S */
+ uint8_t* uart_base_addr=(uint8_t*)0xce840000;
+ *(uart_base_addr) = c;
+#endif
+}
+
+void bootdebug3(int c);
+void bootdebug3(int c)
+{
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+
+ bst = fdtbus_bs_tag;
+ bus_space_map(bst, 0x1e840000, 0x20000, 0, &bsh);
+ bus_space_write_1(bst, bsh, 0, c);
+ bus_space_unmap(bst, bsh, 0x20000);
+}
+#endif
Index: head/sys/arm/ralink/rt1310_timer.c
===================================================================
--- head/sys/arm/ralink/rt1310_timer.c
+++ head/sys/arm/ralink/rt1310_timer.c
@@ -0,0 +1,341 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org>
+ * Copyright (c) 2015 Hiroki Mori
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/timetc.h>
+#include <sys/timeet.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ralink/rt1310reg.h>
+#include <arm/ralink/rt1310var.h>
+
+struct rt1310_timer_softc {
+ device_t lt_dev;
+ struct eventtimer lt_et;
+ struct resource * lt_res[8];
+ bus_space_tag_t lt_bst0;
+ bus_space_handle_t lt_bsh0;
+ bus_space_tag_t lt_bst1;
+ bus_space_handle_t lt_bsh1;
+ bus_space_tag_t lt_bst2;
+ bus_space_handle_t lt_bsh2;
+ bus_space_tag_t lt_bst3;
+ bus_space_handle_t lt_bsh3;
+ int lt_oneshot;
+ uint32_t lt_period;
+};
+
+static struct resource_spec rt1310_timer_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { SYS_RES_MEMORY, 1, RF_ACTIVE },
+ { SYS_RES_MEMORY, 2, RF_ACTIVE },
+ { SYS_RES_MEMORY, 3, RF_ACTIVE },
+ { SYS_RES_IRQ, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 1, RF_ACTIVE },
+ { SYS_RES_IRQ, 2, RF_ACTIVE },
+ { -1, 0 }
+};
+
+static struct rt1310_timer_softc *timer_softc = NULL;
+static int rt1310_timer_initialized = 0;
+static int rt1310_timer_probe(device_t);
+static int rt1310_timer_attach(device_t);
+static int rt1310_timer_start(struct eventtimer *,
+ sbintime_t first, sbintime_t period);
+static int rt1310_timer_stop(struct eventtimer *et);
+static unsigned rt1310_get_timecount(struct timecounter *);
+static int rt1310_hardclock(void *);
+
+#define timer0_read_4(sc, reg) \
+ bus_space_read_4(sc->lt_bst0, sc->lt_bsh0, reg)
+#define timer0_write_4(sc, reg, val) \
+ bus_space_write_4(sc->lt_bst0, sc->lt_bsh0, reg, val)
+#define timer0_clear(sc) \
+ do { \
+ timer0_write_4(sc, RT_TIMER_LOAD, 0); \
+ timer0_write_4(sc, RT_TIMER_VALUE, 0); \
+ } while(0)
+
+#define timer1_read_4(sc, reg) \
+ bus_space_read_4(sc->lt_bst1, sc->lt_bsh1, reg)
+#define timer1_write_4(sc, reg, val) \
+ bus_space_write_4(sc->lt_bst1, sc->lt_bsh1, reg, val)
+#define timer1_clear(sc) \
+ do { \
+ timer1_write_4(sc, RT_TIMER_LOAD, 0); \
+ timer1_write_4(sc, RT_TIMER_VALUE, 0); \
+ } while(0)
+
+#define timer2_read_4(sc, reg) \
+ bus_space_read_4(sc->lt_bst1, sc->lt_bsh2, reg)
+#define timer2_write_4(sc, reg, val) \
+ bus_space_write_4(sc->lt_bst2, sc->lt_bsh2, reg, val)
+#define timer3_write_4(sc, reg, val) \
+ bus_space_write_4(sc->lt_bst3, sc->lt_bsh3, reg, val)
+
+
+static struct timecounter rt1310_timecounter = {
+ .tc_get_timecount = rt1310_get_timecount,
+ .tc_name = "RT1310ATimer1",
+ .tc_frequency = 0, /* will be filled later */
+ .tc_counter_mask = ~0u,
+ .tc_quality = 1000,
+};
+
+static int
+rt1310_timer_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "rt,timer"))
+ return (ENXIO);
+
+ device_set_desc(dev, "RT1310 timer");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+rt1310_timer_attach(device_t dev)
+{
+ void *intrcookie;
+ struct rt1310_timer_softc *sc = device_get_softc(dev);
+ phandle_t node;
+ uint32_t freq;
+
+ if (timer_softc)
+ return (ENXIO);
+
+ timer_softc = sc;
+
+ if (bus_alloc_resources(dev, rt1310_timer_spec, sc->lt_res)) {
+ device_printf(dev, "could not allocate resources\n");
+ return (ENXIO);
+ }
+
+ sc->lt_bst0 = rman_get_bustag(sc->lt_res[0]);
+ sc->lt_bsh0 = rman_get_bushandle(sc->lt_res[0]);
+ sc->lt_bst1 = rman_get_bustag(sc->lt_res[1]);
+ sc->lt_bsh1 = rman_get_bushandle(sc->lt_res[1]);
+ sc->lt_bst2 = rman_get_bustag(sc->lt_res[2]);
+ sc->lt_bsh2 = rman_get_bushandle(sc->lt_res[2]);
+ sc->lt_bst3 = rman_get_bustag(sc->lt_res[3]);
+ sc->lt_bsh3 = rman_get_bushandle(sc->lt_res[3]);
+
+ /* Timer2 interrupt */
+ if (bus_setup_intr(dev, sc->lt_res[6], INTR_TYPE_CLK,
+ rt1310_hardclock, NULL, sc, &intrcookie)) {
+ device_printf(dev, "could not setup interrupt handler\n");
+ bus_release_resources(dev, rt1310_timer_spec, sc->lt_res);
+ return (ENXIO);
+ }
+
+ /* Enable timer clock */
+/*
+ rt1310_pwr_write(dev, LPC_CLKPWR_TIMCLK_CTRL1,
+ LPC_CLKPWR_TIMCLK_CTRL1_TIMER0 |
+ LPC_CLKPWR_TIMCLK_CTRL1_TIMER1);
+*/
+
+ /* Get PERIPH_CLK encoded in parent bus 'bus-frequency' property */
+
+ node = ofw_bus_get_node(dev);
+ if (OF_getprop(OF_parent(node), "bus-frequency", &freq,
+ sizeof(pcell_t)) <= 0) {
+ bus_release_resources(dev, rt1310_timer_spec, sc->lt_res);
+ bus_teardown_intr(dev, sc->lt_res[2], intrcookie);
+ device_printf(dev, "could not obtain base clock frequency\n");
+ return (ENXIO);
+ }
+
+ freq = fdt32_to_cpu(freq);
+
+ /* Set desired frequency in event timer and timecounter */
+ sc->lt_et.et_frequency = (uint64_t)freq;
+ rt1310_timecounter.tc_frequency = (uint64_t)freq;
+
+ sc->lt_et.et_name = "RT1310ATimer2";
+ sc->lt_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
+ sc->lt_et.et_quality = 1000;
+ sc->lt_et.et_min_period = (0x00000002LLU << 32) / sc->lt_et.et_frequency;
+ sc->lt_et.et_max_period = (0xfffffffeLLU << 32) / sc->lt_et.et_frequency;
+ sc->lt_et.et_start = rt1310_timer_start;
+ sc->lt_et.et_stop = rt1310_timer_stop;
+ sc->lt_et.et_priv = sc;
+
+ et_register(&sc->lt_et);
+ tc_init(&rt1310_timecounter);
+
+ /* Reset and enable timecounter */
+
+ timer0_write_4(sc, RT_TIMER_CONTROL, 0);
+ timer1_write_4(sc, RT_TIMER_CONTROL, 0);
+ timer2_write_4(sc, RT_TIMER_CONTROL, 0);
+ timer3_write_4(sc, RT_TIMER_CONTROL, 0);
+
+ timer1_write_4(sc, RT_TIMER_LOAD, ~0);
+ timer1_write_4(sc, RT_TIMER_VALUE, ~0);
+ timer1_write_4(sc, RT_TIMER_CONTROL,
+ RT_TIMER_CTRL_ENABLE | RT_TIMER_CTRL_PERIODCAL);
+
+ /* DELAY() now can work properly */
+ rt1310_timer_initialized = 1;
+
+ return (0);
+}
+
+static int
+rt1310_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
+{
+ struct rt1310_timer_softc *sc = (struct rt1310_timer_softc *)et->et_priv;
+ uint32_t ticks;
+
+ if (period == 0) {
+ sc->lt_oneshot = 1;
+ sc->lt_period = 0;
+ } else {
+ sc->lt_oneshot = 0;
+ sc->lt_period = ((uint32_t)et->et_frequency * period) >> 32;
+ }
+
+ if (first == 0)
+ ticks = sc->lt_period;
+ else
+ ticks = ((uint32_t)et->et_frequency * first) >> 32;
+
+ /* Reset timer */
+ timer2_write_4(sc, RT_TIMER_CONTROL, 0);
+
+ /* Start timer */
+ timer2_write_4(sc, RT_TIMER_LOAD, ticks);
+ timer2_write_4(sc, RT_TIMER_VALUE, ticks);
+ timer2_write_4(sc, RT_TIMER_CONTROL,
+ RT_TIMER_CTRL_ENABLE | RT_TIMER_CTRL_INTCTL);
+
+ return (0);
+}
+
+static int
+rt1310_timer_stop(struct eventtimer *et)
+{
+ struct rt1310_timer_softc *sc = (struct rt1310_timer_softc *)et->et_priv;
+
+ timer2_write_4(sc, RT_TIMER_CONTROL, 0);
+
+ return (0);
+}
+
+static device_method_t rt1310_timer_methods[] = {
+ DEVMETHOD(device_probe, rt1310_timer_probe),
+ DEVMETHOD(device_attach, rt1310_timer_attach),
+ { 0, 0 }
+};
+
+static driver_t rt1310_timer_driver = {
+ "timer",
+ rt1310_timer_methods,
+ sizeof(struct rt1310_timer_softc),
+};
+
+static devclass_t rt1310_timer_devclass;
+
+EARLY_DRIVER_MODULE(timer, simplebus, rt1310_timer_driver, rt1310_timer_devclass, 0, 0, BUS_PASS_TIMER);
+
+static int
+rt1310_hardclock(void *arg)
+{
+ struct rt1310_timer_softc *sc = (struct rt1310_timer_softc *)arg;
+
+ /* Reset pending interrupt */
+ timer2_write_4(sc, RT_TIMER_CONTROL,
+ timer2_read_4(sc, RT_TIMER_CONTROL) | 0x08);
+ timer2_write_4(sc, RT_TIMER_CONTROL,
+ timer2_read_4(sc, RT_TIMER_CONTROL) & 0x1fb);
+
+ /* Start timer again */
+ if (!sc->lt_oneshot) {
+ timer2_write_4(sc, RT_TIMER_LOAD, sc->lt_period);
+ timer2_write_4(sc, RT_TIMER_VALUE, sc->lt_period);
+ timer2_write_4(sc, RT_TIMER_CONTROL,
+ RT_TIMER_CTRL_ENABLE | RT_TIMER_CTRL_INTCTL);
+ }
+
+ if (sc->lt_et.et_active)
+ sc->lt_et.et_event_cb(&sc->lt_et, sc->lt_et.et_arg);
+
+ return (FILTER_HANDLED);
+}
+
+static unsigned
+rt1310_get_timecount(struct timecounter *tc)
+{
+ return ~timer1_read_4(timer_softc, RT_TIMER_VALUE);
+}
+
+void
+DELAY(int usec)
+{
+ uint32_t counter;
+ uint32_t first, last;
+ int val = (rt1310_timecounter.tc_frequency / 1000000 + 1) * usec;
+
+ /* Timer is not initialized yet */
+ if (!rt1310_timer_initialized) {
+ for (; usec > 0; usec--)
+ for (counter = 100; counter > 0; counter--)
+ ;
+ return;
+ }
+
+ first = rt1310_get_timecount(&rt1310_timecounter);
+ while (val > 0) {
+ last = rt1310_get_timecount(&rt1310_timecounter);
+ if (last < first) {
+ /* Timer rolled over */
+ last = first;
+ }
+
+ val -= (last - first);
+ first = last;
+ }
+}
Index: head/sys/arm/ralink/rt1310reg.h
===================================================================
--- head/sys/arm/ralink/rt1310reg.h
+++ head/sys/arm/ralink/rt1310reg.h
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org>
+ * Copyright (c) 2015 Hiroki Mori
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM_RALINK_RT1310REG_H
+#define _ARM_RALINK_RT1310REG_H
+
+/*
+ * Interrupt controller
+ */
+
+#define RT_INTC_SCR0 0x00
+#define RT_INTC_SVR0 0x80
+#define RT_INTC_ISR 0x104
+#define RT_INTC_IPR 0x108
+#define RT_INTC_IMR 0x10c
+#define RT_INTC_IECR 0x114
+#define RT_INTC_ICCR 0x118
+
+#define RT_INTC_TRIG_LOW_LVL (0)
+#define RT_INTC_TRIG_HIGH_LVL (1)
+#define RT_INTC_TRIG_NEG_EDGE (2)
+#define RT_INTC_TRIG_POS_EDGE (3)
+
+#define RT_INTC_TRIG_SHIF 6
+
+/*
+ * Timer 0|1|2|3.
+ */
+
+#define RT_TIMER_LOAD 0x00
+#define RT_TIMER_VALUE 0x04
+#define RT_TIMER_CONTROL 0x08
+
+#define RT_TIMER_CTRL_INTCTL (1 << 1)
+#define RT_TIMER_CTRL_INTCLR (1 << 2)
+#define RT_TIMER_CTRL_INTMASK (1 << 3)
+#define RT_TIMER_CTRL_DIV16 (3 << 4)
+#define RT_TIMER_CTRL_DIV256 (7 << 4)
+#define RT_TIMER_CTRL_PERIODCAL (1 << 7)
+#define RT_TIMER_CTRL_ENABLE (1 << 8)
+
+#define RT_TIMER_INTERVAL (5000*150)
+
+/*
+ * GPIO
+ */
+
+#define RT_GPIO_PORTA (0)
+#define RT_GPIO_PORTB (1)
+
+#define RT_GPIO_OFF_PADR (0x0)
+#define RT_GPIO_OFF_PADIR (0x4)
+#define RT_GPIO_OFF_PBDR (0x8)
+#define RT_GPIO_OFF_PBDIR (0xC)
+
+#endif /* _ARM_RALINK_RT1310REG_H */
Index: head/sys/arm/ralink/rt1310var.h
===================================================================
--- head/sys/arm/ralink/rt1310var.h
+++ head/sys/arm/ralink/rt1310var.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM_RT_RTVAR_H
+#define _ARM_RT_RTVAR_H
+
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+
+/* Clocking and power control */
+uint32_t lpc_pwr_read(device_t, int);
+void lpc_pwr_write(device_t, int, uint32_t);
+
+/* GPIO */
+void rt1310_gpio_init(void);
+int rt1310_gpio_set_flags(device_t, int, int);
+int rt1310_gpio_set_state(device_t, int, int);
+int rt1310_gpio_get_state(device_t, int, int *);
+
+/* DMA */
+struct lpc_dmac_channel_config
+{
+ int ldc_fcntl;
+ int ldc_src_periph;
+ int ldc_src_width;
+ int ldc_src_incr;
+ int ldc_src_burst;
+ int ldc_dst_periph;
+ int ldc_dst_width;
+ int ldc_dst_incr;
+ int ldc_dst_burst;
+ void (*ldc_success_handler)(void *);
+ void (*ldc_error_handler)(void *);
+ void * ldc_handler_arg;
+};
+
+int lpc_dmac_config_channel(device_t, int, struct lpc_dmac_channel_config *);
+int lpc_dmac_setup_transfer(device_t, int, bus_addr_t, bus_addr_t, bus_size_t, int);
+int lpc_dmac_enable_channel(device_t, int);
+int lpc_dmac_disable_channel(device_t, int);
+int lpc_dmac_start_burst(device_t, int);
+
+extern uint32_t rt1310_master_clock;
+
+#endif /* _ARM_RT_RTVAR_H */
Index: head/sys/boot/fdt/dts/arm/rt1310a.dtsi
===================================================================
--- head/sys/boot/fdt/dts/arm/rt1310a.dtsi
+++ head/sys/boot/fdt/dts/arm/rt1310a.dtsi
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2011 Jakub Klama <jceel@FreeBSD.org>
+ * Copyright (c) 2015 Hiroki Mori
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Ralink RT1310A Device Tree Source.
+ *
+ * $FreeBSD$
+ */
+
+/ {
+ compatible = "ralink,rt1310a-soc";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ serial0 = &serial0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "ARM,926EJ-S";
+ reg = <0x0>;
+ d-cache-line-size = <32>; // 32 bytes
+ i-cache-line-size = <32>; // 32 bytes
+ d-cache-size = <0x4000>; // L1, 16K
+ i-cache-size = <0x4000>; // L1, 16K
+ timebase-frequency = <0>;
+ bus-frequency = <0>;
+ clock-frequency = <0>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x40000000 0x1000000>; // 16M at 0x40000000
+ };
+
+ localbus@1f000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x0 0x1f000000 0x400000>;
+ };
+
+ ahb@19C00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x0 0x19C00000 0xE0000>;
+ bus-frequency = <13000000>;
+
+ PIC: pic@40000 {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x40000 0x20000>;
+ compatible = "rt,pic";
+ };
+
+ fvmdio@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fv,mdio";
+ reg = <0x80000 0x20000>;
+ };
+
+ enet0:fv_mac0@80000 {
+ compatible = "fv,ethernet";
+ reg = <0x80000 0x20000>;
+ interrupts = <7>;
+ interrupt-parent = <&PIC>;
+
+ };
+
+ enet1:fv_mac1@A0000 {
+ compatible = "fv,ethernet";
+ reg = <0xA0000 0x20000>;
+ interrupts = <8>;
+ interrupt-parent = <&PIC>;
+ };
+
+ };
+
+ apb@1E800000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x0 0x1E800000 0x800000>;
+ bus-frequency = <75000000>;
+
+ timer@000000 {
+ compatible = "rt,timer";
+ reg = <0x0 0x10
+ 0x10 0x10
+ 0x20 0x10
+ 0x30 0x10>;
+ interrupts = <3 4 5>;
+ interrupt-parent = <&PIC>;
+ };
+
+ rtc@20000 {
+ compatible = "rt,rtc";
+ interrupts = <6>;
+ reg = <0x20000 0x20000>;
+ };
+
+ serial0: serial@40000 {
+ compatible = "ns16550";
+ reg = <0x40000 0x20000>;
+ interrupts = <1>;
+ reg-shift = <2>;
+ clock-frequency = <6758400>;
+ current-speed = <38400>;
+ interrupt-parent = <&PIC>;
+ };
+
+ gpio0: gpio@A0000 {
+ compatible = "ralink,rt1310-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <8>;
+ reg = <0xA0000 0x20000>;
+ };
+ };
+
+
+/*
+ chosen {
+ stdin = "serial0";
+ stdout = "serial0";
+ };
+*/
+};
+
Index: head/sys/boot/fdt/dts/arm/wzr2-g300n.dts
===================================================================
--- head/sys/boot/fdt/dts/arm/wzr2-g300n.dts
+++ head/sys/boot/fdt/dts/arm/wzr2-g300n.dts
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2015 Hiroki Mori
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Buffalo WZR2-G300N Device Tree Source.
+ *
+ * $FreeBSD$
+ */
+
+/dts-v1/;
+
+#include "rt1310a.dtsi"
+
+/ {
+ compatible = "WZR2-G300N", "ralink,rt1310a-soc";
+ model = "WZR2-G300N";
+
+ flash@1f000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x1f000000 0x400000>; // 4M at 0x1f000000
+
+ partition@0 {
+ reg = <0x00000000 0x0000e000>;
+ label = "uboot";
+ };
+ partition@1 {
+ reg = <0x0000e000 0x00002000>;
+ label = "uboot_env";
+ };
+ partition@2 {
+ reg = <0x00010000 0x000f0000>;
+ label = "kernel";
+ };
+ partition@3 {
+ reg = <0x00100000 0x002d0000>;
+ label = "rootfs";
+ };
+ partition@4 {
+ reg = <0x003d0000 0x00010000>;
+ label = "config";
+ };
+ partition@5 {
+ reg = <0x00010000 0x003c0000>;
+ label = "upgrade";
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "status";
+ gpios = <&gpio0 4 0>;
+ };
+ };
+
+ ip17x@0 {
+ compatible = "icplus,ip17x";
+ mii-poll = <0>;
+ };
+
+};
+
+&enet0 {
+ local-mac-address = [ 00 1a f1 01 1f 23 ];
+};
+
+&enet1 {
+ local-mac-address = [ 00 1a f1 01 1f 24 ];
+};

File Metadata

Mime Type
text/plain
Expires
Sun, Feb 23, 12:28 PM (11 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16791188
Default Alt Text
D7238.diff (115 KB)

Event Timeline