summaryrefslogtreecommitdiffstats
path: root/sys/mips/idt
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2008-07-06 21:09:29 +0000
committerimp <imp@FreeBSD.org>2008-07-06 21:09:29 +0000
commit63f02baf0e5ce3db18056a08a90ca971fb12de6d (patch)
tree31d944679243fdf0be594fcd6d48f9e779df37f1 /sys/mips/idt
parentbdbada7ab202ec9b0f096811f6fbe2eda04cc5c9 (diff)
downloadFreeBSD-src-63f02baf0e5ce3db18056a08a90ca971fb12de6d.zip
FreeBSD-src-63f02baf0e5ce3db18056a08a90ca971fb12de6d.tar.gz
As discussed on IRC and at BSDcan, move the mips32/* directories up a
level. The distinction was artificial. Some more movement around the deck charis is likely depending on the fallout from this one. Paths were corrected after the svn mv. Hope that's OK.
Diffstat (limited to 'sys/mips/idt')
-rw-r--r--sys/mips/idt/files.idt8
-rw-r--r--sys/mips/idt/idt_machdep.c188
-rw-r--r--sys/mips/idt/idtpci.c565
-rw-r--r--sys/mips/idt/idtreg.h153
-rw-r--r--sys/mips/idt/if_kr.c1615
-rw-r--r--sys/mips/idt/if_krreg.h284
-rw-r--r--sys/mips/idt/obio.c514
-rw-r--r--sys/mips/idt/obiovar.h67
-rw-r--r--sys/mips/idt/std.idt5
-rw-r--r--sys/mips/idt/uart_bus_rc32434.c100
-rw-r--r--sys/mips/idt/uart_cpu_rc32434.c85
11 files changed, 3584 insertions, 0 deletions
diff --git a/sys/mips/idt/files.idt b/sys/mips/idt/files.idt
new file mode 100644
index 0000000..370ccf9
--- /dev/null
+++ b/sys/mips/idt/files.idt
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+mips/idt/idt_machdep.c standard
+mips/idt/idtpci.c optional pci
+mips/idt/if_kr.c optional kr
+mips/idt/obio.c standard
+mips/idt/uart_cpu_rc32434.c optional uart
+mips/idt/uart_bus_rc32434.c optional uart
diff --git a/sys/mips/idt/idt_machdep.c b/sys/mips/idt/idt_machdep.c
new file mode 100644
index 0000000..040c3f9
--- /dev/null
+++ b/sys/mips/idt/idt_machdep.c
@@ -0,0 +1,188 @@
+/*-
+ * Copyright (C) 2007 by Oleksandr Tymoshenko. 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 ``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 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 SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: $
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/cons.h>
+#include <sys/exec.h>
+#include <sys/ucontext.h>
+#include <sys/proc.h>
+#include <sys/kdb.h>
+#include <sys/ptrace.h>
+#include <sys/reboot.h>
+#include <sys/signalvar.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/user.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <machine/cache.h>
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cpuinfo.h>
+#include <machine/cpufunc.h>
+#include <machine/cpuregs.h>
+#include <machine/hwfunc.h>
+#include <machine/intr_machdep.h>
+#include <machine/locore.h>
+#include <machine/md_var.h>
+#include <machine/pte.h>
+#include <machine/sigframe.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+extern int *edata;
+extern int *end;
+
+void
+platform_halt(void)
+{
+
+}
+
+
+void
+platform_identify(void)
+{
+
+}
+
+void
+platform_reset(void)
+{
+ volatile unsigned int * p = (void *)0xb8008000;
+ /*
+ * TODO: we should take care of TLB stuff here. Otherwise
+ * board does not boots properly next time
+ */
+
+ /* Write 0x8000_0001 to the Reset register */
+ *p = 0x80000001;
+
+ __asm __volatile("li $25, 0xbfc00000");
+ __asm __volatile("j $25");
+}
+
+void
+platform_trap_enter(void)
+{
+
+}
+
+void
+platform_trap_exit(void)
+{
+
+}
+
+void
+platform_start(__register_t a0, __register_t a1,
+ __register_t a2 __unused, __register_t a3 __unused)
+{
+ uint64_t platform_counter_freq;
+ vm_offset_t kernend;
+ int argc = a0;
+ char **argv = (char **)a1;
+ int i, mem;
+
+
+ /* clear the BSS and SBSS segments */
+ kernend = round_page((vm_offset_t)&end);
+ memset(&edata, 0, kernend - (vm_offset_t)(&edata));
+
+ /*
+ * Looking for mem=XXM argument
+ */
+ mem = 0; /* Just something to start with */
+ for (i=0; i < argc; i++) {
+ if (strncmp(argv[i], "mem=", 4) == 0) {
+ mem = strtol(argv[i] + 4, NULL, 0);
+ break;
+ }
+ }
+
+ bootverbose = 1;
+ if (mem > 0)
+ realmem = btoc(mem << 20);
+ else
+ realmem = btoc(32 << 20);
+
+ for (i = 0; i < 10; i++) {
+ phys_avail[i] = 0;
+ }
+
+ /* phys_avail regions are in bytes */
+ phys_avail[0] = MIPS_KSEG0_TO_PHYS((vm_offset_t)&end);
+ phys_avail[1] = ctob(realmem);
+
+ physmem = realmem;
+
+ /*
+ * ns8250 uart code uses DELAY so ticker should be inititalized
+ * before cninit. And tick_init_params refers to hz, so * init_param1
+ * should be called first.
+ */
+ init_param1();
+ /* TODO: parse argc,argv */
+ platform_counter_freq = 330000000UL;
+ mips_timer_init_params(platform_counter_freq, 1);
+ cninit();
+ /* Panic here, after cninit */
+ if (mem == 0)
+ panic("No mem=XX parameter in arguments");
+
+ printf("cmd line: ");
+ for (i=0; i < argc; i++)
+ printf("%s ", argv[i]);
+ printf("\n");
+
+ init_param2(physmem);
+ mips_cpu_init();
+ pmap_bootstrap();
+ mips_proc0_init();
+ mutex_init();
+#ifdef DDB
+ kdb_init();
+#endif
+}
diff --git a/sys/mips/idt/idtpci.c b/sys/mips/idt/idtpci.c
new file mode 100644
index 0000000..7e4414f
--- /dev/null
+++ b/sys/mips/idt/idtpci.c
@@ -0,0 +1,565 @@
+/* $NetBSD: idtpci.c,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2007 David Young.
+ * Copyright (c) 2007 Oleskandr Tymoshenko. 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE 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 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
+ * 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.
+ */
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Written by Garrett D'Amore for Itronix Inc.
+ *
+ * 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. The name of Itronix Inc. may not be used to endorse
+ * or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/interrupt.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/pmap.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include <dev/pci/pcib_private.h>
+#include "pcib_if.h"
+
+#include <mips/mips32/idt/idtreg.h>
+
+#ifdef IDTPCI_DEBUG
+int idtpci_debug = 1;
+#define IDTPCI_DPRINTF(__fmt, ...) \
+do { \
+ if (idtpci_debug) \
+ printf((__fmt), __VA_ARGS__); \
+} while (/*CONSTCOND*/0)
+#else /* !IDTPCI_DEBUG */
+#define IDTPCI_DPRINTF(__fmt, ...) do { } while (/*CONSTCOND*/0)
+#endif /* IDTPCI_DEBUG */
+
+#define IDTPCI_TAG_BUS_MASK 0x007f0000
+#define IDTPCI_TAG_DEVICE_MASK 0x00007800
+#define IDTPCI_TAG_FUNCTION_MASK 0x00000300
+#define IDTPCI_TAG_REGISTER_MASK 0x0000007c
+
+#define IDTPCI_MAX_DEVICE
+
+#define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(IDT_BASE_PCI + (o)))
+#define REG_WRITE(o,v) (REG_READ(o)) = (v)
+
+unsigned int korina_fixup[24] = {
+ 0x00000157, 0x00000000, 0x00003c04, 0x00000008, 0x18800001, 0x18000001,
+ 0x48000008, 0x00000000, 0x00000000, 0x00000000, 0x011d0214, 0x00000000,
+ 0x00000000, 0x00000000, 0x38080101, 0x00008080, 0x00000d6e, 0x00000000,
+ 0x00000051, 0x00000000, 0x00000055, 0x18000000, 0x00000000, 0x00000000
+};
+
+struct idtpci_softc {
+ device_t sc_dev;
+
+ int sc_busno;
+ struct rman sc_mem_rman[2];
+ struct rman sc_io_rman[2];
+ struct rman sc_irq_rman;
+ uint32_t sc_mem;
+ uint32_t sc_io;
+};
+
+static uint32_t
+idtpci_make_addr(int bus, int slot, int func, int reg)
+{
+
+ return 0x80000000 | (bus << 16) | (slot << 11) | (func << 8) | reg;
+}
+
+static int
+idtpci_probe(device_t dev)
+{
+
+ return (0);
+}
+
+static int
+idtpci_attach(device_t dev)
+{
+ int busno = 0;
+ struct idtpci_softc *sc = device_get_softc(dev);
+ unsigned int pci_data, force_endianess = 0;
+ int i;
+ bus_addr_t addr;
+
+ sc->sc_dev = dev;
+ sc->sc_busno = busno;
+
+ sc->sc_io = 0;
+ sc->sc_mem = 0;
+
+ /* TODO: Check for host mode */
+
+ /* Enabled PCI, IG mode, EAP mode */
+ REG_WRITE(IDT_PCI_CNTL, IDT_PCI_CNTL_IGM | IDT_PCI_CNTL_EAP |
+ IDT_PCI_CNTL_EN);
+ /* Wait while "Reset in progress bit" set */
+ while(1) {
+ pci_data = REG_READ(IDT_PCI_STATUS);
+ if((pci_data & IDT_PCI_STATUS_RIP) == 0)
+ break;
+ }
+
+ /* Reset status register */
+ REG_WRITE(IDT_PCI_STATUS, 0);
+ /* Mask interrupts related to status register */
+ REG_WRITE(IDT_PCI_STATUS_MASK, 0xffffffff);
+
+ /* Disable PCI decoupled access */
+ REG_WRITE(IDT_PCI_DAC, 0);
+ /* Zero status and mask DA interrupts */
+ REG_WRITE(IDT_PCI_DAS, 0);
+ REG_WRITE(IDT_PCI_DASM, 0x7f);
+
+ /* Init PCI messaging unit */
+ /* Disable messaging interrupts */
+ REG_WRITE(IDT_PCI_IIC, 0);
+ REG_WRITE(IDT_PCI_IIM, 0xffffffff);
+ REG_WRITE(IDT_PCI_OIC, 0);
+ REG_WRITE(IDT_PCI_OIM, 0);
+
+#ifdef __MIPSEB__
+ force_endianess = IDT_PCI_LBA_FE;
+#endif
+
+ /* LBA0 -- memory window */
+ REG_WRITE(IDT_PCI_LBA0, IDT_PCIMEM0_BASE);
+ REG_WRITE(IDT_PCI_LBA0_MAP, IDT_PCIMEM0_BASE);
+ REG_WRITE(IDT_PCI_LBA0_CNTL, IDT_PCI_LBA_SIZE_16MB | force_endianess);
+ pci_data = REG_READ(IDT_PCI_LBA0_CNTL);
+
+ /* LBA1 -- memory window */
+ REG_WRITE(IDT_PCI_LBA1, IDT_PCIMEM1_BASE);
+ REG_WRITE(IDT_PCI_LBA1_MAP, IDT_PCIMEM1_BASE);
+ REG_WRITE(IDT_PCI_LBA1_CNTL, IDT_PCI_LBA_SIZE_256MB | force_endianess);
+ pci_data = REG_READ(IDT_PCI_LBA1_CNTL);
+
+ /* LBA2 -- IO window */
+ REG_WRITE(IDT_PCI_LBA2, IDT_PCIMEM2_BASE);
+ REG_WRITE(IDT_PCI_LBA2_MAP, IDT_PCIMEM2_BASE);
+ REG_WRITE(IDT_PCI_LBA2_CNTL, IDT_PCI_LBA_SIZE_4MB | IDT_PCI_LBA_MSI |
+ force_endianess);
+ pci_data = REG_READ(IDT_PCI_LBA2_CNTL);
+
+ /* LBA3 -- IO window */
+ REG_WRITE(IDT_PCI_LBA3, IDT_PCIMEM3_BASE);
+ REG_WRITE(IDT_PCI_LBA3_MAP, IDT_PCIMEM3_BASE);
+ REG_WRITE(IDT_PCI_LBA3_CNTL, IDT_PCI_LBA_SIZE_1MB | IDT_PCI_LBA_MSI |
+ force_endianess);
+ pci_data = REG_READ(IDT_PCI_LBA3_CNTL);
+
+
+ pci_data = REG_READ(IDT_PCI_CNTL) & ~IDT_PCI_CNTL_TNR;
+ REG_WRITE(IDT_PCI_CNTL, pci_data);
+ pci_data = REG_READ(IDT_PCI_CNTL);
+
+ /* Rewrite Target Control register with default values */
+ REG_WRITE(IDT_PCI_TC, (IDT_PCI_TC_DTIMER << 8) | IDT_PCI_TC_RTIMER);
+
+ /* Perform Korina fixup */
+ addr = idtpci_make_addr(0, 0, 0, 4);
+ for (i = 0; i < 24; i++) {
+
+ REG_WRITE(IDT_PCI_CFG_ADDR, addr);
+ REG_WRITE(IDT_PCI_CFG_DATA, korina_fixup[i]);
+ __asm__ volatile ("sync");
+
+ REG_WRITE(IDT_PCI_CFG_ADDR, 0);
+ REG_WRITE(IDT_PCI_CFG_DATA, 0);
+ addr += 4;
+ }
+
+ /* Use KSEG1 to access IO ports for it is uncached */
+ sc->sc_io = 0;
+ sc->sc_io_rman[0].rm_type = RMAN_ARRAY;
+ sc->sc_io_rman[0].rm_descr = "IDTPCI I/O Ports window 1";
+ if (rman_init(&sc->sc_io_rman[0]) != 0 ||
+ rman_manage_region(&sc->sc_io_rman[0],
+ IDT_PCIMEM2_BASE, IDT_PCIMEM2_BASE + IDT_PCIMEM2_SIZE - 1) != 0) {
+ panic("idtpci_attach: failed to set up I/O rman");
+ }
+
+ sc->sc_io_rman[1].rm_type = RMAN_ARRAY;
+ sc->sc_io_rman[1].rm_descr = "IDTPCI I/O Ports window 2";
+ if (rman_init(&sc->sc_io_rman[1]) != 0 ||
+ rman_manage_region(&sc->sc_io_rman[1],
+ IDT_PCIMEM3_BASE, IDT_PCIMEM3_BASE + IDT_PCIMEM3_SIZE - 1) != 0) {
+ panic("idtpci_attach: failed to set up I/O rman");
+ }
+
+ /* Use KSEG1 to access PCI memory for it is uncached */
+ sc->sc_mem = 0;
+ sc->sc_mem_rman[0].rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman[0].rm_descr = "IDTPCI PCI Memory window 1";
+ if (rman_init(&sc->sc_mem_rman[0]) != 0 ||
+ rman_manage_region(&sc->sc_mem_rman[0],
+ IDT_PCIMEM0_BASE, IDT_PCIMEM0_BASE + IDT_PCIMEM0_SIZE) != 0) {
+ panic("idtpci_attach: failed to set up memory rman");
+ }
+
+ sc->sc_mem_rman[1].rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman[1].rm_descr = "IDTPCI PCI Memory window 2";
+ if (rman_init(&sc->sc_mem_rman[1]) != 0 ||
+ rman_manage_region(&sc->sc_mem_rman[1],
+ IDT_PCIMEM1_BASE, IDT_PCIMEM1_BASE + IDT_PCIMEM1_SIZE) != 0) {
+ panic("idtpci_attach: failed to set up memory rman");
+ }
+
+ sc->sc_irq_rman.rm_type = RMAN_ARRAY;
+ sc->sc_irq_rman.rm_descr = "IDTPCI PCI IRQs";
+ if (rman_init(&sc->sc_irq_rman) != 0 ||
+ rman_manage_region(&sc->sc_irq_rman, PCI_IRQ_BASE,
+ PCI_IRQ_END) != 0)
+ panic("idtpci_attach: failed to set up IRQ rman");
+
+ device_add_child(dev, "pci", busno);
+ return (bus_generic_attach(dev));
+}
+
+static int
+idtpci_maxslots(device_t dev)
+{
+
+ return (PCI_SLOTMAX);
+}
+
+static uint32_t
+idtpci_read_config(device_t dev, int bus, int slot, int func, int reg,
+ int bytes)
+{
+ uint32_t data;
+ uint32_t shift, mask;
+ bus_addr_t addr;
+
+ IDTPCI_DPRINTF("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__,
+ bus, slot, func, reg, bytes);
+
+ addr = idtpci_make_addr(bus, slot, func, reg);
+
+ REG_WRITE(IDT_PCI_CFG_ADDR, addr);
+ data = REG_READ(IDT_PCI_CFG_DATA);
+
+ switch (reg % 4) {
+ case 3:
+ shift = 24;
+ break;
+ case 2:
+ shift = 16;
+ break;
+ case 1:
+ shift = 8;
+ break;
+ default:
+ shift = 0;
+ break;
+ }
+
+ switch (bytes) {
+ case 1:
+ mask = 0xff;
+ data = (data >> shift) & mask;
+ break;
+ case 2:
+ mask = 0xffff;
+ if (reg % 4 == 0)
+ data = data & mask;
+ else
+ data = (data >> 16) & mask;
+ break;
+ case 4:
+ break;
+ default:
+ panic("%s: wrong bytes count", __func__);
+ break;
+ }
+
+ __asm__ volatile ("sync");
+ IDTPCI_DPRINTF("%s: read 0x%x\n", __func__, data);
+
+ return (data);
+}
+
+static void
+idtpci_write_config(device_t dev, int bus, int slot, int func, int reg,
+ uint32_t data, int bytes)
+{
+ bus_addr_t addr;
+ uint32_t reg_data;
+ uint32_t shift, mask;
+
+ IDTPCI_DPRINTF("%s: tag (%x, %x, %x) reg %d(%d) data %08x\n", __func__,
+ bus, slot, func, reg, bytes, data);
+
+ if (bytes != 4) {
+ reg_data = idtpci_read_config(dev, bus, slot, func, reg, 4);
+
+ switch (reg % 4) {
+ case 3:
+ shift = 24;
+ break;
+ case 2:
+ shift = 16;
+ break;
+ case 1:
+ shift = 8;
+ break;
+ default:
+ shift = 0;
+ break;
+ }
+
+ switch (bytes) {
+ case 1:
+ mask = 0xff;
+ data = (reg_data & ~ (mask << shift)) | (data << shift);
+ break;
+ case 2:
+ mask = 0xffff;
+ if (reg % 4 == 0)
+ data = (reg_data & ~mask) | data;
+ else
+ data = (reg_data & ~ (mask << shift)) |
+ (data << shift);
+ break;
+ case 4:
+ break;
+ default:
+ panic("%s: wrong bytes count", __func__);
+ break;
+ }
+ }
+
+ addr = idtpci_make_addr(bus, slot, func, reg);
+
+
+ REG_WRITE(IDT_PCI_CFG_ADDR, addr);
+ REG_WRITE(IDT_PCI_CFG_DATA, data);
+ __asm__ volatile ("sync");
+
+ REG_WRITE(IDT_PCI_CFG_ADDR, 0);
+ REG_WRITE(IDT_PCI_CFG_DATA, 0);
+}
+
+static int
+idtpci_route_interrupt(device_t pcib, device_t device, int pin)
+{
+ static int idt_pci_table[2][12] =
+ {
+ { 0, 0, 2, 3, 2, 3, 0, 0, 0, 0, 0, 1 },
+ { 0, 0, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3 }
+ };
+ int dev, bus, irq;
+
+ dev = pci_get_slot(device);
+ bus = pci_get_bus(device);
+ if (bootverbose)
+ device_printf(pcib, "routing pin %d for %s\n", pin,
+ device_get_nameunit(device));
+ if (bus >= 0 && bus <= 1 &&
+ dev >= 0 && dev <= 11) {
+ irq = IP_IRQ(6, idt_pci_table[bus][dev] + 4);
+ if (bootverbose)
+ printf("idtpci: %d/%d/%d -> IRQ%d\n",
+ pci_get_bus(device), dev, pci_get_function(device),
+ irq);
+ return (irq);
+ } else
+ printf("idtpci: no mapping for %d/%d/%d\n",
+ pci_get_bus(device), dev, pci_get_function(device));
+
+ return (-1);
+}
+
+static int
+idtpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct idtpci_softc *sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_DOMAIN:
+ *result = 0;
+ return (0);
+ case PCIB_IVAR_BUS:
+ *result = sc->sc_busno;
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+static int
+idtpci_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
+{
+ struct idtpci_softc * sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ sc->sc_busno = result;
+ return (0);
+ }
+ return (ENOENT);
+}
+
+static struct resource *
+idtpci_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+
+ struct idtpci_softc *sc = device_get_softc(bus);
+ struct resource *rv = NULL;
+ struct rman *rm1, *rm2;
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm1 = &sc->sc_irq_rman;
+ rm2 = NULL;
+ break;
+ case SYS_RES_MEMORY:
+ rm1 = &sc->sc_mem_rman[0];
+ rm2 = &sc->sc_mem_rman[1];
+ break;
+ case SYS_RES_IOPORT:
+ rm1 = &sc->sc_io_rman[0];
+ rm2 = &sc->sc_io_rman[1];
+ break;
+ default:
+ return (NULL);
+ }
+
+ rv = rman_reserve_resource(rm1, start, end, count, flags, child);
+
+ /* Try second window if it exists */
+ if ((rv == NULL) && (rm2 != NULL))
+ rv = rman_reserve_resource(rm2, start, end, count, flags,
+ child);
+
+ if (rv == NULL)
+ return (NULL);
+
+ rman_set_rid(rv, *rid);
+
+ if (flags & RF_ACTIVE) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ }
+
+ return (rv);
+}
+
+static int
+idtpci_teardown_intr(device_t dev, device_t child, struct resource *res,
+ void *cookie)
+{
+
+ return (intr_event_remove_handler(cookie));
+}
+
+static device_method_t idtpci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, idtpci_probe),
+ DEVMETHOD(device_attach, idtpci_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, idtpci_read_ivar),
+ DEVMETHOD(bus_write_ivar, idtpci_write_ivar),
+ DEVMETHOD(bus_alloc_resource, idtpci_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, idtpci_teardown_intr),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, idtpci_maxslots),
+ DEVMETHOD(pcib_read_config, idtpci_read_config),
+ DEVMETHOD(pcib_write_config, idtpci_write_config),
+ DEVMETHOD(pcib_route_interrupt, idtpci_route_interrupt),
+
+ {0, 0}
+};
+
+static driver_t idtpci_driver = {
+ "pcib",
+ idtpci_methods,
+ sizeof(struct idtpci_softc),
+};
+
+static devclass_t idtpci_devclass;
+
+DRIVER_MODULE(idtpci, obio, idtpci_driver, idtpci_devclass, 0, 0);
diff --git a/sys/mips/idt/idtreg.h b/sys/mips/idt/idtreg.h
new file mode 100644
index 0000000..3a088e7
--- /dev/null
+++ b/sys/mips/idt/idtreg.h
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (C) 2007 by Oleksandr Tymoshenko. 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 ``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 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 SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+#ifndef __IDTREG_H__
+#define __IDTREG_H__
+
+/* Interrupt controller */
+#define IDT_BASE_ICU 0x18038000
+#define ICU_IPEND2 0x00
+#define ICU_ITEST2 0x04
+#define ICU_IMASK2 0x08
+#define ICU_IPEND3 0x0C
+#define ICU_ITEST3 0x10
+#define ICU_IMASK3 0x14
+#define ICU_IPEND4 0x18
+#define ICU_ITEST4 0x1c
+#define ICU_IMASK4 0x20
+#define ICU_IPEND5 0x24
+#define ICU_ITEST5 0x28
+#define ICU_IMASK5 0x2c
+#define ICU_IPEND6 0x30
+#define ICU_ITEST6 0x34
+#define ICU_IMASK6 0x38
+#define ICU_NMIPS 0x3c
+
+#define IDT_BASE_GPIO 0x18050000
+#define GPIO_FUNC 0x00
+#define GPIO_CFG 0x04
+#define GPIO_DATA 0x08
+#define GPIO_ILEVEL 0x0C
+#define GPIO_ISTAT 0x10
+#define GPIO_NMIEN 0x14
+
+#define IDT_BASE_UART0 0x18058000
+
+/* PCI controller */
+#define IDT_BASE_PCI 0x18080000
+#define IDT_PCI_CNTL 0x00
+#define IDT_PCI_CNTL_EN 0x001
+#define IDT_PCI_CNTL_TNR 0x002
+#define IDT_PCI_CNTL_SCE 0x004
+#define IDT_PCI_CNTL_IEN 0x008
+#define IDT_PCI_CNTL_AAA 0x010
+#define IDT_PCI_CNTL_EAP 0x020
+#define IDT_PCI_CNTL_IGM 0x200
+#define IDT_PCI_STATUS 0x04
+#define IDT_PCI_STATUS_RIP 0x20000
+#define IDT_PCI_STATUS_MASK 0x08
+#define IDT_PCI_CFG_ADDR 0x0C
+#define IDT_PCI_CFG_DATA 0x10
+/* LBA stuff */
+#define IDT_PCI_LBA0 0x14
+#define IDT_PCI_LBA0_CNTL 0x18
+#define IDT_PCI_LBA_MSI 0x01
+#define IDT_PCI_LBA_SIZE_1MB (0x14 << 2)
+#define IDT_PCI_LBA_SIZE_2MB (0x15 << 2)
+#define IDT_PCI_LBA_SIZE_4MB (0x16 << 2)
+#define IDT_PCI_LBA_SIZE_8MB (0x17 << 2)
+#define IDT_PCI_LBA_SIZE_16MB (0x18 << 2)
+#define IDT_PCI_LBA_SIZE_32MB (0x19 << 2)
+#define IDT_PCI_LBA_SIZE_64MB (0x1A << 2)
+#define IDT_PCI_LBA_SIZE_128MB (0x1B << 2)
+#define IDT_PCI_LBA_SIZE_256MB (0x1C << 2)
+#define IDT_PCI_LBA_FE 0x80
+#define IDT_PCI_LBA_RT 0x100
+#define IDT_PCI_LBA0_MAP 0x1C
+#define IDT_PCI_LBA1 0x20
+#define IDT_PCI_LBA1_CNTL 0x24
+#define IDT_PCI_LBA1_MAP 0x28
+#define IDT_PCI_LBA2 0x2C
+#define IDT_PCI_LBA2_CNTL 0x30
+#define IDT_PCI_LBA2_MAP 0x34
+#define IDT_PCI_LBA3 0x38
+#define IDT_PCI_LBA3_CNTL 0x3C
+#define IDT_PCI_LBA3_MAP 0x40
+/* decoupled registers */
+#define IDT_PCI_DAC 0x44
+#define IDT_PCI_DAS 0x48
+#define IDT_PCI_DASM 0x4C
+
+#define IDT_PCI_TC 0x5C
+#define IDT_PCI_TC_RTIMER 0x10
+#define IDT_PCI_TC_DTIMER 0x08
+/* Messaging unit of PCI controller */
+#define IDT_PCI_IIC 0x8024
+#define IDT_PCI_IIM 0x8028
+#define IDT_PCI_OIC 0x8030
+#define IDT_PCI_OIM 0x8034
+
+/* PCI-related stuff */
+#define IDT_PCIMEM0_BASE 0x50000000
+#define IDT_PCIMEM0_SIZE 0x01000000
+
+#define IDT_PCIMEM1_BASE 0x60000000
+#define IDT_PCIMEM1_SIZE 0x10000000
+
+#define IDT_PCIMEM2_BASE 0x18C00000
+#define IDT_PCIMEM2_SIZE 0x00400000
+
+#define IDT_PCIMEM3_BASE 0x18800000
+#define IDT_PCIMEM3_SIZE 0x00100000
+
+/* Interrupts-related stuff */
+#define IRQ_BASE 8
+/* Convert <IPbit, irq_offset> pair to IRQ number */
+#define IP_IRQ(IPbit, offset) ((IPbit - 2) * 32 + (offset) + IRQ_BASE)
+/* The last one available IRQ */
+#define IRQ_END IP_IRQ(6, 31)
+#define ICU_GROUP_REG_OFFSET 0x0C
+
+#define ICU_IP(irq) (((irq) - IRQ_BASE) & 0x1f)
+#define ICU_IP_BIT(irq) (1 << ICU_IP(irq))
+#define ICU_GROUP(irq) (((irq) - IRQ_BASE) >> 5)
+
+#define ICU_GROUP_MASK_REG(group) \
+ (ICU_IMASK2 + ((((group) - 2) * ICU_GROUP_REG_OFFSET)))
+#define ICU_GROUP_IPEND_REG(group) \
+ (ICU_IPEND2 + ((((group) - 2) * ICU_GROUP_REG_OFFSET)))
+
+#define ICU_IRQ_MASK_REG(irq) \
+ (ICU_IMASK2 + ((ICU_GROUP(irq) * ICU_GROUP_REG_OFFSET)))
+#define ICU_IRQ_IPEND_REG(irq) \
+ (ICU_IPEND2 + ((ICU_GROUP(irq) * ICU_GROUP_REG_OFFSET)))
+
+#define PCI_IRQ_BASE IP_IRQ(6, 4)
+#define PCI_IRQ_END IP_IRQ(6, 7)
+
+#endif /* __IDTREG_H__ */
+
diff --git a/sys/mips/idt/if_kr.c b/sys/mips/idt/if_kr.c
new file mode 100644
index 0000000..817cff2
--- /dev/null
+++ b/sys/mips/idt/if_kr.c
@@ -0,0 +1,1615 @@
+/*-
+ * 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 SOFTWARE 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 ARE 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 SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: $
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * RC32434 Ethernet interface driver
+ */
+#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/module.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/bpf.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>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+MODULE_DEPEND(kr, ether, 1, 1, 1);
+MODULE_DEPEND(kr, miibus, 1, 1, 1);
+
+#include "miibus_if.h"
+
+#include <mips/mips32/idt/if_krreg.h>
+
+#define KR_DEBUG
+
+static int kr_attach(device_t);
+static int kr_detach(device_t);
+static int kr_ifmedia_upd(struct ifnet *);
+static void kr_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int kr_ioctl(struct ifnet *, u_long, caddr_t);
+static void kr_init(void *);
+static void kr_init_locked(struct kr_softc *);
+static void kr_link_task(void *, int);
+static int kr_miibus_readreg(device_t, int, int);
+static void kr_miibus_statchg(device_t);
+static int kr_miibus_writereg(device_t, int, int, int);
+static int kr_probe(device_t);
+static void kr_reset(struct kr_softc *);
+static int kr_resume(device_t);
+static int kr_rx_ring_init(struct kr_softc *);
+static int kr_tx_ring_init(struct kr_softc *);
+static void kr_shutdown(device_t);
+static void kr_start(struct ifnet *);
+static void kr_start_locked(struct ifnet *);
+static void kr_stop(struct kr_softc *);
+static int kr_suspend(device_t);
+
+static void kr_rx(struct kr_softc *);
+static void kr_tx(struct kr_softc *);
+static void kr_rx_intr(void *);
+static void kr_tx_intr(void *);
+static void kr_rx_und_intr(void *);
+static void kr_tx_ovr_intr(void *);
+static void kr_tick(void *);
+
+static void kr_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+static int kr_dma_alloc(struct kr_softc *);
+static void kr_dma_free(struct kr_softc *);
+static int kr_newbuf(struct kr_softc *, int);
+static __inline void kr_fixup_rx(struct mbuf *);
+
+static device_method_t kr_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, kr_probe),
+ DEVMETHOD(device_attach, kr_attach),
+ DEVMETHOD(device_detach, kr_detach),
+ DEVMETHOD(device_suspend, kr_suspend),
+ DEVMETHOD(device_resume, kr_resume),
+ DEVMETHOD(device_shutdown, kr_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, kr_miibus_readreg),
+ DEVMETHOD(miibus_writereg, kr_miibus_writereg),
+ DEVMETHOD(miibus_statchg, kr_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t kr_driver = {
+ "kr",
+ kr_methods,
+ sizeof(struct kr_softc)
+};
+
+static devclass_t kr_devclass;
+
+DRIVER_MODULE(kr, obio, kr_driver, kr_devclass, 0, 0);
+DRIVER_MODULE(kr, cardbus, kr_driver, kr_devclass, 0, 0);
+DRIVER_MODULE(miibus, kr, miibus_driver, miibus_devclass, 0, 0);
+
+static int
+kr_probe(device_t dev)
+{
+
+ device_set_desc(dev, "RC32434 Ethernet interface");
+ return (0);
+}
+
+static int
+kr_attach(device_t dev)
+{
+ uint8_t eaddr[ETHER_ADDR_LEN];
+ struct ifnet *ifp;
+ struct kr_softc *sc;
+ int error = 0, rid;
+ int unit;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ sc->kr_dev = dev;
+
+ mtx_init(&sc->kr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF);
+ callout_init_mtx(&sc->kr_stat_callout, &sc->kr_mtx, 0);
+ TASK_INIT(&sc->kr_link_task, 0, kr_link_task, sc);
+ pci_enable_busmaster(dev);
+
+ /* Map control/status registers. */
+ sc->kr_rid = 0;
+ sc->kr_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->kr_rid,
+ RF_ACTIVE);
+
+ if (sc->kr_res == NULL) {
+ device_printf(dev, "couldn't map memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->kr_btag = rman_get_bustag(sc->kr_res);
+ sc->kr_bhandle = rman_get_bushandle(sc->kr_res);
+
+ /* Allocate interrupts */
+ rid = 0;
+ sc->kr_rx_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, KR_RX_IRQ,
+ KR_RX_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->kr_rx_irq == NULL) {
+ device_printf(dev, "couldn't map rx interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ rid = 0;
+ sc->kr_tx_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, KR_TX_IRQ,
+ KR_TX_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->kr_tx_irq == NULL) {
+ device_printf(dev, "couldn't map tx interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ rid = 0;
+ sc->kr_rx_und_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ KR_RX_UND_IRQ, KR_RX_UND_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->kr_rx_und_irq == NULL) {
+ device_printf(dev, "couldn't map rx underrun interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ rid = 0;
+ sc->kr_tx_ovr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ KR_TX_OVR_IRQ, KR_TX_OVR_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->kr_tx_ovr_irq == NULL) {
+ device_printf(dev, "couldn't map tx overrun interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Allocate ifnet structure. */
+ ifp = sc->kr_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 = kr_ioctl;
+ ifp->if_start = kr_start;
+ ifp->if_init = kr_init;
+
+ /* XXX: add real size */
+ IFQ_SET_MAXLEN(&ifp->if_snd, 9);
+ ifp->if_snd.ifq_maxlen = 9;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ ifp->if_capenable = ifp->if_capabilities;
+
+ eaddr[0] = 0x00;
+ eaddr[1] = 0x0C;
+ eaddr[2] = 0x42;
+ eaddr[3] = 0x09;
+ eaddr[4] = 0x5E;
+ eaddr[5] = 0x6B;
+
+ if (kr_dma_alloc(sc) != 0) {
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* TODO: calculate prescale */
+ CSR_WRITE_4(sc, KR_ETHMCP, (165000000 / (1250000 + 1)) & ~1);
+
+ CSR_WRITE_4(sc, KR_MIIMCFG, KR_MIIMCFG_R);
+ DELAY(1000);
+ CSR_WRITE_4(sc, KR_MIIMCFG, 0);
+
+ /* Do MII setup. */
+ if (mii_phy_probe(dev, &sc->kr_miibus,
+ kr_ifmedia_upd, kr_ifmedia_sts)) {
+ device_printf(dev, "MII without any phy!\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Call MI attach routine. */
+ ether_ifattach(ifp, eaddr);
+
+ /* Hook interrupt last to avoid having to lock softc */
+ error = bus_setup_intr(dev, sc->kr_rx_irq, INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, kr_rx_intr, sc, &sc->kr_rx_intrhand);
+
+ if (error) {
+ device_printf(dev, "couldn't set up rx irq\n");
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->kr_tx_irq, INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, kr_tx_intr, sc, &sc->kr_tx_intrhand);
+
+ if (error) {
+ device_printf(dev, "couldn't set up tx irq\n");
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->kr_rx_und_irq,
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, kr_rx_und_intr, sc,
+ &sc->kr_rx_und_intrhand);
+
+ if (error) {
+ device_printf(dev, "couldn't set up rx underrun irq\n");
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->kr_tx_ovr_irq,
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, kr_tx_ovr_intr, sc,
+ &sc->kr_tx_ovr_intrhand);
+
+ if (error) {
+ device_printf(dev, "couldn't set up tx overrun irq\n");
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+
+fail:
+ if (error)
+ kr_detach(dev);
+
+ return (error);
+}
+
+static int
+kr_detach(device_t dev)
+{
+ struct kr_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = sc->kr_ifp;
+
+ KASSERT(mtx_initialized(&sc->kr_mtx), ("vr mutex not initialized"));
+
+ /* These should only be active if attach succeeded */
+ if (device_is_attached(dev)) {
+ KR_LOCK(sc);
+ sc->kr_detach = 1;
+ kr_stop(sc);
+ KR_UNLOCK(sc);
+ taskqueue_drain(taskqueue_swi, &sc->kr_link_task);
+ ether_ifdetach(ifp);
+ }
+ if (sc->kr_miibus)
+ device_delete_child(dev, sc->kr_miibus);
+ bus_generic_detach(dev);
+
+ if (sc->kr_rx_intrhand)
+ bus_teardown_intr(dev, sc->kr_rx_irq, sc->kr_rx_intrhand);
+ if (sc->kr_rx_irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_rx_irq);
+ if (sc->kr_tx_intrhand)
+ bus_teardown_intr(dev, sc->kr_tx_irq, sc->kr_tx_intrhand);
+ if (sc->kr_tx_irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_tx_irq);
+ if (sc->kr_rx_und_intrhand)
+ bus_teardown_intr(dev, sc->kr_rx_und_irq,
+ sc->kr_rx_und_intrhand);
+ if (sc->kr_rx_und_irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_rx_und_irq);
+ if (sc->kr_tx_ovr_intrhand)
+ bus_teardown_intr(dev, sc->kr_tx_ovr_irq,
+ sc->kr_tx_ovr_intrhand);
+ if (sc->kr_tx_ovr_irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_tx_ovr_irq);
+
+ if (sc->kr_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->kr_rid,
+ sc->kr_res);
+
+ if (ifp)
+ if_free(ifp);
+
+ kr_dma_free(sc);
+
+ mtx_destroy(&sc->kr_mtx);
+
+ return (0);
+
+}
+
+static int
+kr_suspend(device_t dev)
+{
+
+ panic("%s", __func__);
+ return 0;
+}
+
+static int
+kr_resume(device_t dev)
+{
+
+ panic("%s", __func__);
+ return 0;
+}
+
+static void
+kr_shutdown(device_t dev)
+{
+ struct kr_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ KR_LOCK(sc);
+ kr_stop(sc);
+ KR_UNLOCK(sc);
+}
+
+static int
+kr_miibus_readreg(device_t dev, int phy, int reg)
+{
+ struct kr_softc * sc = device_get_softc(dev);
+ int i, result;
+
+ i = KR_MII_TIMEOUT;
+ while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
+ i--;
+
+ if (i == 0)
+ device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
+
+ CSR_WRITE_4(sc, KR_MIIMADDR, (phy << 8) | reg);
+
+ i = KR_MII_TIMEOUT;
+ while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
+ i--;
+
+ if (i == 0)
+ device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
+
+ CSR_WRITE_4(sc, KR_MIIMCMD, KR_MIIMCMD_RD);
+
+ i = KR_MII_TIMEOUT;
+ while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
+ i--;
+
+ if (i == 0)
+ device_printf(dev, "phy mii read is timed out %d:%d\n", phy,
+ reg);
+
+ if (CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_NV)
+ printf("phy mii readreg failed %d:%d: data not valid\n",
+ phy, reg);
+
+ result = CSR_READ_4(sc , KR_MIIMRDD);
+ CSR_WRITE_4(sc, KR_MIIMCMD, 0);
+
+ return (result);
+}
+
+static int
+kr_miibus_writereg(device_t dev, int phy, int reg, int data)
+{
+ struct kr_softc * sc = device_get_softc(dev);
+ int i;
+
+ i = KR_MII_TIMEOUT;
+ while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
+ i--;
+
+ if (i == 0)
+ device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
+
+ CSR_WRITE_4(sc, KR_MIIMADDR, (phy << 8) | reg);
+
+ i = KR_MII_TIMEOUT;
+ while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
+ i--;
+
+ if (i == 0)
+ device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
+
+ CSR_WRITE_4(sc, KR_MIIMWTD, data);
+
+ i = KR_MII_TIMEOUT;
+ while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
+ i--;
+
+ if (i == 0)
+ device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
+
+ return (0);
+}
+
+static void
+kr_miibus_statchg(device_t dev)
+{
+ struct kr_softc *sc;
+
+ sc = device_get_softc(dev);
+ taskqueue_enqueue(taskqueue_swi, &sc->kr_link_task);
+}
+
+static void
+kr_link_task(void *arg, int pending)
+{
+ struct kr_softc *sc;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ /* int lfdx, mfdx; */
+
+ sc = (struct kr_softc *)arg;
+
+ KR_LOCK(sc);
+ mii = device_get_softc(sc->kr_miibus);
+ ifp = sc->kr_ifp;
+ if (mii == NULL || ifp == NULL ||
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ KR_UNLOCK(sc);
+ return;
+ }
+
+ if (mii->mii_media_status & IFM_ACTIVE) {
+ if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
+ sc->kr_link_status = 1;
+ } else
+ sc->kr_link_status = 0;
+
+ KR_UNLOCK(sc);
+}
+
+static void
+kr_reset(struct kr_softc *sc)
+{
+ int i;
+
+ CSR_WRITE_4(sc, KR_ETHINTFC, 0);
+
+ for (i = 0; i < KR_TIMEOUT; i++) {
+ DELAY(10);
+ if (!(CSR_READ_4(sc, KR_ETHINTFC) & ETH_INTFC_RIP))
+ break;
+ }
+
+ if (i == KR_TIMEOUT)
+ device_printf(sc->kr_dev, "reset time out\n");
+}
+
+static void
+kr_init(void *xsc)
+{
+ struct kr_softc *sc = xsc;
+
+ KR_LOCK(sc);
+ kr_init_locked(sc);
+ KR_UNLOCK(sc);
+}
+
+static void
+kr_init_locked(struct kr_softc *sc)
+{
+ struct ifnet *ifp = sc->kr_ifp;
+ struct mii_data *mii;
+
+ KR_LOCK_ASSERT(sc);
+
+ mii = device_get_softc(sc->kr_miibus);
+
+ kr_stop(sc);
+ kr_reset(sc);
+
+ CSR_WRITE_4(sc, KR_ETHINTFC, ETH_INTFC_EN);
+
+ /* Init circular RX list. */
+ if (kr_rx_ring_init(sc) != 0) {
+ device_printf(sc->kr_dev,
+ "initialization failed: no memory for rx buffers\n");
+ kr_stop(sc);
+ return;
+ }
+
+ /* Init tx descriptors. */
+ kr_tx_ring_init(sc);
+
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_S, 0);
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_NDPTR, 0);
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_DPTR,
+ sc->kr_rdata.kr_rx_ring_paddr);
+
+
+ KR_DMA_CLEARBITS_REG(KR_DMA_RXCHAN, DMA_SM,
+ DMA_SM_H | DMA_SM_E | DMA_SM_D) ;
+
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_S, 0);
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_NDPTR, 0);
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_DPTR, 0);
+ KR_DMA_CLEARBITS_REG(KR_DMA_TXCHAN, DMA_SM,
+ DMA_SM_F | DMA_SM_E);
+
+
+ /* Accept only packets destined for THIS Ethernet device address */
+ CSR_WRITE_4(sc, KR_ETHARC, 1);
+
+ /*
+ * Set all Ethernet address registers to the same initial values
+ * set all four addresses to 66-88-aa-cc-dd-ee
+ */
+ CSR_WRITE_4(sc, KR_ETHSAL0, 0x42095E6B);
+ CSR_WRITE_4(sc, KR_ETHSAH0, 0x0000000C);
+
+ CSR_WRITE_4(sc, KR_ETHSAL1, 0x42095E6B);
+ CSR_WRITE_4(sc, KR_ETHSAH1, 0x0000000C);
+
+ CSR_WRITE_4(sc, KR_ETHSAL2, 0x42095E6B);
+ CSR_WRITE_4(sc, KR_ETHSAH2, 0x0000000C);
+
+ CSR_WRITE_4(sc, KR_ETHSAL3, 0x42095E6B);
+ CSR_WRITE_4(sc, KR_ETHSAH3, 0x0000000C);
+
+ CSR_WRITE_4(sc, KR_ETHMAC2,
+ KR_ETH_MAC2_PEN | KR_ETH_MAC2_CEN | KR_ETH_MAC2_FD);
+
+ CSR_WRITE_4(sc, KR_ETHIPGT, KR_ETHIPGT_FULL_DUPLEX);
+ CSR_WRITE_4(sc, KR_ETHIPGR, 0x12); /* minimum value */
+
+ CSR_WRITE_4(sc, KR_MIIMCFG, KR_MIIMCFG_R);
+ DELAY(1000);
+ CSR_WRITE_4(sc, KR_MIIMCFG, 0);
+
+ /* TODO: calculate prescale */
+ CSR_WRITE_4(sc, KR_ETHMCP, (165000000 / (1250000 + 1)) & ~1);
+
+ /* FIFO Tx threshold level */
+ CSR_WRITE_4(sc, KR_ETHFIFOTT, 0x30);
+
+ CSR_WRITE_4(sc, KR_ETHMAC1, KR_ETH_MAC1_RE);
+
+ sc->kr_link_status = 0;
+ mii_mediachg(mii);
+
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ callout_reset(&sc->kr_stat_callout, hz, kr_tick, sc);
+}
+
+static void
+kr_start(struct ifnet *ifp)
+{
+ struct kr_softc *sc;
+
+ sc = ifp->if_softc;
+
+ KR_LOCK(sc);
+ kr_start_locked(ifp);
+ KR_UNLOCK(sc);
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int
+kr_encap(struct kr_softc *sc, struct mbuf **m_head)
+{
+ struct kr_txdesc *txd;
+ struct kr_desc *desc, *prev_desc;
+ bus_dma_segment_t txsegs[KR_MAXFRAGS];
+ uint32_t link_addr;
+ int error, i, nsegs, prod, si, prev_prod;
+
+ KR_LOCK_ASSERT(sc);
+
+ prod = sc->kr_cdata.kr_tx_prod;
+ txd = &sc->kr_cdata.kr_txdesc[prod];
+ error = bus_dmamap_load_mbuf_sg(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap,
+ *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
+ if (error == EFBIG) {
+ panic("EFBIG");
+ } 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->kr_cdata.kr_tx_cnt + nsegs >= (KR_TX_RING_CNT - 1)) {
+ bus_dmamap_unload(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap);
+ return (ENOBUFS);
+ }
+
+ txd->tx_m = *m_head;
+ bus_dmamap_sync(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_PREWRITE);
+
+ si = prod;
+
+ /*
+ * Make a list of descriptors for this packet. DMA controller will
+ * walk through it while kr_link is not zero. The last one should
+ * have COF flag set, to pickup next chain from NDPTR
+ */
+ prev_prod = prod;
+ desc = prev_desc = NULL;
+ for (i = 0; i < nsegs; i++) {
+ desc = &sc->kr_rdata.kr_tx_ring[prod];
+ desc->kr_ctl = KR_DMASIZE(txsegs[i].ds_len) | KR_CTL_IOF;
+ if (i == 0)
+ desc->kr_devcs = KR_DMATX_DEVCS_FD;
+ desc->kr_ca = txsegs[i].ds_addr;
+ desc->kr_link = 0;
+ /* link with previous descriptor */
+ if (prev_desc)
+ prev_desc->kr_link = KR_TX_RING_ADDR(sc, prod);
+
+ sc->kr_cdata.kr_tx_cnt++;
+ prev_desc = desc;
+ KR_INC(prod, KR_TX_RING_CNT);
+ }
+
+ /*
+ * Set COF for last descriptor and mark last fragment with LD flag
+ */
+ if (desc) {
+ desc->kr_ctl |= KR_CTL_COF;
+ desc->kr_devcs |= KR_DMATX_DEVCS_LD;
+ }
+
+ /* Update producer index. */
+ sc->kr_cdata.kr_tx_prod = prod;
+
+ /* Sync descriptors. */
+ bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_cdata.kr_tx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /* Start transmitting */
+ /* Check if new list is queued in NDPTR */
+ if (KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_NDPTR) == 0) {
+ /* NDPTR is not busy - start new list */
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_NDPTR,
+ KR_TX_RING_ADDR(sc, si));
+ }
+ else {
+ link_addr = KR_TX_RING_ADDR(sc, si);
+ /* Get previous descriptor */
+ si = (si + KR_TX_RING_CNT - 1) % KR_TX_RING_CNT;
+ desc = &sc->kr_rdata.kr_tx_ring[si];
+ desc->kr_link = link_addr;
+ }
+
+ return (0);
+}
+
+static void
+kr_start_locked(struct ifnet *ifp)
+{
+ struct kr_softc *sc;
+ struct mbuf *m_head;
+ int enq;
+
+ sc = ifp->if_softc;
+
+ KR_LOCK_ASSERT(sc);
+
+ if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING || sc->kr_link_status == 0 )
+ return;
+
+ for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
+ sc->kr_cdata.kr_tx_cnt < KR_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 (kr_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);
+ }
+}
+
+static void
+kr_stop(struct kr_softc *sc)
+{
+ struct ifnet *ifp;
+
+ KR_LOCK_ASSERT(sc);
+
+
+ ifp = sc->kr_ifp;
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ callout_stop(&sc->kr_stat_callout);
+
+ /* mask out RX interrupts */
+ KR_DMA_SETBITS_REG(KR_DMA_RXCHAN, DMA_SM,
+ DMA_SM_D | DMA_SM_H | DMA_SM_E);
+
+ /* mask out TX interrupts */
+ KR_DMA_SETBITS_REG(KR_DMA_TXCHAN, DMA_SM,
+ DMA_SM_F | DMA_SM_E);
+
+ /* Abort RX DMA transactions */
+ if (KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_C) & DMA_C_R) {
+ /* Set ABORT bit if trunsuction is in progress */
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_C, DMA_C_ABORT);
+ /* XXX: Add timeout */
+ while ((KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_S) & DMA_S_H) == 0)
+ DELAY(10);
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_S, 0);
+ }
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_DPTR, 0);
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_NDPTR, 0);
+
+ /* Abort TX DMA transactions */
+ if (KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_C) & DMA_C_R) {
+ /* Set ABORT bit if trunsuction is in progress */
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_C, DMA_C_ABORT);
+ /* XXX: Add timeout */
+ while ((KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_S) & DMA_S_H) == 0)
+ DELAY(10);
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_S, 0);
+ }
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_DPTR, 0);
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_NDPTR, 0);
+
+ CSR_WRITE_4(sc, KR_ETHINTFC, 0);
+}
+
+
+static int
+kr_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct kr_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
+ int error;
+
+ switch (command) {
+ case SIOCSIFFLAGS:
+#if 0
+ KR_LOCK(sc);
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ if ((ifp->if_flags ^ sc->kr_if_flags) &
+ (IFF_PROMISC | IFF_ALLMULTI))
+ kr_set_filter(sc);
+ } else {
+ if (sc->kr_detach == 0)
+ kr_init_locked(sc);
+ }
+ } else {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ kr_stop(sc);
+ }
+ sc->kr_if_flags = ifp->if_flags;
+ KR_UNLOCK(sc);
+#endif
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+#if 0
+ KR_LOCK(sc);
+ kr_set_filter(sc);
+ KR_UNLOCK(sc);
+#endif
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->kr_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ 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 = KR_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) {
+ KR_LOCK(sc);
+ kr_vlan_setup(sc);
+ KR_UNLOCK(sc);
+ }
+ }
+ VLAN_CAPABILITIES(ifp);
+#endif
+ break;
+ default:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ }
+
+ return (error);
+}
+
+/*
+ * Set media options.
+ */
+static int
+kr_ifmedia_upd(struct ifnet *ifp)
+{
+ struct kr_softc *sc;
+ struct mii_data *mii;
+ struct mii_softc *miisc;
+ int error;
+
+ sc = ifp->if_softc;
+ KR_LOCK(sc);
+ mii = device_get_softc(sc->kr_miibus);
+ if (mii->mii_instance) {
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ mii_phy_reset(miisc);
+ }
+ error = mii_mediachg(mii);
+ KR_UNLOCK(sc);
+
+ return (error);
+}
+
+/*
+ * Report current media status.
+ */
+static void
+kr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct kr_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+
+ mii = device_get_softc(sc->kr_miibus);
+ KR_LOCK(sc);
+ mii_pollstat(mii);
+ KR_UNLOCK(sc);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+}
+
+struct kr_dmamap_arg {
+ bus_addr_t kr_busaddr;
+};
+
+static void
+kr_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct kr_dmamap_arg *ctx;
+
+ if (error != 0)
+ return;
+ ctx = arg;
+ ctx->kr_busaddr = segs[0].ds_addr;
+}
+
+static int
+kr_dma_alloc(struct kr_softc *sc)
+{
+ struct kr_dmamap_arg ctx;
+ struct kr_txdesc *txd;
+ struct kr_rxdesc *rxd;
+ int error, i;
+
+ /* Create parent DMA tag. */
+ error = bus_dma_tag_create(
+ bus_get_dma_tag(sc->kr_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->kr_cdata.kr_parent_tag);
+ if (error != 0) {
+ device_printf(sc->kr_dev, "failed to create parent DMA tag\n");
+ goto fail;
+ }
+ /* Create tag for Tx ring. */
+ error = bus_dma_tag_create(
+ sc->kr_cdata.kr_parent_tag, /* parent */
+ KR_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ KR_TX_RING_SIZE, /* maxsize */
+ 1, /* nsegments */
+ KR_TX_RING_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->kr_cdata.kr_tx_ring_tag);
+ if (error != 0) {
+ device_printf(sc->kr_dev, "failed to create Tx ring DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Rx ring. */
+ error = bus_dma_tag_create(
+ sc->kr_cdata.kr_parent_tag, /* parent */
+ KR_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ KR_RX_RING_SIZE, /* maxsize */
+ 1, /* nsegments */
+ KR_RX_RING_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->kr_cdata.kr_rx_ring_tag);
+ if (error != 0) {
+ device_printf(sc->kr_dev, "failed to create Rx ring DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Tx buffers. */
+ error = bus_dma_tag_create(
+ sc->kr_cdata.kr_parent_tag, /* parent */
+ sizeof(uint32_t), 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MCLBYTES * KR_MAXFRAGS, /* maxsize */
+ KR_MAXFRAGS, /* nsegments */
+ MCLBYTES, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->kr_cdata.kr_tx_tag);
+ if (error != 0) {
+ device_printf(sc->kr_dev, "failed to create Tx DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Rx buffers. */
+ error = bus_dma_tag_create(
+ sc->kr_cdata.kr_parent_tag, /* parent */
+ KR_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->kr_cdata.kr_rx_tag);
+ if (error != 0) {
+ device_printf(sc->kr_dev, "failed to create Rx DMA tag\n");
+ goto fail;
+ }
+
+ /* Allocate DMA'able memory and load the DMA map for Tx ring. */
+ error = bus_dmamem_alloc(sc->kr_cdata.kr_tx_ring_tag,
+ (void **)&sc->kr_rdata.kr_tx_ring, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->kr_cdata.kr_tx_ring_map);
+ if (error != 0) {
+ device_printf(sc->kr_dev,
+ "failed to allocate DMA'able memory for Tx ring\n");
+ goto fail;
+ }
+
+ ctx.kr_busaddr = 0;
+ error = bus_dmamap_load(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_cdata.kr_tx_ring_map, sc->kr_rdata.kr_tx_ring,
+ KR_TX_RING_SIZE, kr_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.kr_busaddr == 0) {
+ device_printf(sc->kr_dev,
+ "failed to load DMA'able memory for Tx ring\n");
+ goto fail;
+ }
+ sc->kr_rdata.kr_tx_ring_paddr = ctx.kr_busaddr;
+
+ /* Allocate DMA'able memory and load the DMA map for Rx ring. */
+ error = bus_dmamem_alloc(sc->kr_cdata.kr_rx_ring_tag,
+ (void **)&sc->kr_rdata.kr_rx_ring, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->kr_cdata.kr_rx_ring_map);
+ if (error != 0) {
+ device_printf(sc->kr_dev,
+ "failed to allocate DMA'able memory for Rx ring\n");
+ goto fail;
+ }
+
+ ctx.kr_busaddr = 0;
+ error = bus_dmamap_load(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_cdata.kr_rx_ring_map, sc->kr_rdata.kr_rx_ring,
+ KR_RX_RING_SIZE, kr_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.kr_busaddr == 0) {
+ device_printf(sc->kr_dev,
+ "failed to load DMA'able memory for Rx ring\n");
+ goto fail;
+ }
+ sc->kr_rdata.kr_rx_ring_paddr = ctx.kr_busaddr;
+
+ /* Create DMA maps for Tx buffers. */
+ for (i = 0; i < KR_TX_RING_CNT; i++) {
+ txd = &sc->kr_cdata.kr_txdesc[i];
+ txd->tx_m = NULL;
+ txd->tx_dmamap = NULL;
+ error = bus_dmamap_create(sc->kr_cdata.kr_tx_tag, 0,
+ &txd->tx_dmamap);
+ if (error != 0) {
+ device_printf(sc->kr_dev,
+ "failed to create Tx dmamap\n");
+ goto fail;
+ }
+ }
+ /* Create DMA maps for Rx buffers. */
+ if ((error = bus_dmamap_create(sc->kr_cdata.kr_rx_tag, 0,
+ &sc->kr_cdata.kr_rx_sparemap)) != 0) {
+ device_printf(sc->kr_dev,
+ "failed to create spare Rx dmamap\n");
+ goto fail;
+ }
+ for (i = 0; i < KR_RX_RING_CNT; i++) {
+ rxd = &sc->kr_cdata.kr_rxdesc[i];
+ rxd->rx_m = NULL;
+ rxd->rx_dmamap = NULL;
+ error = bus_dmamap_create(sc->kr_cdata.kr_rx_tag, 0,
+ &rxd->rx_dmamap);
+ if (error != 0) {
+ device_printf(sc->kr_dev,
+ "failed to create Rx dmamap\n");
+ goto fail;
+ }
+ }
+
+fail:
+ return (error);
+}
+
+static void
+kr_dma_free(struct kr_softc *sc)
+{
+ struct kr_txdesc *txd;
+ struct kr_rxdesc *rxd;
+ int i;
+
+ /* Tx ring. */
+ if (sc->kr_cdata.kr_tx_ring_tag) {
+ if (sc->kr_cdata.kr_tx_ring_map)
+ bus_dmamap_unload(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_cdata.kr_tx_ring_map);
+ if (sc->kr_cdata.kr_tx_ring_map &&
+ sc->kr_rdata.kr_tx_ring)
+ bus_dmamem_free(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_rdata.kr_tx_ring,
+ sc->kr_cdata.kr_tx_ring_map);
+ sc->kr_rdata.kr_tx_ring = NULL;
+ sc->kr_cdata.kr_tx_ring_map = NULL;
+ bus_dma_tag_destroy(sc->kr_cdata.kr_tx_ring_tag);
+ sc->kr_cdata.kr_tx_ring_tag = NULL;
+ }
+ /* Rx ring. */
+ if (sc->kr_cdata.kr_rx_ring_tag) {
+ if (sc->kr_cdata.kr_rx_ring_map)
+ bus_dmamap_unload(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_cdata.kr_rx_ring_map);
+ if (sc->kr_cdata.kr_rx_ring_map &&
+ sc->kr_rdata.kr_rx_ring)
+ bus_dmamem_free(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_rdata.kr_rx_ring,
+ sc->kr_cdata.kr_rx_ring_map);
+ sc->kr_rdata.kr_rx_ring = NULL;
+ sc->kr_cdata.kr_rx_ring_map = NULL;
+ bus_dma_tag_destroy(sc->kr_cdata.kr_rx_ring_tag);
+ sc->kr_cdata.kr_rx_ring_tag = NULL;
+ }
+ /* Tx buffers. */
+ if (sc->kr_cdata.kr_tx_tag) {
+ for (i = 0; i < KR_TX_RING_CNT; i++) {
+ txd = &sc->kr_cdata.kr_txdesc[i];
+ if (txd->tx_dmamap) {
+ bus_dmamap_destroy(sc->kr_cdata.kr_tx_tag,
+ txd->tx_dmamap);
+ txd->tx_dmamap = NULL;
+ }
+ }
+ bus_dma_tag_destroy(sc->kr_cdata.kr_tx_tag);
+ sc->kr_cdata.kr_tx_tag = NULL;
+ }
+ /* Rx buffers. */
+ if (sc->kr_cdata.kr_rx_tag) {
+ for (i = 0; i < KR_RX_RING_CNT; i++) {
+ rxd = &sc->kr_cdata.kr_rxdesc[i];
+ if (rxd->rx_dmamap) {
+ bus_dmamap_destroy(sc->kr_cdata.kr_rx_tag,
+ rxd->rx_dmamap);
+ rxd->rx_dmamap = NULL;
+ }
+ }
+ if (sc->kr_cdata.kr_rx_sparemap) {
+ bus_dmamap_destroy(sc->kr_cdata.kr_rx_tag,
+ sc->kr_cdata.kr_rx_sparemap);
+ sc->kr_cdata.kr_rx_sparemap = 0;
+ }
+ bus_dma_tag_destroy(sc->kr_cdata.kr_rx_tag);
+ sc->kr_cdata.kr_rx_tag = NULL;
+ }
+
+ if (sc->kr_cdata.kr_parent_tag) {
+ bus_dma_tag_destroy(sc->kr_cdata.kr_parent_tag);
+ sc->kr_cdata.kr_parent_tag = NULL;
+ }
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int
+kr_tx_ring_init(struct kr_softc *sc)
+{
+ struct kr_ring_data *rd;
+ struct kr_txdesc *txd;
+ bus_addr_t addr;
+ int i;
+
+ sc->kr_cdata.kr_tx_prod = 0;
+ sc->kr_cdata.kr_tx_cons = 0;
+ sc->kr_cdata.kr_tx_cnt = 0;
+ sc->kr_cdata.kr_tx_pkts = 0;
+
+ rd = &sc->kr_rdata;
+ bzero(rd->kr_tx_ring, KR_TX_RING_SIZE);
+ for (i = 0; i < KR_TX_RING_CNT; i++) {
+ if (i == KR_TX_RING_CNT - 1)
+ addr = KR_TX_RING_ADDR(sc, 0);
+ else
+ addr = KR_TX_RING_ADDR(sc, i + 1);
+ rd->kr_tx_ring[i].kr_ctl = KR_CTL_IOF;
+ rd->kr_tx_ring[i].kr_ca = 0;
+ rd->kr_tx_ring[i].kr_devcs = 0;
+ rd->kr_tx_ring[i].kr_link = 0;
+ txd = &sc->kr_cdata.kr_txdesc[i];
+ txd->tx_m = NULL;
+ }
+
+ bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_cdata.kr_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
+kr_rx_ring_init(struct kr_softc *sc)
+{
+ struct kr_ring_data *rd;
+ struct kr_rxdesc *rxd;
+ bus_addr_t addr;
+ int i;
+
+ sc->kr_cdata.kr_rx_cons = 0;
+
+ rd = &sc->kr_rdata;
+ bzero(rd->kr_rx_ring, KR_RX_RING_SIZE);
+ for (i = 0; i < KR_RX_RING_CNT; i++) {
+ rxd = &sc->kr_cdata.kr_rxdesc[i];
+ rxd->rx_m = NULL;
+ rxd->desc = &rd->kr_rx_ring[i];
+ if (i == KR_RX_RING_CNT - 1)
+ addr = KR_RX_RING_ADDR(sc, 0);
+ else
+ addr = KR_RX_RING_ADDR(sc, i + 1);
+ rd->kr_rx_ring[i].kr_ctl = KR_CTL_IOD;
+ if (i == KR_RX_RING_CNT - 1)
+ rd->kr_rx_ring[i].kr_ctl |= KR_CTL_COD;
+ rd->kr_rx_ring[i].kr_devcs = 0;
+ rd->kr_rx_ring[i].kr_ca = 0;
+ rd->kr_rx_ring[i].kr_link = addr;
+ if (kr_newbuf(sc, i) != 0)
+ return (ENOBUFS);
+ }
+
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_cdata.kr_rx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int
+kr_newbuf(struct kr_softc *sc, int idx)
+{
+ struct kr_desc *desc;
+ struct kr_rxdesc *rxd;
+ struct mbuf *m;
+ bus_dma_segment_t segs[1];
+ bus_dmamap_t map;
+ int nsegs;
+
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL)
+ return (ENOBUFS);
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+ m_adj(m, sizeof(uint64_t));
+
+ if (bus_dmamap_load_mbuf_sg(sc->kr_cdata.kr_rx_tag,
+ sc->kr_cdata.kr_rx_sparemap, m, segs, &nsegs, 0) != 0) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
+
+ rxd = &sc->kr_cdata.kr_rxdesc[idx];
+ if (rxd->rx_m != NULL) {
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap);
+ }
+ map = rxd->rx_dmamap;
+ rxd->rx_dmamap = sc->kr_cdata.kr_rx_sparemap;
+ sc->kr_cdata.kr_rx_sparemap = map;
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_PREREAD);
+ rxd->rx_m = m;
+ desc = rxd->desc;
+ desc->kr_ca = segs[0].ds_addr;
+ desc->kr_ctl |= KR_DMASIZE(segs[0].ds_len);
+ rxd->saved_ca = desc->kr_ca ;
+ rxd->saved_ctl = desc->kr_ctl ;
+
+ return (0);
+}
+
+static __inline void
+kr_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) + 1); i++)
+ *dst++ = *src++;
+
+ m->m_data -= ETHER_ALIGN;
+}
+
+
+static void
+kr_tx(struct kr_softc *sc)
+{
+ struct kr_txdesc *txd;
+ struct kr_desc *cur_tx;
+ struct ifnet *ifp;
+ uint32_t ctl, devcs;
+ int cons, prod;
+
+ KR_LOCK_ASSERT(sc);
+
+ cons = sc->kr_cdata.kr_tx_cons;
+ prod = sc->kr_cdata.kr_tx_prod;
+ if (cons == prod)
+ return;
+
+ bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_cdata.kr_tx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ ifp = sc->kr_ifp;
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ for (; cons != prod; KR_INC(cons, KR_TX_RING_CNT)) {
+ cur_tx = &sc->kr_rdata.kr_tx_ring[cons];
+ ctl = cur_tx->kr_ctl;
+ devcs = cur_tx->kr_devcs;
+ /* Check if descriptor has "finished" flag */
+ if ((ctl & KR_CTL_F) == 0)
+ break;
+
+ sc->kr_cdata.kr_tx_cnt--;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ txd = &sc->kr_cdata.kr_txdesc[cons];
+
+ if (devcs & KR_DMATX_DEVCS_TOK)
+ ifp->if_opackets++;
+ else {
+ ifp->if_oerrors++;
+ /* collisions: medium busy, late collision */
+ if ((devcs & KR_DMATX_DEVCS_EC) ||
+ (devcs & KR_DMATX_DEVCS_LC))
+ ifp->if_collisions++;
+ }
+
+ bus_dmamap_sync(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->kr_cdata.kr_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->kr_ctl = KR_CTL_IOF;
+ cur_tx->kr_devcs = 0;
+ cur_tx->kr_ca = 0;
+ cur_tx->kr_link = 0;
+ }
+
+ sc->kr_cdata.kr_tx_cons = cons;
+
+ bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_cdata.kr_tx_ring_map, BUS_DMASYNC_PREWRITE);
+}
+
+
+static void
+kr_rx(struct kr_softc *sc)
+{
+ struct kr_rxdesc *rxd;
+ struct ifnet *ifp = sc->kr_ifp;
+ int cons, prog, packet_len, count, error;
+ struct kr_desc *cur_rx;
+ struct mbuf *m;
+
+ KR_LOCK_ASSERT(sc);
+
+ cons = sc->kr_cdata.kr_rx_cons;
+
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_cdata.kr_rx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ for (prog = 0; prog < KR_RX_RING_CNT; KR_INC(cons, KR_RX_RING_CNT)) {
+ cur_rx = &sc->kr_rdata.kr_rx_ring[cons];
+ rxd = &sc->kr_cdata.kr_rxdesc[cons];
+ m = rxd->rx_m;
+
+ if ((cur_rx->kr_ctl & KR_CTL_D) == 0)
+ break;
+
+ prog++;
+
+ packet_len = KR_PKTSIZE(cur_rx->kr_devcs);
+ count = m->m_len - KR_DMASIZE(cur_rx->kr_ctl);
+ /* Assume it's error */
+ error = 1;
+
+ if (packet_len != count)
+ ifp->if_ierrors++;
+ else if (count < 64)
+ ifp->if_ierrors++;
+ else if ((cur_rx->kr_devcs & KR_DMARX_DEVCS_LD) == 0)
+ ifp->if_ierrors++;
+ else if ((cur_rx->kr_devcs & KR_DMARX_DEVCS_ROK) != 0) {
+ error = 0;
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_PREREAD);
+ m = rxd->rx_m;
+ kr_fixup_rx(m);
+ m->m_pkthdr.rcvif = ifp;
+ /* Skip 4 bytes of CRC */
+ m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN;
+ ifp->if_ipackets++;
+
+ KR_UNLOCK(sc);
+ (*ifp->if_input)(ifp, m);
+ KR_LOCK(sc);
+ }
+
+ if (error) {
+ /* Restore CONTROL and CA values, reset DEVCS */
+ cur_rx->kr_ctl = rxd->saved_ctl;
+ cur_rx->kr_ca = rxd->saved_ca;
+ cur_rx->kr_devcs = 0;
+ }
+ else {
+ /* Reinit descriptor */
+ cur_rx->kr_ctl = KR_CTL_IOD;
+ if (cons == KR_RX_RING_CNT - 1)
+ cur_rx->kr_ctl |= KR_CTL_COD;
+ cur_rx->kr_devcs = 0;
+ cur_rx->kr_ca = 0;
+ if (kr_newbuf(sc, cons) != 0) {
+ device_printf(sc->kr_dev,
+ "Failed to allocate buffer\n");
+ break;
+ }
+ }
+
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_cdata.kr_rx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ }
+
+ if (prog > 0) {
+ sc->kr_cdata.kr_rx_cons = cons;
+
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_cdata.kr_rx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ }
+}
+
+static void
+kr_rx_intr(void *arg)
+{
+ struct kr_softc *sc = arg;
+ uint32_t status;
+
+ KR_LOCK(sc);
+
+ /* mask out interrupts */
+ KR_DMA_SETBITS_REG(KR_DMA_RXCHAN, DMA_SM,
+ DMA_SM_D | DMA_SM_H | DMA_SM_E);
+
+ status = KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_S);
+ if (status & (DMA_S_D | DMA_S_E | DMA_S_H)) {
+ kr_rx(sc);
+
+ if (status & DMA_S_E)
+ device_printf(sc->kr_dev, "RX DMA error\n");
+ }
+
+ /* Reread status */
+ status = KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_S);
+
+ /* restart DMA RX if it has been halted */
+ if (status & DMA_S_H) {
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_DPTR,
+ KR_RX_RING_ADDR(sc, sc->kr_cdata.kr_rx_cons));
+ }
+
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_S, ~status);
+
+ /* Enable F, H, E interrupts */
+ KR_DMA_CLEARBITS_REG(KR_DMA_RXCHAN, DMA_SM,
+ DMA_SM_D | DMA_SM_H | DMA_SM_E);
+
+ KR_UNLOCK(sc);
+}
+
+static void
+kr_tx_intr(void *arg)
+{
+ struct kr_softc *sc = arg;
+ uint32_t status;
+
+ KR_LOCK(sc);
+
+ /* mask out interrupts */
+ KR_DMA_SETBITS_REG(KR_DMA_TXCHAN, DMA_SM,
+ DMA_SM_F | DMA_SM_E);
+
+ status = KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_S);
+ if (status & (DMA_S_F | DMA_S_E)) {
+ kr_tx(sc);
+ if (status & DMA_S_E)
+ device_printf(sc->kr_dev, "DMA error\n");
+ }
+
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_S, ~status);
+
+ /* Enable F, E interrupts */
+ KR_DMA_CLEARBITS_REG(KR_DMA_TXCHAN, DMA_SM,
+ DMA_SM_F | DMA_SM_E);
+
+ KR_UNLOCK(sc);
+
+}
+
+static void
+kr_rx_und_intr(void *arg)
+{
+
+ panic("interrupt: %s\n", __func__);
+}
+
+static void
+kr_tx_ovr_intr(void *arg)
+{
+
+ panic("interrupt: %s\n", __func__);
+}
+
+static void
+kr_tick(void *xsc)
+{
+ struct kr_softc *sc = xsc;
+ struct mii_data *mii;
+
+ KR_LOCK_ASSERT(sc);
+
+ mii = device_get_softc(sc->kr_miibus);
+ mii_tick(mii);
+ callout_reset(&sc->kr_stat_callout, hz, kr_tick, sc);
+}
diff --git a/sys/mips/idt/if_krreg.h b/sys/mips/idt/if_krreg.h
new file mode 100644
index 0000000..b20900a
--- /dev/null
+++ b/sys/mips/idt/if_krreg.h
@@ -0,0 +1,284 @@
+/*-
+ * 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 SOFTWARE 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 ARE 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 SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef __IF_KRREG_H__
+#define __IF_KRREG_H__
+
+#define KR_ETHINTFC 0x0000 /* Ethernet interface control */
+#define ETH_INTFC_EN 0x0001
+#define ETH_INTFC_RIP 0x0004
+#define ETH_INTFC_EN 0x0001
+#define KR_ETHFIFOTT 0x0004 /* Ethernet FIFO transmit threshold */
+#define KR_ETHARC 0x0008 /* Ethernet address recognition control */
+#define KR_ETHHASH0 0x000C /* Ethernet hash table 0 */
+#define KR_ETHHASH1 0x0010 /* Ethernet hash table 1 */
+#define KR_ETHPFS 0x0024 /* Ethernet pause frame status */
+#define KR_ETHMCP 0x0028 /* Ethernet management clock prescalar */
+#define KR_ETHSAL0 0x0100 /* Ethernet station address 0 low */
+#define KR_ETHSAH0 0x0104 /* Ethernet station address 0 high */
+#define KR_ETHSAL1 0x0108 /* Ethernet station address 1 low */
+#define KR_ETHSAH1 0x010C /* Ethernet station address 1 high */
+#define KR_ETHSAL2 0x0110 /* Ethernet station address 2 low */
+#define KR_ETHSAH2 0x0114 /* Ethernet station address 2 high */
+#define KR_ETHSAL3 0x0118 /* Ethernet station address 3 low */
+#define KR_ETHSAH3 0x011C /* Ethernet station address 3 high */
+#define KR_ETHRBC 0x0120 /* Ethernet receive byte count */
+#define KR_ETHRPC 0x0124 /* Ethernet receive packet count */
+#define KR_ETHRUPC 0x0128 /* Ethernet receive undersized packet cnt */
+#define KR_ETHRFC 0x012C /* Ethernet receive fragment count */
+#define KR_ETHTBC 0x0130 /* Ethernet transmit byte count */
+#define KR_ETHGPF 0x0134 /* Ethernet generate pause frame */
+#define KR_ETHMAC1 0x0200 /* Ethernet MAC configuration 1 */
+#define KR_ETH_MAC1_RE 0x01
+#define KR_ETH_MAC1_PAF 0x02
+#define KR_ETH_MAC1_MR 0x80
+#define KR_ETHMAC2 0x0204 /* Ethernet MAC configuration 2 */
+#define KR_ETH_MAC2_FD 0x01
+#define KR_ETH_MAC2_FLC 0x02
+#define KR_ETH_MAC2_HFE 0x04
+#define KR_ETH_MAC2_DC 0x08
+#define KR_ETH_MAC2_CEN 0x10
+#define KR_ETH_MAC2_PEN 0x20
+#define KR_ETH_MAC2_VPE 0x08
+#define KR_ETHIPGT 0x0208 /* Ethernet back-to-back inter-packet gap */
+#define KR_ETHIPGR 0x020C /* Ethernet non back-to-back inter-packet gap */
+#define KR_ETHCLRT 0x0210 /* Ethernet collision window retry */
+#define KR_ETHMAXF 0x0214 /* Ethernet maximum frame length */
+#define KR_ETHMTEST 0x021C /* Ethernet MAC test */
+#define KR_MIIMCFG 0x0220 /* MII management configuration */
+#define KR_MIIMCFG_R 0x8000
+#define KR_MIIMCMD 0x0224 /* MII management command */
+#define KR_MIIMCMD_RD 0x01
+#define KR_MIIMCMD_SCN 0x02
+#define KR_MIIMADDR 0x0228 /* MII management address */
+#define KR_MIIMWTD 0x022C /* MII management write data */
+#define KR_MIIMRDD 0x0230 /* MII management read data */
+#define KR_MIIMIND 0x0234 /* MII management indicators */
+#define KR_MIIMIND_BSY 0x1
+#define KR_MIIMIND_SCN 0x2
+#define KR_MIIMIND_NV 0x4
+#define KR_ETHCFSA0 0x0240 /* Ethernet control frame station address 0 */
+#define KR_ETHCFSA1 0x0244 /* Ethernet control frame station address 1 */
+#define KR_ETHCFSA2 0x0248 /* Ethernet control frame station address 2 */
+
+#define KR_ETHIPGT_HALF_DUPLEX 0x12
+#define KR_ETHIPGT_FULL_DUPLEX 0x15
+
+#define KR_TIMEOUT 0xf000
+#define KR_MII_TIMEOUT 0xf000
+
+#define KR_RX_IRQ 40
+#define KR_TX_IRQ 41
+#define KR_RX_UND_IRQ 42
+#define KR_TX_OVR_IRQ 43
+#define RC32434_DMA_BASE_ADDR MIPS_PHYS_TO_KSEG1(0x18040000)
+#define DMA_C 0x00
+#define DMA_C_R 0x01
+#define DMA_C_ABORT 0x10
+#define DMA_S 0x04
+#define DMA_S_F 0x01
+#define DMA_S_D 0x02
+#define DMA_S_C 0x04
+#define DMA_S_E 0x08
+#define DMA_S_H 0x10
+#define DMA_SM 0x08
+#define DMA_SM_F 0x01
+#define DMA_SM_D 0x02
+#define DMA_SM_C 0x04
+#define DMA_SM_E 0x08
+#define DMA_SM_H 0x10
+#define DMA_DPTR 0x0C
+#define DMA_NDPTR 0x10
+
+#define RC32434_DMA_CHAN_SIZE 0x14
+#define KR_DMA_RXCHAN 0
+#define KR_DMA_TXCHAN 1
+
+#define KR_DMA_READ_REG(chan, reg) \
+ (*(volatile uint32_t *) \
+ (RC32434_DMA_BASE_ADDR + chan * RC32434_DMA_CHAN_SIZE + reg))
+
+#define KR_DMA_WRITE_REG(chan, reg, val) \
+ ((*(volatile uint32_t *) \
+ (RC32434_DMA_BASE_ADDR + chan * RC32434_DMA_CHAN_SIZE + reg)) = val)
+
+#define KR_DMA_SETBITS_REG(chan, reg, bits) \
+ KR_DMA_WRITE_REG((chan), (reg), KR_DMA_READ_REG((chan), (reg)) | (bits))
+
+#define KR_DMA_CLEARBITS_REG(chan, reg, bits) \
+ KR_DMA_WRITE_REG((chan), (reg), \
+ KR_DMA_READ_REG((chan), (reg)) & ~(bits))
+
+struct kr_desc {
+ uint32_t kr_ctl;
+ uint32_t kr_ca;
+ uint32_t kr_devcs;
+ uint32_t kr_link;
+};
+
+
+#define KR_DMASIZE(len) ((len) & ((1 << 18)-1))
+#define KR_PKTSIZE(len) ((len & 0xffff0000) >> 16)
+
+#define KR_CTL_COF 0x02000000
+#define KR_CTL_COD 0x04000000
+#define KR_CTL_IOF 0x08000000
+#define KR_CTL_IOD 0x10000000
+#define KR_CTL_T 0x20000000
+#define KR_CTL_D 0x40000000
+#define KR_CTL_F 0x80000000
+
+#define KR_DMARX_DEVCS_RSV 0x00000001
+#define KR_DMARX_DEVCS_LD 0x00000002
+#define KR_DMARX_DEVCS_ROK 0x00000004
+#define KR_DMARX_DEVCS_FM 0x00000008
+#define KR_DMARX_DEVCS_MP 0x00000010
+#define KR_DMARX_DEVCS_BP 0x00000020
+#define KR_DMARX_DEVCS_VLT 0x00000040
+#define KR_DMARX_DEVCS_CF 0x00000080
+#define KR_DMARX_DEVCS_OVR 0x00000100
+#define KR_DMARX_DEVCS_CRC 0x00000200
+#define KR_DMARX_DEVCS_CV 0x00000400
+#define KR_DMARX_DEVCS_DB 0x00000800
+#define KR_DMARX_DEVCS_LE 0x00001000
+#define KR_DMARX_DEVCS_LOR 0x00002000
+#define KR_DMARX_DEVCS_CES 0x00004000
+
+#define KR_DMATX_DEVCS_FD 0x00000001
+#define KR_DMATX_DEVCS_LD 0x00000002
+#define KR_DMATX_DEVCS_OEN 0x00000004
+#define KR_DMATX_DEVCS_PEN 0x00000008
+#define KR_DMATX_DEVCS_CEN 0x00000010
+#define KR_DMATX_DEVCS_HEN 0x00000020
+#define KR_DMATX_DEVCS_TOK 0x00000040
+#define KR_DMATX_DEVCS_MP 0x00000080
+#define KR_DMATX_DEVCS_BP 0x00000100
+#define KR_DMATX_DEVCS_UND 0x00000200
+#define KR_DMATX_DEVCS_OF 0x00000400
+#define KR_DMATX_DEVCS_ED 0x00000800
+#define KR_DMATX_DEVCS_EC 0x00001000
+#define KR_DMATX_DEVCS_LC 0x00002000
+#define KR_DMATX_DEVCS_TD 0x00004000
+#define KR_DMATX_DEVCS_CRC 0x00008000
+#define KR_DMATX_DEVCS_LE 0x00010000
+
+#define KR_RX_RING_CNT 128
+#define KR_TX_RING_CNT 128
+#define KR_TX_RING_SIZE sizeof(struct kr_desc) * KR_TX_RING_CNT
+#define KR_RX_RING_SIZE sizeof(struct kr_desc) * KR_RX_RING_CNT
+#define KR_RING_ALIGN sizeof(struct kr_desc)
+#define KR_RX_ALIGN sizeof(uint32_t)
+#define KR_MAXFRAGS 8
+#define KR_TX_INTR_THRESH 8
+
+#define KR_TX_RING_ADDR(sc, i) \
+ ((sc)->kr_rdata.kr_tx_ring_paddr + sizeof(struct kr_desc) * (i))
+#define KR_RX_RING_ADDR(sc, i) \
+ ((sc)->kr_rdata.kr_rx_ring_paddr + sizeof(struct kr_desc) * (i))
+#define KR_INC(x,y) (x) = (((x) + 1) % y)
+
+struct kr_txdesc {
+ struct mbuf *tx_m;
+ bus_dmamap_t tx_dmamap;
+};
+
+struct kr_rxdesc {
+ struct mbuf *rx_m;
+ bus_dmamap_t rx_dmamap;
+ struct kr_desc *desc;
+ /* Use this values on error instead of allocating new mbuf */
+ uint32_t saved_ctl, saved_ca;
+};
+
+struct kr_chain_data {
+ bus_dma_tag_t kr_parent_tag;
+ bus_dma_tag_t kr_tx_tag;
+ struct kr_txdesc kr_txdesc[KR_TX_RING_CNT];
+ bus_dma_tag_t kr_rx_tag;
+ struct kr_rxdesc kr_rxdesc[KR_RX_RING_CNT];
+ bus_dma_tag_t kr_tx_ring_tag;
+ bus_dma_tag_t kr_rx_ring_tag;
+ bus_dmamap_t kr_tx_ring_map;
+ bus_dmamap_t kr_rx_ring_map;
+ bus_dmamap_t kr_rx_sparemap;
+ int kr_tx_pkts;
+ int kr_tx_prod;
+ int kr_tx_cons;
+ int kr_tx_cnt;
+ int kr_rx_cons;
+};
+
+struct kr_ring_data {
+ struct kr_desc *kr_rx_ring;
+ struct kr_desc *kr_tx_ring;
+ bus_addr_t kr_rx_ring_paddr;
+ bus_addr_t kr_tx_ring_paddr;
+};
+
+struct kr_softc {
+ struct ifnet *kr_ifp; /* interface info */
+ bus_space_handle_t kr_bhandle; /* bus space handle */
+ bus_space_tag_t kr_btag; /* bus space tag */
+ device_t kr_dev;
+ struct resource *kr_res;
+ int kr_rid;
+ struct resource *kr_rx_irq;
+ void *kr_rx_intrhand;
+ struct resource *kr_tx_irq;
+ void *kr_tx_intrhand;
+ struct resource *kr_rx_und_irq;
+ void *kr_rx_und_intrhand;
+ struct resource *kr_tx_ovr_irq;
+ void *kr_tx_ovr_intrhand;
+ device_t kr_miibus;
+ bus_dma_tag_t kr_parent_tag;
+ bus_dma_tag_t kr_tag;
+ struct mtx kr_mtx;
+ struct callout kr_stat_callout;
+ struct task kr_link_task;
+ struct kr_chain_data kr_cdata;
+ struct kr_ring_data kr_rdata;
+ int kr_link_status;
+ int kr_detach;
+};
+
+#define KR_LOCK(_sc) mtx_lock(&(_sc)->kr_mtx)
+#define KR_UNLOCK(_sc) mtx_unlock(&(_sc)->kr_mtx)
+#define KR_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->kr_mtx, MA_OWNED)
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->kr_btag, sc->kr_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->kr_btag, sc->kr_bhandle, reg)
+
+#endif /* __IF_KRREG_H__ */
diff --git a/sys/mips/idt/obio.c b/sys/mips/idt/obio.c
new file mode 100644
index 0000000..c938f72
--- /dev/null
+++ b/sys/mips/idt/obio.c
@@ -0,0 +1,514 @@
+/*-
+ * Copyright (c) 2007, Oleksandr Tymoshenko <gonzo@freebsd.org>
+ *
+ * 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 for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <mips/mips32/idt/idtreg.h>
+#include <mips/mips32/idt/obiovar.h>
+
+#define ICU_REG_READ(o) \
+ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(IDT_BASE_ICU + (o)))
+#define ICU_REG_WRITE(o,v) (ICU_REG_READ(o)) = (v)
+
+#define GPIO_REG_READ(o) \
+ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(IDT_BASE_GPIO + (o)))
+#define GPIO_REG_WRITE(o,v) (GPIO_REG_READ(o)) = (v)
+
+static int obio_activate_resource(device_t, device_t, int, int,
+ struct resource *);
+static device_t obio_add_child(device_t, int, const char *, int);
+static struct resource *
+ obio_alloc_resource(device_t, device_t, int, int *, u_long,
+ u_long, u_long, u_int);
+static int obio_attach(device_t);
+static int obio_deactivate_resource(device_t, device_t, int, int,
+ struct resource *);
+static struct resource_list *
+ obio_get_resource_list(device_t, device_t);
+static void obio_hinted_child(device_t, const char *, int);
+static int obio_intr(void *);
+static int obio_probe(device_t);
+static int obio_release_resource(device_t, device_t, int, int,
+ struct resource *);
+static int obio_setup_intr(device_t, device_t, struct resource *, int,
+ driver_filter_t *, driver_intr_t *, void *, void **);
+static int obio_teardown_intr(device_t, device_t, struct resource *,
+ void *);
+
+static void obio_mask_irq(unsigned int irq)
+{
+ int ip_bit, mask, mask_register;
+
+ /* mask IRQ */
+ mask_register = ICU_IRQ_MASK_REG(irq);
+ ip_bit = ICU_IP_BIT(irq);
+
+ mask = ICU_REG_READ(mask_register);
+ ICU_REG_WRITE(mask_register, mask | ip_bit);
+}
+
+static void obio_unmask_irq(unsigned int irq)
+{
+ int ip_bit, mask, mask_register;
+
+ /* unmask IRQ */
+ mask_register = ICU_IRQ_MASK_REG(irq);
+ ip_bit = ICU_IP_BIT(irq);
+
+ mask = ICU_REG_READ(mask_register);
+ ICU_REG_WRITE(mask_register, mask & ~ip_bit);
+}
+
+static int
+obio_probe(device_t dev)
+{
+
+ return (0);
+}
+
+static int
+obio_attach(device_t dev)
+{
+ struct obio_softc *sc = device_get_softc(dev);
+ int rid, irq;
+
+ sc->oba_mem_rman.rm_type = RMAN_ARRAY;
+ sc->oba_mem_rman.rm_descr = "OBIO memeory";
+ if (rman_init(&sc->oba_mem_rman) != 0 ||
+ rman_manage_region(&sc->oba_mem_rman, OBIO_MEM_START,
+ OBIO_MEM_START + OBIO_MEM_SIZE) != 0)
+ panic("obio_attach: failed to set up I/O rman");
+
+ sc->oba_irq_rman.rm_type = RMAN_ARRAY;
+ sc->oba_irq_rman.rm_descr = "OBIO IRQ";
+
+ if (rman_init(&sc->oba_irq_rman) != 0 ||
+ rman_manage_region(&sc->oba_irq_rman, IRQ_BASE, IRQ_END) != 0)
+ panic("obio_attach: failed to set up IRQ rman");
+
+ /* Hook up our interrupt handlers. We should handle IRQ0..IRQ4*/
+ for(irq = 0; irq < 5; irq++) {
+ if ((sc->sc_irq[irq] = bus_alloc_resource(dev, SYS_RES_IRQ,
+ &rid, irq, irq, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+ device_printf(dev, "unable to allocate IRQ resource\n");
+ return (ENXIO);
+ }
+
+ if ((bus_setup_intr(dev, sc->sc_irq[irq], INTR_TYPE_MISC,
+ obio_intr, NULL, sc, &sc->sc_ih[irq]))) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ return (ENXIO);
+ }
+ }
+
+ bus_generic_probe(dev);
+ bus_enumerate_hinted_children(dev);
+ bus_generic_attach(dev);
+
+ return (0);
+}
+
+static struct resource *
+obio_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct obio_softc *sc = device_get_softc(bus);
+ struct obio_ivar *ivar = device_get_ivars(child);
+ struct resource *rv;
+ struct resource_list_entry *rle;
+ struct rman *rm;
+ int isdefault, needactivate, passthrough;
+
+ isdefault = (start == 0UL && end == ~0UL);
+ needactivate = flags & RF_ACTIVE;
+ passthrough = (device_get_parent(child) != bus);
+ rle = NULL;
+
+ if (passthrough)
+ return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type,
+ rid, start, end, count, flags));
+
+ /*
+ * If this is an allocation of the "default" range for a given RID,
+ * and we know what the resources for this device are (ie. they aren't
+ * maintained by a child bus), then work out the start/end values.
+ */
+ if (isdefault) {
+ rle = resource_list_find(&ivar->resources, type, *rid);
+ if (rle == NULL)
+ return (NULL);
+ if (rle->res != NULL) {
+ panic("%s: resource entry is busy", __func__);
+ }
+ start = rle->start;
+ end = rle->end;
+ count = rle->count;
+ }
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &sc->oba_irq_rman;
+ break;
+ case SYS_RES_MEMORY:
+ rm = &sc->oba_mem_rman;
+ break;
+ default:
+ printf("%s: unknown resource type %d\n", __func__, type);
+ return (0);
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == 0) {
+ printf("%s: could not reserve resource\n", __func__);
+ return (0);
+ }
+
+ rman_set_rid(rv, *rid);
+
+ if (needactivate) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ printf("%s: could not activate resource\n", __func__);
+ rman_release_resource(rv);
+ return (0);
+ }
+ }
+
+ return (rv);
+}
+
+static int
+obio_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ /* XXX: should we mask/unmask IRQ here? */
+ return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child,
+ type, rid, r));
+}
+
+static int
+obio_deactivate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ /* XXX: should we mask/unmask IRQ here? */
+ return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus), child,
+ type, rid, r));
+}
+
+static int
+obio_release_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r)
+{
+ struct resource_list *rl;
+ struct resource_list_entry *rle;
+
+ rl = obio_get_resource_list(dev, child);
+ if (rl == NULL)
+ return (EINVAL);
+ rle = resource_list_find(rl, type, rid);
+ if (rle == NULL)
+ return (EINVAL);
+ rman_release_resource(r);
+ rle->res = NULL;
+
+ return (0);
+}
+
+static int
+obio_setup_intr(device_t dev, device_t child, struct resource *ires,
+ int flags, driver_filter_t *filt, driver_intr_t *handler,
+ void *arg, void **cookiep)
+{
+ struct obio_softc *sc = device_get_softc(dev);
+ struct intr_event *event;
+ int irq, ip_bit, error, mask, mask_register;
+
+ irq = rman_get_start(ires);
+
+ if (irq >= NIRQS)
+ panic("%s: bad irq %d", __func__, irq);
+
+ event = sc->sc_eventstab[irq];
+ if (event == NULL) {
+ error = intr_event_create(&event, (void *)irq, 0,
+ (mask_fn)obio_mask_irq, (mask_fn)obio_unmask_irq,
+ NULL, NULL,
+ "obio intr%d:", irq);
+
+ sc->sc_eventstab[irq] = event;
+ }
+
+ intr_event_add_handler(event, device_get_nameunit(child), filt,
+ handler, arg, intr_priority(flags), flags, cookiep);
+
+ /* unmask IRQ */
+ mask_register = ICU_IRQ_MASK_REG(irq);
+ ip_bit = ICU_IP_BIT(irq);
+
+ mask = ICU_REG_READ(mask_register);
+ ICU_REG_WRITE(mask_register, mask & ~ip_bit);
+
+ return (0);
+}
+
+static int
+obio_teardown_intr(device_t dev, device_t child, struct resource *ires,
+ void *cookie)
+{
+ struct obio_softc *sc = device_get_softc(dev);
+ int irq, result;
+ uint32_t mask_register, mask, ip_bit;
+
+ irq = rman_get_start(ires);
+ if (irq >= NIRQS)
+ panic("%s: bad irq %d", __func__, irq);
+
+ if (sc->sc_eventstab[irq] == NULL)
+ panic("Trying to teardown unoccupied IRQ");
+
+ /* mask IRQ */
+ mask_register = ICU_IRQ_MASK_REG(irq);
+ ip_bit = ICU_IP_BIT(irq);
+
+ mask = ICU_REG_READ(mask_register);
+ ICU_REG_WRITE(mask_register, mask | ip_bit);
+
+ result = intr_event_remove_handler(cookie);
+ if (!result)
+ sc->sc_eventstab[irq] = NULL;
+
+ return (result);
+}
+
+static int
+obio_intr(void *arg)
+{
+ struct obio_softc *sc = arg;
+ struct intr_event *event;
+ struct intr_handler *ih;
+ uint32_t irqstat, ipend, imask, xpend;
+ int irq, thread, group, i, ret;
+
+ irqstat = 0;
+ irq = 0;
+ for (group = 2; group <= 6; group++) {
+ ipend = ICU_REG_READ(ICU_GROUP_IPEND_REG(group));
+ imask = ICU_REG_READ(ICU_GROUP_MASK_REG(group));
+ xpend = ipend;
+ ipend &= ~imask;
+
+ while ((i = fls(xpend)) != 0) {
+ xpend &= ~(1 << (i - 1));
+ irq = IP_IRQ(group, i - 1);
+ }
+
+ while ((i = fls(ipend)) != 0) {
+ ipend &= ~(1 << (i - 1));
+ irq = IP_IRQ(group, i - 1);
+ event = sc->sc_eventstab[irq];
+ thread = 0;
+#ifndef INTR_FILTER
+ obio_mask_irq(irq);
+#endif
+ if (!event || TAILQ_EMPTY(&event->ie_handlers)) {
+#ifdef INTR_FILTER
+ obio_unmask_irq(irq);
+#endif
+ continue;
+ }
+
+#ifdef INTR_FILTER
+ /* TODO: frame instead of NULL? */
+ intr_event_handle(event, NULL);
+ /* XXX: Log stray IRQs */
+#else
+ /* Execute fast handlers. */
+ TAILQ_FOREACH(ih, &event->ie_handlers,
+ ih_next) {
+ if (ih->ih_filter == NULL)
+ thread = 1;
+ else
+ ret = ih->ih_filter(ih->ih_argument);
+ /*
+ * Wrapper handler special case: see
+ * intr_execute_handlers() in
+ * i386/intr_machdep.c
+ */
+ if (!thread) {
+ if (ret == FILTER_SCHEDULE_THREAD)
+ thread = 1;
+ }
+ }
+
+ /* Schedule thread if needed. */
+ if (thread)
+ intr_event_schedule_thread(event);
+ else
+ obio_unmask_irq(irq);
+ }
+ }
+#endif
+#if 0
+ ipend = ICU_REG_READ(ICU_IPEND2);
+ printf("ipend2 = %08x!\n", ipend);
+
+ ipend = ICU_REG_READ(ICU_IPEND3);
+ printf("ipend3 = %08x!\n", ipend);
+
+ ipend = ICU_REG_READ(ICU_IPEND4);
+ printf("ipend4 = %08x!\n", ipend);
+ ipend = ICU_REG_READ(ICU_IPEND5);
+ printf("ipend5 = %08x!\n", ipend);
+
+ ipend = ICU_REG_READ(ICU_IPEND6);
+ printf("ipend6 = %08x!\n", ipend);
+#endif
+ while (irqstat != 0) {
+ if ((irqstat & 1) == 1) {
+ }
+
+ irq++;
+ irqstat >>= 1;
+ }
+
+ return (FILTER_HANDLED);
+}
+
+static void
+obio_hinted_child(device_t bus, const char *dname, int dunit)
+{
+ device_t child;
+ long maddr;
+ int msize;
+ int irq;
+ int result;
+
+ child = BUS_ADD_CHILD(bus, 0, dname, dunit);
+
+ /*
+ * Set hard-wired resources for hinted child using
+ * specific RIDs.
+ */
+ resource_long_value(dname, dunit, "maddr", &maddr);
+ resource_int_value(dname, dunit, "msize", &msize);
+
+
+ result = bus_set_resource(child, SYS_RES_MEMORY, 0,
+ maddr, msize);
+ if (result != 0)
+ device_printf(bus, "warning: bus_set_resource() failed\n");
+
+ if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
+ result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
+ if (result != 0)
+ device_printf(bus,
+ "warning: bus_set_resource() failed\n");
+ }
+}
+
+static device_t
+obio_add_child(device_t bus, int order, const char *name, int unit)
+{
+ device_t child;
+ struct obio_ivar *ivar;
+
+ ivar = malloc(sizeof(struct obio_ivar), M_DEVBUF, M_WAITOK | M_ZERO);
+ if (ivar == NULL) {
+ printf("Failed to allocate ivar\n");
+ return (0);
+ }
+ resource_list_init(&ivar->resources);
+
+ child = device_add_child_ordered(bus, order, name, unit);
+ if (child == NULL) {
+ printf("Can't add child %s%d ordered\n", name, unit);
+ return (0);
+ }
+
+ device_set_ivars(child, ivar);
+
+ return (child);
+}
+
+/*
+ * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource
+ * Provides pointer to resource_list for these routines
+ */
+static struct resource_list *
+obio_get_resource_list(device_t dev, device_t child)
+{
+ struct obio_ivar *ivar;
+
+ ivar = device_get_ivars(child);
+ return (&(ivar->resources));
+}
+
+static device_method_t obio_methods[] = {
+ DEVMETHOD(bus_activate_resource, obio_activate_resource),
+ DEVMETHOD(bus_add_child, obio_add_child),
+ DEVMETHOD(bus_alloc_resource, obio_alloc_resource),
+ DEVMETHOD(bus_deactivate_resource, obio_deactivate_resource),
+ DEVMETHOD(bus_get_resource_list, obio_get_resource_list),
+ DEVMETHOD(bus_hinted_child, obio_hinted_child),
+ DEVMETHOD(bus_release_resource, obio_release_resource),
+ DEVMETHOD(bus_setup_intr, obio_setup_intr),
+ DEVMETHOD(bus_teardown_intr, obio_teardown_intr),
+ DEVMETHOD(device_attach, obio_attach),
+ DEVMETHOD(device_probe, obio_probe),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+
+ {0, 0},
+};
+
+static driver_t obio_driver = {
+ "obio",
+ obio_methods,
+ sizeof(struct obio_softc),
+};
+static devclass_t obio_devclass;
+
+DRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0);
diff --git a/sys/mips/idt/obiovar.h b/sys/mips/idt/obiovar.h
new file mode 100644
index 0000000..526efac
--- /dev/null
+++ b/sys/mips/idt/obiovar.h
@@ -0,0 +1,67 @@
+/* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 2002, 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * 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 for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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 _ADM5120_OBIOVAR_H_
+#define _ADM5120_OBIOVAR_H_
+
+#include <sys/rman.h>
+
+/* Number of controller's IRQs */
+#define NIRQS 32*5
+
+/* Number of CPU IRQ lines */
+#define MIPS_IRQS 5
+
+#define OBIO_MEM_START 0x18000000L
+#define OBIO_MEM_SIZE 0x200000
+
+struct obio_softc {
+ struct rman oba_mem_rman;
+ struct rman oba_irq_rman;
+ struct intr_event *sc_eventstab[NIRQS]; /* IRQ events structs */
+ struct resource *sc_irq[MIPS_IRQS]; /* IRQ resource */
+ void *sc_ih[MIPS_IRQS]; /* interrupt cookie */
+};
+
+struct obio_ivar {
+ struct resource_list resources;
+};
+
+#endif /* _ADM5120_OBIOVAR_H_ */
diff --git a/sys/mips/idt/std.idt b/sys/mips/idt/std.idt
new file mode 100644
index 0000000..fa067e7
--- /dev/null
+++ b/sys/mips/idt/std.idt
@@ -0,0 +1,5 @@
+# $FreeBSD$
+# Standard include file for IDT
+
+files "../mips32/idt/files.idt"
+options ISA_MIPS32
diff --git a/sys/mips/idt/uart_bus_rc32434.c b/sys/mips/idt/uart_bus_rc32434.c
new file mode 100644
index 0000000..0626b52
--- /dev/null
+++ b/sys/mips/idt/uart_bus_rc32434.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2007 Bruce M. Simpson.
+ * 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
+ * $Id$
+ */
+/*
+ * Skeleton of this file was based on respective code for ARM
+ * code written by Olivier Houchard.
+ */
+
+/*
+ * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is
+ * experimental and was written for MIPS32 port.
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+#include <mips/mips32/idt/idtreg.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <dev/ic/ns16550.h>
+
+#include "uart_if.h"
+
+static int uart_rc32434_probe(device_t dev);
+
+extern struct uart_class uart_rc32434_uart_class;
+
+static device_method_t uart_rc32434_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_rc32434_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_rc32434_driver = {
+ uart_driver_name,
+ uart_rc32434_methods,
+ sizeof(struct uart_softc),
+};
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+
+static int
+uart_rc32434_probe(device_t dev)
+{
+ struct uart_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs);
+ sc->sc_class = &uart_ns8250_class;
+ bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
+ sc->sc_sysdev->bas.regshft = 2;
+ sc->sc_sysdev->bas.bst = 0;
+ sc->sc_sysdev->bas.bsh = MIPS_PHYS_TO_KSEG1(IDT_BASE_UART0);
+ sc->sc_bas.regshft = 2;
+ sc->sc_bas.bst = 0;
+ sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(IDT_BASE_UART0);
+
+ return (uart_bus_probe(dev, 2, 330000000UL/2, 0, 0));
+}
+
+DRIVER_MODULE(uart, obio, uart_rc32434_driver, uart_devclass, 0, 0);
diff --git a/sys/mips/idt/uart_cpu_rc32434.c b/sys/mips/idt/uart_cpu_rc32434.c
new file mode 100644
index 0000000..6bbc5bd
--- /dev/null
+++ b/sys/mips/idt/uart_cpu_rc32434.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@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.
+ *
+ * $Id$
+ */
+/*
+ * Skeleton of this file was based on respective code for ARM
+ * code written by Olivier Houchard.
+ */
+/*
+ * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is
+ * experimental and was written for MIPS32 port.
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+extern struct uart_class uart_rc32434_uart_class;
+bus_space_tag_t uart_bus_space_io;
+bus_space_tag_t uart_bus_space_mem;
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+
+ return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+ uint32_t maddr;
+
+ if (resource_int_value("uart", 0, "maddr", &maddr) != 0 ||
+ maddr == 0)
+ return (ENXIO);
+
+ /* Got it. Fill in the instance and return it. */
+ di->ops = uart_getops(&uart_ns8250_class);
+ di->bas.chan = 0;
+ di->bas.bst = 0;
+ di->bas.regshft = 2;
+ di->bas.rclk = 330000000UL/2; /* IPbus clock */
+ di->baudrate = 115200;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+ uart_bus_space_io = 0;
+ uart_bus_space_mem = 0;
+ di->bas.bsh = MIPS_PHYS_TO_KSEG1(maddr);
+ return (0);
+}
OpenPOWER on IntegriCloud