summaryrefslogtreecommitdiffstats
path: root/sys/mips/idt
diff options
context:
space:
mode:
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