summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgonzo <gonzo@FreeBSD.org>2009-04-14 22:53:22 +0000
committergonzo <gonzo@FreeBSD.org>2009-04-14 22:53:22 +0000
commit821d317cbea839f0d98a13b4d1b444ec15b7dd16 (patch)
tree947489fdb684e228bb2ae3c4d68c2cf3606fddbf
parent16b2e4b851fc13d49105bf544ef5f7d89526ed3a (diff)
downloadFreeBSD-src-821d317cbea839f0d98a13b4d1b444ec15b7dd16.zip
FreeBSD-src-821d317cbea839f0d98a13b4d1b444ec15b7dd16.tar.gz
- Revert changes accidentally killed by merge operation
-rw-r--r--sys/conf/Makefile.mips48
-rw-r--r--sys/conf/files.mips4
-rw-r--r--sys/conf/ldscript.mips2
-rw-r--r--sys/dev/siba/siba_cc.c (renamed from sys/mips/sentry5/siba_cc.c)0
-rw-r--r--sys/dev/siba/siba_mips.c (renamed from sys/mips/sentry5/siba_mips.c)0
-rw-r--r--sys/dev/siba/siba_sdram.c (renamed from sys/mips/sentry5/siba_sdram.c)0
-rw-r--r--sys/mips/alchemy/alchemy_machdep.c157
-rw-r--r--sys/mips/alchemy/aureg.h373
-rw-r--r--sys/mips/alchemy/files.alchemy7
-rw-r--r--sys/mips/alchemy/obio.c501
-rw-r--r--sys/mips/alchemy/std.alchemy8
-rw-r--r--sys/mips/alchemy/uart_bus_alchemy.c87
-rw-r--r--sys/mips/alchemy/uart_cpu_alchemy.c79
-rw-r--r--sys/mips/atheros/apb.c433
-rw-r--r--sys/mips/atheros/apbvar.h48
-rw-r--r--sys/mips/atheros/ar71xx_machdep.c161
-rw-r--r--sys/mips/atheros/ar71xx_ohci.c205
-rw-r--r--sys/mips/atheros/ar71xx_pci.c429
-rw-r--r--sys/mips/atheros/ar71xxreg.h317
-rw-r--r--sys/mips/atheros/files.ar71xx9
-rw-r--r--sys/mips/atheros/if_arge.c1657
-rw-r--r--sys/mips/atheros/if_argevar.h138
-rw-r--r--sys/mips/atheros/uart_bus_ar71xx.c79
-rw-r--r--sys/mips/atheros/uart_cpu_ar71xx.c78
-rw-r--r--sys/mips/conf/ADM51201
-rw-r--r--sys/mips/conf/ALCHEMY66
-rw-r--r--sys/mips/conf/AR71XX37
-rw-r--r--sys/mips/conf/AR71XX.hints25
-rw-r--r--sys/mips/conf/MALTA1
-rw-r--r--sys/mips/conf/QEMU1
-rw-r--r--sys/mips/conf/SENTRY511
-rw-r--r--sys/mips/include/bus.h5
-rw-r--r--sys/mips/mips/elf_machdep.c3
-rw-r--r--sys/mips/mips/elf_trampoline.c133
-rw-r--r--sys/mips/mips/inckern.S34
-rw-r--r--sys/mips/mips/nexus.c39
-rw-r--r--sys/mips/sentry5/files.sentry57
37 files changed, 5146 insertions, 37 deletions
diff --git a/sys/conf/Makefile.mips b/sys/conf/Makefile.mips
index 443065a..e03432c 100644
--- a/sys/conf/Makefile.mips
+++ b/sys/conf/Makefile.mips
@@ -28,35 +28,73 @@ S= ../../..
.endif
.include "$S/conf/kern.pre.mk"
+SYSTEM_LD:= ${SYSTEM_LD:$S/conf/ldscript.$M=ldscript.$M}
+SYSTEM_DEP:= ${SYSTEM_DEP:$S/conf/ldscript.$M=ldscript.$M}
+
# XXX: Such sweeping assumptions...
MACHINE=mips
MACHINE_ARCH=mips
+KERNLOADADDR?=0x80001000
+# This obscure value is defined by CFE for WR160N
+# To be changed later
+TRAMPLOADADDR?=0x807963c0
MKMODULESENV+= MACHINE=${MACHINE} MACHINE_ARCH=${MACHINE_ARCH}
# We default to the MIPS32 ISA, if none specified in the
# kernel configuration file.
ARCH_FLAGS?=-march=mips32
+EXTRA_FLAGS=-fno-pic -mno-abicalls -mno-dsp -G0
HACK_EXTRA_FLAGS=-shared
.if defined(TARGET_BIG_ENDIAN)
CFLAGS+=-EB
SYSTEM_LD+=-EB
+EXTRA_FLAGS+=-EB
+TRAMP_LDFLAGS+=-Wl,-EB
HACK_EXTRA_FLAGS+=-EB -Wl,-EB
.else
CFLAGS+=-EL
SYSTEM_LD+=-EL
+EXTRA_FLAGS+=-EL
+TRAMP_LDFLAGS+=-Wl,-EL
HACK_EXTRA_FLAGS+=-EL -Wl,-EL
.endif
# We add the -fno-pic flag to kernels because otherwise performance
# is extremely poor, as well as -mno-abicalls to force no ABI usage.
-CFLAGS+=-fno-pic -mno-abicalls -G0 $(ARCH_FLAGS)
-HACK_EXTRA_FLAGS+=-fno-pic -mno-abicalls -G0 $(ARCH_FLAGS)
+CFLAGS+=${EXTRA_FLAGS} $(ARCH_FLAGS)
+HACK_EXTRA_FLAGS+=${EXTRA_FLAGS} $(ARCH_FLAGS)
# XXX hardcoded kernel entry point
ASM_CFLAGS+=${CFLAGS} -D_LOCORE -DLOCORE
+KERNEL_EXTRA=trampoline
+trampoline: ${KERNEL_KO}.tramp.bin
+${KERNEL_KO}.tramp.bin: ${KERNEL_KO} $S/$M/$M/elf_trampoline.c \
+ $S/$M/$M/inckern.S
+ ${OBJCOPY} --strip-symbol '$$d' --strip-symbol '$$a' \
+ -g --strip-symbol '$$t' ${FULLKERNEL} ${KERNEL_KO}.tmp
+ sed s/${KERNLOADADDR}/${TRAMPLOADADDR}/ ldscript.$M | \
+ sed s/" + SIZEOF_HEADERS"// > ldscript.$M.tramp.noheader
+ # Generate .S file that setups stack and jumps to trampoline
+ echo "#include <machine/asm.h>" >tmphack.S
+ echo "ENTRY(_start)" >>tmphack.S
+ echo "la t0, kernel_end" >>tmphack.S
+ echo "move sp, t0" >>tmphack.S
+ echo "add sp, 0x2000" >>tmphack.S
+ echo "and sp, ~0x7" >>tmphack.S
+ echo "la t0, _startC" >>tmphack.S
+ echo "j t0" >>tmphack.S
+ echo "END(_start)" >>tmphack.S
+ echo "#define KERNNAME \"${KERNEL_KO}.tmp\"" >opt_kernname.h
+ ${CC} -O -nostdlib -I. -I$S ${EXTRA_FLAGS} ${TRAMP_LDFLAGS} -Xlinker \
+ -T -Xlinker ldscript.$M.tramp.noheader tmphack.S \
+ $S/$M/$M/elf_trampoline.c $S/$M/$M/inckern.S \
+ -o ${KERNEL_KO}.tramp.noheader
+ ${OBJCOPY} -S -O binary ${KERNEL_KO}.tramp.noheader \
+ ${KERNEL_KO}.tramp.bin \
+
%BEFORE_DEPEND
%OBJS
@@ -69,6 +107,12 @@ ASM_CFLAGS+=${CFLAGS} -D_LOCORE -DLOCORE
%CLEAN
+CLEAN+= ldscript.$M ldscript.$M.tramp.noheader \
+ ${KERNEL_KO}.tramp.noheader ${KERNEL_KO}.tramp.bin
+
+ldscript.$M: $S/conf/ldscript.$M
+ cat $S/conf/ldscript.$M|sed s/KERNLOADADDR/${KERNLOADADDR}/g \
+ > ldscript.$M
%RULES
.include "$S/conf/kern.post.mk"
diff --git a/sys/conf/files.mips b/sys/conf/files.mips
index 1e233d7..bbedd96 100644
--- a/sys/conf/files.mips
+++ b/sys/conf/files.mips
@@ -96,3 +96,7 @@ dev/cfe/cfe_api.c optional cfe
dev/cfe/cfe_console.c optional cfe_console
#dev/cfe/cfe_resource.c optional cfe # not yet needed
+dev/siba/siba.c optional siba
+dev/siba/siba_pcib.c optional siba pci
+dev/siba/siba_cc.c optional siba
+#mips/sentry5/siba_mips.c optional siba # not yet
diff --git a/sys/conf/ldscript.mips b/sys/conf/ldscript.mips
index ca4a70b..3e55dba 100644
--- a/sys/conf/ldscript.mips
+++ b/sys/conf/ldscript.mips
@@ -43,7 +43,7 @@ PROVIDE (_DYNAMIC = 0);
SECTIONS
{
/* Read-only sections, merged into text segment: */
- . = 0x80100000 + SIZEOF_HEADERS;
+ . = KERNLOADADDR + SIZEOF_HEADERS;
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
diff --git a/sys/mips/sentry5/siba_cc.c b/sys/dev/siba/siba_cc.c
index cd78f0b..cd78f0b 100644
--- a/sys/mips/sentry5/siba_cc.c
+++ b/sys/dev/siba/siba_cc.c
diff --git a/sys/mips/sentry5/siba_mips.c b/sys/dev/siba/siba_mips.c
index 676da83..676da83 100644
--- a/sys/mips/sentry5/siba_mips.c
+++ b/sys/dev/siba/siba_mips.c
diff --git a/sys/mips/sentry5/siba_sdram.c b/sys/dev/siba/siba_sdram.c
index 8e74e53..8e74e53 100644
--- a/sys/mips/sentry5/siba_sdram.c
+++ b/sys/dev/siba/siba_sdram.c
diff --git a/sys/mips/alchemy/alchemy_machdep.c b/sys/mips/alchemy/alchemy_machdep.c
new file mode 100644
index 0000000..eca9b18
--- /dev/null
+++ b/sys/mips/alchemy/alchemy_machdep.c
@@ -0,0 +1,157 @@
+/*-
+ * 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.
+ *
+ */
+
+#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;
+
+static void
+mips_init(void)
+{
+ int i;
+
+ printf("entry: mips_init()\n");
+
+ bootverbose = 1;
+ realmem = btoc(16 << 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;
+
+ init_param1();
+ init_param2(physmem);
+ mips_cpu_init();
+ pmap_bootstrap();
+ mips_proc0_init();
+ mutex_init();
+#ifdef DDB
+ kdb_init();
+#endif
+}
+
+void
+platform_halt(void)
+{
+
+}
+
+
+void
+platform_identify(void)
+{
+
+}
+
+void
+platform_reset(void)
+{
+
+ __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 __unused, __register_t a1 __unused,
+ __register_t a2 __unused, __register_t a3 __unused)
+{
+ vm_offset_t kernend;
+ uint64_t platform_counter_freq = 175 * 1000 * 1000;
+
+ /* clear the BSS and SBSS segments */
+ kernend = round_page((vm_offset_t)&end);
+ memset(&edata, 0, kernend - (vm_offset_t)(&edata));
+
+ cninit();
+ mips_init();
+ /* Set counter_freq for tick_init_params() */
+ platform_counter_freq = 175 * 1000 * 1000;
+
+ mips_timer_init_params(platform_counter_freq, 0);
+}
diff --git a/sys/mips/alchemy/aureg.h b/sys/mips/alchemy/aureg.h
new file mode 100644
index 0000000..dfa2103
--- /dev/null
+++ b/sys/mips/alchemy/aureg.h
@@ -0,0 +1,373 @@
+/* $NetBSD: aureg.h,v 1.18 2006/10/02 06:44:00 gdamore Exp $ */
+
+/*
+ * Copyright 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Simon Burge 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.
+ */
+
+#ifndef _MIPS_ALCHEMY_AUREG_H
+#define _MIPS_ALCHEMY_AUREG_H
+
+/************************************************************************/
+/******************** AC97 Controller registers *********************/
+/************************************************************************/
+#define AC97_BASE 0x10000000
+
+/************************************************************************/
+/*********************** USB Host registers *************************/
+/************************************************************************/
+#define USBH_BASE 0x10100000
+#define AU1550_USBH_BASE 0x14020000
+
+#define USBH_ENABLE 0x7fffc
+#define USBH_SIZE 0x100000
+
+#define AU1550_USBH_ENABLE 0x7ffc
+#define AU1550_USBH_SIZE 0x60000
+
+/************************************************************************/
+/********************** USB Device registers ************************/
+/************************************************************************/
+#define USBD_BASE 0x10200000
+
+/************************************************************************/
+/************************* IRDA registers ***************************/
+/************************************************************************/
+#define IRDA_BASE 0x10300000
+
+/************************************************************************/
+/****************** Interrupt Controller registers ******************/
+/************************************************************************/
+
+#define IC0_BASE 0x10400000
+#define IC1_BASE 0x11800000
+
+/*
+ * The *_READ registers read the current value of the register
+ * The *_SET registers set to 1 all bits that are written 1
+ * The *_CLEAR registers clear to zero all bits that are written as 1
+ */
+#define IC_CONFIG0_READ 0x40 /* See table below */
+#define IC_CONFIG0_SET 0x40
+#define IC_CONFIG0_CLEAR 0x44
+
+#define IC_CONFIG1_READ 0x48 /* See table below */
+#define IC_CONFIG1_SET 0x48
+#define IC_CONFIG1_CLEAR 0x4c
+
+#define IC_CONFIG2_READ 0x50 /* See table below */
+#define IC_CONFIG2_SET 0x50
+#define IC_CONFIG2_CLEAR 0x54
+
+#define IC_REQUEST0_INT 0x54 /* Show active interrupts on request 0 */
+
+#define IC_SOURCE_READ 0x58 /* Interrupt source */
+#define IC_SOURCE_SET 0x58 /* 0 - test bit used as source */
+#define IC_SOURCE_CLEAR 0x5c /* 1 - peripheral/GPIO used as source */
+
+#define IC_REQUEST1_INT 0x5c /* Show active interrupts on request 1 */
+
+#define IC_ASSIGN_REQUEST_READ 0x60 /* Assigns the interrupt to one of the */
+#define IC_ASSIGN_REQUEST_SET 0x60 /* CPU requests (0 - assign to request 1, */
+#define IC_ASSIGN_REQUEST_CLEAR 0x64 /* 1 - assign to request 0) */
+
+#define IC_WAKEUP_READ 0x68 /* Controls whether the interrupt can */
+#define IC_WAKEUP_SET 0x68 /* cause a wakeup from IDLE */
+#define IC_WAKEUP_CLEAR 0x6c
+
+#define IC_MASK_READ 0x70 /* Enables/Disables the interrupt */
+#define IC_MASK_SET 0x70
+#define IC_MASK_CLEAR 0x74
+
+#define IC_RISING_EDGE 0x78 /* Check/clear rising edge */
+
+#define IC_FALLING_EDGE 0x7c /* Check/clear falling edge */
+
+#define IC_TEST_BIT 0x80 /* single bit source select */
+
+/*
+ * Interrupt Configuration Register Functions
+ *
+ * Cfg2[n] Cfg1[n] Cfg0[n] Function
+ * 0 0 0 Interrupts Disabled
+ * 0 0 1 Rising Edge Enabled
+ * 0 1 0 Falling Edge Enabled
+ * 0 1 1 Rising and Falling Edge Enabled
+ * 1 0 0 Interrupts Disabled
+ * 1 0 1 High Level Enabled
+ * 1 1 0 Low Level Enabled
+ * 1 1 1 Both Levels and Both Edges Enabled
+ */
+
+/************************************************************************/
+/************* Programable Serial Controller registers **************/
+/************************************************************************/
+
+#define PSC0_BASE 0x11A00000
+#define PSC1_BASE 0x11B00000
+#define PSC2_BASE 0x10A00000
+#define PSC3_BASE 0x10B00000
+
+
+/************************************************************************/
+/********************** Ethernet MAC registers **********************/
+/************************************************************************/
+
+#define MAC0_BASE 0x10500000
+#define MAC1_BASE 0x10510000
+#define MACx_SIZE 0x28
+
+#define AU1500_MAC0_BASE 0x11500000 /* Grr, different on Au1500 */
+#define AU1500_MAC1_BASE 0x11510000 /* Grr, different on Au1500 */
+
+#define MAC0_ENABLE 0x10520000
+#define MAC1_ENABLE 0x10520004
+#define MACENx_SIZE 0x04
+
+#define AU1500_MAC0_ENABLE 0x11520000 /* Grr, different on Au1500 */
+#define AU1500_MAC1_ENABLE 0x11520004 /* Grr, different on Au1500 */
+
+#define MAC0_DMA_BASE 0x14004000
+#define MAC1_DMA_BASE 0x14004200
+#define MACx_DMA_SIZE 0x140
+
+/************************************************************************/
+/********************** Static Bus registers ************************/
+/************************************************************************/
+#define STATIC_BUS_BASE 0x14001000
+
+/************************************************************************/
+/******************** Secure Digital registers **********************/
+/************************************************************************/
+#define SD0_BASE 0x10600000
+#define SD1_BASE 0x10680000
+
+/************************************************************************/
+/************************* I^2S registers ***************************/
+/************************************************************************/
+#define I2S_BASE 0x11000000
+
+/************************************************************************/
+/************************** UART registers **************************/
+/************************************************************************/
+
+#define UART0_BASE 0x11100000
+#define UART1_BASE 0x11200000
+#define UART2_BASE 0x11300000
+#define UART3_BASE 0x11400000
+
+/************************************************************************/
+/************************* SSI registers ****************************/
+/************************************************************************/
+#define SSI0_BASE 0x11600000
+#define SSI1_BASE 0x11680000
+
+/************************************************************************/
+/************************ GPIO2 registers ***************************/
+/************************************************************************/
+#define GPIO_BASE 0x11900100
+
+/************************************************************************/
+/************************ GPIO2 registers ***************************/
+/************************************************************************/
+#define GPIO2_BASE 0x11700000
+
+/************************************************************************/
+/************************* PCI registers ****************************/
+/************************************************************************/
+#define PCI_BASE 0x14005000
+#define PCI_HEADER 0x14005100
+#define PCI_MEM_BASE 0x400000000ULL
+#define PCI_IO_BASE 0x500000000ULL
+#define PCI_CONFIG_BASE 0x600000000ULL
+
+/************************************************************************/
+/*********************** PCMCIA registers ***************************/
+/************************************************************************/
+#define PCMCIA_BASE 0xF00000000ULL
+
+/************************************************************************/
+/****************** Programmable Counter registers ******************/
+/************************************************************************/
+
+#define SYS_BASE 0x11900000
+
+#define PC_BASE SYS_BASE
+
+#define PC_TRIM0 0x00 /* PC0 Divide (16 bits) */
+#define PC_COUNTER_WRITE0 0x04 /* set PC0 */
+#define PC_MATCH0_0 0x08 /* match counter & interrupt */
+#define PC_MATCH1_0 0x0c /* match counter & interrupt */
+#define PC_MATCH2_0 0x10 /* match counter & interrupt */
+#define PC_COUNTER_CONTROL 0x14 /* Programmable Counter Control */
+#define CC_E1S 0x00800000 /* Enable PC1 write status */
+#define CC_T1S 0x00100000 /* Trim PC1 write status */
+#define CC_M21 0x00080000 /* Match 2 of PC1 write status */
+#define CC_M11 0x00040000 /* Match 1 of PC1 write status */
+#define CC_M01 0x00020000 /* Match 0 of PC1 write status */
+#define CC_C1S 0x00010000 /* PC1 write status */
+#define CC_BP 0x00004000 /* Bypass OSC (use GPIO1) */
+#define CC_EN1 0x00002000 /* Enable PC1 */
+#define CC_BT1 0x00001000 /* Bypass Trim on PC1 */
+#define CC_EN0 0x00000800 /* Enable PC0 */
+#define CC_BT0 0x00000400 /* Bypass Trim on PC0 */
+#define CC_EO 0x00000100 /* Enable Oscillator */
+#define CC_E0S 0x00000080 /* Enable PC0 write status */
+#define CC_32S 0x00000020 /* 32.768kHz OSC status */
+#define CC_T0S 0x00000010 /* Trim PC0 write status */
+#define CC_M20 0x00000008 /* Match 2 of PC0 write status */
+#define CC_M10 0x00000004 /* Match 1 of PC0 write status */
+#define CC_M00 0x00000002 /* Match 0 of PC0 write status */
+#define CC_C0S 0x00000001 /* PC0 write status */
+#define PC_COUNTER_READ_0 0x40 /* get PC0 */
+#define PC_TRIM1 0x44 /* PC1 Divide (16 bits) */
+#define PC_COUNTER_WRITE1 0x48 /* set PC1 */
+#define PC_MATCH0_1 0x4c /* match counter & interrupt */
+#define PC_MATCH1_1 0x50 /* match counter & interrupt */
+#define PC_MATCH2_1 0x54 /* match counter & interrupt */
+#define PC_COUNTER_READ_1 0x58 /* get PC1 */
+
+#define PC_SIZE 0x5c /* size of register set */
+#define PC_RATE 32768 /* counter rate is 32.768kHz */
+
+/************************************************************************/
+/******************* Frequency Generator Registers ******************/
+/************************************************************************/
+
+#define SYS_FREQCTRL0 (SYS_BASE + 0x20)
+#define SFC_FRDIV2(f) (f<<22) /* 29:22. Freq Divider 2 */
+#define SFC_FE2 (1<<21) /* Freq generator output enable 2 */
+#define SFC_FS2 (1<<20) /* Freq generator source 2 */
+#define SFC_FRDIV1(f) (f<<12) /* 19:12. Freq Divider 1 */
+#define SFC_FE1 (1<<11) /* Freq generator output enable 1 */
+#define SFC_FS1 (1<<10) /* Freq generator source 1 */
+#define SFC_FRDIV0(f) (f<<2) /* 9:2. Freq Divider 0 */
+#define SFC_FE0 2 /* Freq generator output enable 0 */
+#define SFC_FS0 1 /* Freq generator source 0 */
+
+#define SYS_FREQCTRL1 (SYS_BASE + 0x24)
+#define SFC_FRDIV5(f) (f<<22) /* 29:22. Freq Divider 5 */
+#define SFC_FE5 (1<<21) /* Freq generator output enable 5 */
+#define SFC_FS5 (1<<20) /* Freq generator source 5 */
+#define SFC_FRDIV4(f) (f<<12) /* 19:12. Freq Divider 4 */
+#define SFC_FE4 (1<<11) /* Freq generator output enable 4 */
+#define SFC_FS4 (1<<10) /* Freq generator source 4 */
+#define SFC_FRDIV3(f) (f<<2) /* 9:2. Freq Divider 3 */
+#define SFC_FE3 2 /* Freq generator output enable 3 */
+#define SFC_FS3 1 /* Freq generator source 3 */
+
+/************************************************************************/
+/****************** Clock Source Control Registers ******************/
+/************************************************************************/
+
+#define SYS_CLKSRC (SYS_BASE + 0x28)
+#define SCS_ME1(n) (n<<27) /* EXTCLK1 Clock Mux input select */
+#define SCS_ME0(n) (n<<22) /* EXTCLK0 Clock Mux input select */
+#define SCS_MPC(n) (n<<17) /* PCI clock mux input select */
+#define SCS_MUH(n) (n<<12) /* USB Host clock mux input select */
+#define SCS_MUD(n) (n<<7) /* USB Device clock mux input select */
+#define SCS_MEx_AUX 0x1 /* Aux clock */
+#define SCS_MEx_FREQ0 0x2 /* FREQ0 */
+#define SCS_MEx_FREQ1 0x3 /* FREQ1 */
+#define SCS_MEx_FREQ2 0x4 /* FREQ2 */
+#define SCS_MEx_FREQ3 0x5 /* FREQ3 */
+#define SCS_MEx_FREQ4 0x6 /* FREQ4 */
+#define SCS_MEx_FREQ5 0x7 /* FREQ5 */
+#define SCS_DE1 (1<<26) /* EXTCLK1 clock divider select */
+#define SCS_CE1 (1<<25) /* EXTCLK1 clock select */
+#define SCS_DE0 (1<<21) /* EXTCLK0 clock divider select */
+#define SCS_CE0 (1<<20) /* EXTCLK0 clock select */
+#define SCS_DPC (1<<16) /* PCI clock divider select */
+#define SCS_CPC (1<<15) /* PCI clock select */
+#define SCS_DUH (1<<11) /* USB Host clock divider select */
+#define SCS_CUH (1<<10) /* USB Host clock select */
+#define SCS_DUD (1<<6) /* USB Device clock divider select */
+#define SCS_CUD (1<<5) /* USB Device clock select */
+/*
+ * Au1550 bits, needed for PSCs. Note that some bits collide with
+ * earlier parts. On Au1550, USB clocks (both device and host) are
+ * shared with PSC2, and must be configured for 48MHz. DBAU1550 YAMON
+ * does this by default. Also, EXTCLK0 is shared with PSC3. DBAU1550
+ * YAMON does not configure any clocks besides PSC2.
+ */
+#define SCS_MP3(n) (n<<22) /* psc3_intclock mux */
+#define SCS_DP3 (1<<21) /* psc3_intclock divider */
+#define SCS_CP3 (1<<20) /* psc3_intclock select */
+#define SCS_MP1(n) (n<<12) /* psc1_intclock mux */
+#define SCS_DP1 (1<<11) /* psc1_intclock divider */
+#define SCS_CP1 (1<<10) /* psc1_intclock select */
+#define SCS_MP0(n) (n<<7) /* psc0_intclock mux */
+#define SCS_DP0 (1<<6) /* psc0_intclock divider */
+#define SCS_CP0 (1<<5) /* psc0_intclock seelct */
+#define SCS_MP2(n) (n<<2) /* psc2_intclock mux */
+#define SCS_DP2 (1<<1) /* psc2_intclock divider */
+#define SCS_CP2 (1<<0) /* psc2_intclock select */
+
+/************************************************************************/
+/*************************** PIN Function *****************************/
+/************************************************************************/
+
+#define SYS_PINFUNC (SYS_BASE + 0x2c)
+#define SPF_PSC3_MASK (7<<20)
+#define SPF_PSC3_AC97 (0<<17) /* select AC97/SPI */
+#define SPF_PSC3_I2S (1<<17) /* select I2S */
+#define SPF_PSC3_SMBUS (3<<17) /* select SMbus */
+#define SPF_PSC3_GPIO (7<<17) /* select gpio215:211 */
+#define SPF_PSC2_MASK (7<<17)
+#define SPF_PSC2_AC97 (0<<17) /* select AC97/SPI */
+#define SPF_PSC2_I2S (1<<17) /* select I2S */
+#define SPF_PSC2_SMBUS (3<<17) /* select SMbus */
+#define SPF_PSC2_GPIO (7<<17) /* select gpio210:206*/
+#define SPF_CS (1<<16) /* extclk0 or 32kHz osc */
+#define SPF_USB (1<<15) /* host or device usb otg */
+#define SPF_U3T (1<<14) /* uart3 tx or gpio23 */
+#define SPF_U1R (1<<13) /* uart1 rx or gpio22 */
+#define SPF_U1T (1<<12) /* uart1 tx or gpio21 */
+#define SPF_EX1 (1<<10) /* gpio3 or extclk1 */
+#define SPF_EX0 (1<<9) /* gpio2 or extclk0/32kHz osc*/
+#define SPF_U3 (1<<7) /* gpio14:9 or uart3 */
+#define SPF_MBSa (1<<5) /* must be set */
+#define SPF_NI2 (1<<4) /* enet1 or gpio28:24 */
+#define SPF_U0 (1<<3) /* uart0 or gpio20 */
+#define SPF_MBSb (1<<2) /* must be set */
+#define SPF_S1 (1<<1) /* gpio17 or psc1_sync1 */
+#define SPF_S0 (1<<0) /* gpio16 or psc0_sync1 */
+
+/************************************************************************/
+/*************************** PLL Control *****************************/
+/************************************************************************/
+
+#define SYS_CPUPLL (SYS_BASE + 0x60)
+#define SYS_AUXPLL (SYS_BASE + 0x64)
+
+#endif /* _MIPS_ALCHEMY_AUREG_H */
diff --git a/sys/mips/alchemy/files.alchemy b/sys/mips/alchemy/files.alchemy
new file mode 100644
index 0000000..8534431
--- /dev/null
+++ b/sys/mips/alchemy/files.alchemy
@@ -0,0 +1,7 @@
+# $FreeBSD$
+# Alchmy on-board devices
+# mips/alchemy/console.c standard
+mips/alchemy/alchemy_machdep.c standard
+mips/alchemy/obio.c standard
+mips/alchemy/uart_bus_alchemy.c optional uart
+mips/alchemy/uart_cpu_alchemy.c optional uart
diff --git a/sys/mips/alchemy/obio.c b/sys/mips/alchemy/obio.c
new file mode 100644
index 0000000..03e098d
--- /dev/null
+++ b/sys/mips/alchemy/obio.c
@@ -0,0 +1,501 @@
+/* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */
+
+/*-
+ * Copyright (c) 2001, 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.
+ */
+
+#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/adm5120/adm5120reg.h>
+#include <mips/adm5120/obiovar.h>
+
+/* MIPS HW interrupts of IRQ/FIQ respectively */
+#define ADM5120_INTR 0
+#define ADM5120_FAST_INTR 1
+
+/* Interrupt levels */
+#define INTR_IRQ 0
+#define INTR_FIQ 1
+
+int irq_priorities[NIRQS] = {
+ INTR_IRQ, /* flash */
+ INTR_FIQ, /* uart0 */
+ INTR_FIQ, /* uart1 */
+ INTR_IRQ, /* ahci */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* admsw */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+};
+
+
+#define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(ADM5120_BASE_ICU + (o)))
+#define REG_WRITE(o,v) (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 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;
+
+ 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, 0, NIRQS-1) != 0)
+ panic("obio_attach: failed to set up IRQ rman");
+
+ /* Hook up our interrupt handler. */
+ if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ ADM5120_INTR, ADM5120_INTR, 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, INTR_TYPE_MISC, obio_intr, NULL,
+ sc, &sc->sc_ih))) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ return (ENXIO);
+ }
+
+ /* Hook up our FAST interrupt handler. */
+ if ((sc->sc_fast_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ ADM5120_FAST_INTR, ADM5120_FAST_INTR, 1,
+ RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+ device_printf(dev, "unable to allocate IRQ resource\n");
+ return (ENXIO);
+ }
+
+ if ((bus_setup_intr(dev, sc->sc_fast_irq, INTR_TYPE_MISC, obio_intr,
+ NULL, sc, &sc->sc_fast_ih))) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ return (ENXIO);
+ }
+
+ /* disable all interrupts */
+ REG_WRITE(ICU_ENABLE_REG, ICU_INT_MASK);
+
+ 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 && count == 1);
+ 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)
+{
+
+ /*
+ * If this is a memory resource, track the direct mapping
+ * in the uncached MIPS KSEG1 segment.
+ */
+ if (type == SYS_RES_MEMORY) {
+ void *vaddr;
+
+ vaddr = (void *)MIPS_PHYS_TO_KSEG1((intptr_t)rman_get_start(r));
+ rman_set_virtual(r, vaddr);
+ rman_set_bustag(r, MIPS_BUS_SPACE_MEM);
+ rman_set_bushandle(r, (bus_space_handle_t)vaddr);
+ }
+
+ return (rman_activate_resource(r));
+}
+
+static int
+obio_deactivate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ return (rman_deactivate_resource(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, error, priority;
+ uint32_t irqmask;
+
+ 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, irq,
+ (mask_fn)mips_mask_irq, (mask_fn)mips_unmask_irq,
+ NULL, NULL, "obio intr%d:", irq);
+
+ sc->sc_eventstab[irq] = event;
+ }
+ else
+ panic("obio: Can't share IRQs");
+
+ intr_event_add_handler(event, device_get_nameunit(child), filt,
+ handler, arg, intr_priority(flags), flags, cookiep);
+
+ irqmask = 1 << irq;
+ priority = irq_priorities[irq];
+
+ if (priority == INTR_FIQ)
+ REG_WRITE(ICU_MODE_REG, REG_READ(ICU_MODE_REG) | irqmask);
+ else
+ REG_WRITE(ICU_MODE_REG, REG_READ(ICU_MODE_REG) & ~irqmask);
+
+ /* enable */
+ REG_WRITE(ICU_ENABLE_REG, irqmask);
+
+ 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 irqmask;
+
+ 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");
+
+ irqmask = 1 << irq; /* only used as a mask from here on */
+
+ /* disable this irq in HW */
+ REG_WRITE(ICU_DISABLE_REG, irqmask);
+
+ 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;
+ uint32_t irqstat;
+ int irq;
+
+ irqstat = REG_READ(ICU_FIQ_STATUS_REG);
+ irqstat |= REG_READ(ICU_STATUS_REG);
+
+ irq = 0;
+ while (irqstat != 0) {
+ if ((irqstat & 1) == 1) {
+ event = sc->sc_eventstab[irq];
+ if (!event || TAILQ_EMPTY(&event->ie_handlers))
+ continue;
+
+ /* TODO: pass frame as an argument*/
+ /* TODO: log stray interrupt */
+ intr_event_handle(event, NULL);
+ }
+
+ 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/alchemy/std.alchemy b/sys/mips/alchemy/std.alchemy
new file mode 100644
index 0000000..a955b67
--- /dev/null
+++ b/sys/mips/alchemy/std.alchemy
@@ -0,0 +1,8 @@
+# $FreeBSD$
+# Standard include file for Alchemy Au1xxx CPUs:
+# Au1000, Au1200, Au1250, Au1500 and Au1550
+
+files "../alchemy/files.alchemy"
+
+cpu CPU_MIPS4KC
+options ISA_MIPS32
diff --git a/sys/mips/alchemy/uart_bus_alchemy.c b/sys/mips/alchemy/uart_bus_alchemy.c
new file mode 100644
index 0000000..5c2315b
--- /dev/null
+++ b/sys/mips/alchemy/uart_bus_alchemy.c
@@ -0,0 +1,87 @@
+/*-
+ * 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.
+ */
+
+#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 <dev/pci/pcivar.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <mips/alchemy/aureg.h>
+
+#include "uart_if.h"
+
+static int uart_alchemy_probe(device_t dev);
+
+static device_method_t uart_alchemy_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_alchemy_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_alchemy_driver = {
+ uart_driver_name,
+ uart_alchemy_methods,
+ sizeof(struct uart_softc),
+};
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+
+static int
+uart_alchemy_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));
+
+ return (uart_bus_probe(dev, 0, 0, 0, 0));
+}
+
+DRIVER_MODULE(uart, obio, uart_alchemy_driver, uart_devclass, 0, 0);
diff --git a/sys/mips/alchemy/uart_cpu_alchemy.c b/sys/mips/alchemy/uart_cpu_alchemy.c
new file mode 100644
index 0000000..931aed6
--- /dev/null
+++ b/sys/mips/alchemy/uart_cpu_alchemy.c
@@ -0,0 +1,79 @@
+/*-
+ * 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.
+ */
+
+#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>
+
+#include <mips/alchemy/aureg.h>
+
+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)
+{
+
+ di->ops = uart_getops(&uart_ns8250_class);
+ di->bas.chan = 0;
+ di->bas.bst = 0;
+ di->bas.regshft = 0;
+ di->bas.rclk = 0;
+ di->baudrate = 115200;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+
+ uart_bus_space_io = 0;
+ uart_bus_space_mem = MIPS_PHYS_TO_KSEG1(UART0_BASE);
+ di->bas.bsh = MIPS_PHYS_TO_KSEG1(UART0_BASE);
+
+ return (0);
+}
diff --git a/sys/mips/atheros/apb.c b/sys/mips/atheros/apb.c
new file mode 100644
index 0000000..d53408c
--- /dev/null
+++ b/sys/mips/atheros/apb.c
@@ -0,0 +1,433 @@
+/*-
+ * Copyright (c) 2009, 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 unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <mips/atheros/apbvar.h>
+#include <mips/atheros/ar71xxreg.h>
+
+#undef APB_DEBUG
+#ifdef APB_DEBUG
+#define dprintf printf
+#else
+#define dprintf(x, arg...)
+#endif /* APB_DEBUG */
+
+static int apb_activate_resource(device_t, device_t, int, int,
+ struct resource *);
+static device_t apb_add_child(device_t, int, const char *, int);
+static struct resource *
+ apb_alloc_resource(device_t, device_t, int, int *, u_long,
+ u_long, u_long, u_int);
+static int apb_attach(device_t);
+static int apb_deactivate_resource(device_t, device_t, int, int,
+ struct resource *);
+static struct resource_list *
+ apb_get_resource_list(device_t, device_t);
+static void apb_hinted_child(device_t, const char *, int);
+static int apb_intr(void *);
+static int apb_probe(device_t);
+static int apb_release_resource(device_t, device_t, int, int,
+ struct resource *);
+static int apb_setup_intr(device_t, device_t, struct resource *, int,
+ driver_filter_t *, driver_intr_t *, void *, void **);
+static int apb_teardown_intr(device_t, device_t, struct resource *,
+ void *);
+
+static void apb_mask_irq(unsigned int irq)
+{
+ uint32_t reg;
+
+ reg = ATH_READ_REG(AR71XX_MISC_INTR_MASK);
+ ATH_WRITE_REG(AR71XX_MISC_INTR_MASK, reg & ~(1 << irq));
+
+}
+
+static void apb_unmask_irq(unsigned int irq)
+{
+ uint32_t reg;
+
+ reg = ATH_READ_REG(AR71XX_MISC_INTR_MASK);
+ ATH_WRITE_REG(AR71XX_MISC_INTR_MASK, reg | (1 << irq));
+}
+
+static int
+apb_probe(device_t dev)
+{
+
+ return (0);
+}
+
+static int
+apb_attach(device_t dev)
+{
+ struct apb_softc *sc = device_get_softc(dev);
+ int rid = 0;
+
+ device_set_desc(dev, "APB Bus bridge");
+ sc->apb_irq_rman.rm_type = RMAN_ARRAY;
+ sc->apb_irq_rman.rm_descr = "APB IRQ";
+
+ if (rman_init(&sc->apb_irq_rman) != 0 ||
+ rman_manage_region(&sc->apb_irq_rman,
+ APB_IRQ_BASE, APB_IRQ_END) != 0)
+ panic("apb_attach: failed to set up IRQ rman");
+
+ if ((sc->sc_misc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+ device_printf(dev, "unable to allocate IRQ resource\n");
+ return (ENXIO);
+ }
+
+ if ((bus_setup_intr(dev, sc->sc_misc_irq, INTR_TYPE_MISC,
+ apb_intr, NULL, sc, &sc->sc_misc_ih))) {
+ 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 *
+apb_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 apb_softc *sc = device_get_softc(bus);
+ struct apb_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;
+ /*
+ * Pass memory requests to nexus device
+ */
+ passthrough = (device_get_parent(child) != bus) ||
+ (type == SYS_RES_MEMORY);
+ rle = NULL;
+
+ dprintf("%s: entry (%p, %p, %d, %p, %p, %p, %ld, %d)\n",
+ __func__, bus, child, type, rid, (void *)(intptr_t)start,
+ (void *)(intptr_t)end, count, flags);
+
+ 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;
+
+ dprintf("%s: default resource (%p, %p, %ld)\n",
+ __func__, (void *)(intptr_t)start,
+ (void *)(intptr_t)end, count);
+ }
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &sc->apb_irq_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
+apb_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
+apb_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
+apb_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 = apb_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
+apb_setup_intr(device_t bus, device_t child, struct resource *ires,
+ int flags, driver_filter_t *filt, driver_intr_t *handler,
+ void *arg, void **cookiep)
+{
+ struct apb_softc *sc = device_get_softc(bus);
+ struct intr_event *event;
+ int irq, error;
+
+ irq = rman_get_start(ires);
+
+ if (irq > APB_IRQ_END)
+ panic("%s: bad irq %d", __func__, irq);
+
+ event = sc->sc_eventstab[irq];
+ if (event == NULL) {
+ error = intr_event_create(&event, (void *)irq, 0, irq,
+ (mask_fn)apb_mask_irq, (mask_fn)apb_unmask_irq,
+ NULL, NULL,
+ "apb 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);
+
+ return (0);
+}
+
+static int
+apb_teardown_intr(device_t dev, device_t child, struct resource *ires,
+ void *cookie)
+{
+ struct apb_softc *sc = device_get_softc(dev);
+ int irq, result;
+
+ irq = rman_get_start(ires);
+ if (irq > APB_IRQ_END)
+ panic("%s: bad irq %d", __func__, irq);
+
+ if (sc->sc_eventstab[irq] == NULL)
+ panic("Trying to teardown unoccupied IRQ");
+
+ apb_mask_irq(irq);
+
+ result = intr_event_remove_handler(cookie);
+ if (!result)
+ sc->sc_eventstab[irq] = NULL;
+
+ return (result);
+}
+
+static int
+apb_intr(void *arg)
+{
+ struct apb_softc *sc = arg;
+ struct intr_event *event;
+ uint32_t reg, irq;
+
+ reg = ATH_READ_REG(AR71XX_MISC_INTR_STATUS);
+ for (irq = 0; irq < APB_NIRQS; irq++) {
+ if (reg & (1 << irq)) {
+ event = sc->sc_eventstab[irq];
+ if (!event || TAILQ_EMPTY(&event->ie_handlers)) {
+ printf("Stray IRQ %d\n", irq);
+ continue;
+ }
+
+ /* TODO: frame instead of NULL? */
+ intr_event_handle(event, NULL);
+ }
+ }
+
+ return (FILTER_HANDLED);
+}
+
+static void
+apb_hinted_child(device_t bus, const char *dname, int dunit)
+{
+ device_t child;
+ long maddr;
+ int msize;
+ int irq;
+ int result;
+ int mem_hints_count;
+
+ child = BUS_ADD_CHILD(bus, 0, dname, dunit);
+
+ /*
+ * Set hard-wired resources for hinted child using
+ * specific RIDs.
+ */
+ mem_hints_count = 0;
+ if (resource_long_value(dname, dunit, "maddr", &maddr) == 0)
+ mem_hints_count++;
+ if (resource_int_value(dname, dunit, "msize", &msize) == 0)
+ mem_hints_count++;
+
+ /* check if all info for mem resource has been provided */
+ if ((mem_hints_count > 0) && (mem_hints_count < 2)) {
+ printf("Either maddr or msize hint is missing for %s%d\n",
+ dname, dunit);
+ } else if (mem_hints_count) {
+ 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
+apb_add_child(device_t bus, int order, const char *name, int unit)
+{
+ device_t child;
+ struct apb_ivar *ivar;
+
+ ivar = malloc(sizeof(struct apb_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 *
+apb_get_resource_list(device_t dev, device_t child)
+{
+ struct apb_ivar *ivar;
+
+ ivar = device_get_ivars(child);
+ return (&(ivar->resources));
+}
+
+static device_method_t apb_methods[] = {
+ DEVMETHOD(bus_activate_resource, apb_activate_resource),
+ DEVMETHOD(bus_add_child, apb_add_child),
+ DEVMETHOD(bus_alloc_resource, apb_alloc_resource),
+ DEVMETHOD(bus_deactivate_resource, apb_deactivate_resource),
+ DEVMETHOD(bus_get_resource_list, apb_get_resource_list),
+ DEVMETHOD(bus_hinted_child, apb_hinted_child),
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_release_resource, apb_release_resource),
+ DEVMETHOD(bus_setup_intr, apb_setup_intr),
+ DEVMETHOD(bus_teardown_intr, apb_teardown_intr),
+ DEVMETHOD(device_attach, apb_attach),
+ DEVMETHOD(device_probe, apb_probe),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+
+ {0, 0},
+};
+
+static driver_t apb_driver = {
+ "apb",
+ apb_methods,
+ sizeof(struct apb_softc),
+};
+static devclass_t apb_devclass;
+
+DRIVER_MODULE(apb, nexus, apb_driver, apb_devclass, 0, 0);
diff --git a/sys/mips/atheros/apbvar.h b/sys/mips/atheros/apbvar.h
new file mode 100644
index 0000000..e1d29f4
--- /dev/null
+++ b/sys/mips/atheros/apbvar.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2009, 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 unmodified, 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.
+ */
+
+#ifndef _APBVAR_H_
+#define _APBVAR_H_
+
+#define APB_IRQ_BASE 0
+#define APB_IRQ_END 7
+#define APB_NIRQS 8
+
+struct apb_softc {
+ struct rman apb_irq_rman;
+ /* IRQ events structs for child devices */
+ struct intr_event *sc_eventstab[APB_NIRQS];
+ /* Resources and cookies for MIPS CPU INTs */
+ struct resource *sc_misc_irq;
+ void *sc_misc_ih;
+};
+
+struct apb_ivar {
+ struct resource_list resources;
+};
+
+#endif /* _APBVAR_H_ */
diff --git a/sys/mips/atheros/ar71xx_machdep.c b/sys/mips/atheros/ar71xx_machdep.c
new file mode 100644
index 0000000..a5699ed
--- /dev/null
+++ b/sys/mips/atheros/ar71xx_machdep.c
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (c) 2009 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 AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <machine/cpuregs.h>
+
+#include <mips/sentry5/s5reg.h>
+
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+#include <sys/kdb.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/hwfunc.h>
+#include <machine/md_var.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+#include <mips/atheros/ar71xxreg.h>
+
+extern int *edata;
+extern int *end;
+
+void
+platform_halt(void)
+{
+
+}
+
+void
+platform_identify(void)
+{
+
+}
+
+void
+platform_reset(void)
+{
+ uint32_t reg = ATH_READ_REG(AR71XX_RST_RESET);
+
+ ATH_WRITE_REG(AR71XX_RST_RESET, reg | RST_RESET_FULL_CHIP);
+ /* Wait for reset */
+ while(1)
+ ;
+}
+
+void
+platform_trap_enter(void)
+{
+
+}
+
+void
+platform_trap_exit(void)
+{
+
+}
+
+void
+platform_start(__register_t a0 __unused, __register_t a1 __unused,
+ __register_t a2 __unused, __register_t a3 __unused)
+{
+ vm_offset_t kernend;
+ uint64_t platform_counter_freq;
+ uint32_t reg;
+
+ /* clear the BSS and SBSS segments */
+ kernend = round_page((vm_offset_t)&end);
+ memset(&edata, 0, kernend - (vm_offset_t)(&edata));
+
+ /* TODO: Get available memory from RedBoot. Is it possible? */
+ realmem = btoc(64*1024*1024);
+ /* 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: Get CPU freq from RedBoot. Is it possible? */
+ platform_counter_freq = 680000000UL;
+ mips_timer_init_params(platform_counter_freq, 0);
+ cninit();
+
+ printf("arguments: \n");
+ printf(" a0 = %08x\n", a0);
+ printf(" a1 = %08x\n", a1);
+ printf(" a2 = %08x\n", a2);
+ printf(" a3 = %08x\n", a3);
+
+ init_param2(physmem);
+ mips_cpu_init();
+ pmap_bootstrap();
+ mips_proc0_init();
+ mutex_init();
+
+ /*
+ * Reset USB devices
+ */
+ reg = ATH_READ_REG(AR71XX_RST_RESET);
+ reg |=
+ RST_RESET_USB_OHCI_DLL | RST_RESET_USB_HOST | RST_RESET_USB_PHY;
+ ATH_WRITE_REG(AR71XX_RST_RESET, reg);
+ DELAY(1000);
+ reg &=
+ ~(RST_RESET_USB_OHCI_DLL | RST_RESET_USB_HOST | RST_RESET_USB_PHY);
+ ATH_WRITE_REG(AR71XX_RST_RESET, reg);
+
+ ATH_WRITE_REG(AR71XX_USB_CTRL_CONFIG,
+ USB_CTRL_CONFIG_OHCI_DES_SWAP | USB_CTRL_CONFIG_OHCI_BUF_SWAP |
+ USB_CTRL_CONFIG_EHCI_DES_SWAP | USB_CTRL_CONFIG_EHCI_BUF_SWAP);
+
+ ATH_WRITE_REG(AR71XX_USB_CTRL_FLADJ,
+ (32 << USB_CTRL_FLADJ_HOST_SHIFT) | (3 << USB_CTRL_FLADJ_A5_SHIFT));
+ DELAY(1000);
+
+#ifdef DDB
+ kdb_init();
+#endif
+}
diff --git a/sys/mips/atheros/ar71xx_ohci.c b/sys/mips/atheros/ar71xx_ohci.c
new file mode 100644
index 0000000..b7adc61
--- /dev/null
+++ b/sys/mips/atheros/ar71xx_ohci.c
@@ -0,0 +1,205 @@
+/*-
+ * Copyright (c) 2009, 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 unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+#include <sys/queue.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
+
+#include <dev/usb/ohcireg.h>
+#include <dev/usb/ohcivar.h>
+
+static int ar71xx_ohci_attach(device_t dev);
+static int ar71xx_ohci_detach(device_t dev);
+static int ar71xx_ohci_probe(device_t dev);
+
+struct ar71xx_ohci_softc
+{
+ struct ohci_softc sc_ohci;
+};
+
+static int
+ar71xx_ohci_probe(device_t dev)
+{
+ device_set_desc(dev, "AR71XX integrated OHCI controller");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+ar71xx_ohci_attach(device_t dev)
+{
+ struct ar71xx_ohci_softc *sc = device_get_softc(dev);
+ int err;
+ int rid;
+
+ rid = 0;
+ sc->sc_ohci.io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->sc_ohci.io_res == NULL) {
+ err = ENOMEM;
+ goto error;
+ }
+ sc->sc_ohci.iot = rman_get_bustag(sc->sc_ohci.io_res);
+ sc->sc_ohci.ioh = rman_get_bushandle(sc->sc_ohci.io_res);
+
+ rid = 0;
+ sc->sc_ohci.irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (sc->sc_ohci.irq_res == NULL) {
+ err = ENOMEM;
+ goto error;
+ }
+ sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usb", -1);
+ if (sc->sc_ohci.sc_bus.bdev == NULL) {
+ err = ENOMEM;
+ goto error;
+ }
+ device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus);
+
+ /* Allocate a parent dma tag for DMA maps */
+ err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0,
+ NULL, NULL, &sc->sc_ohci.sc_bus.parent_dmatag);
+ if (err) {
+ device_printf(dev, "Could not allocate parent DMA tag (%d)\n",
+ err);
+ err = ENXIO;
+ goto error;
+ }
+
+ /* Allocate a dma tag for transfer buffers */
+ err = bus_dma_tag_create(sc->sc_ohci.sc_bus.parent_dmatag, 1, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0,
+ busdma_lock_mutex, &Giant, &sc->sc_ohci.sc_bus.buffer_dmatag);
+ if (err) {
+ device_printf(dev, "Could not allocate transfer tag (%d)\n",
+ err);
+ err = ENXIO;
+ goto error;
+ }
+
+ err = bus_setup_intr(dev, sc->sc_ohci.irq_res, INTR_TYPE_BIO, NULL,
+ ohci_intr, sc, &sc->sc_ohci.ih);
+ if (err) {
+ err = ENXIO;
+ goto error;
+ }
+ strlcpy(sc->sc_ohci.sc_vendor, "Atheros",
+ sizeof(sc->sc_ohci.sc_vendor));
+
+ bus_space_write_4(sc->sc_ohci.iot, sc->sc_ohci.ioh, OHCI_CONTROL, 0);
+
+ err = ohci_init(&sc->sc_ohci);
+ if (!err) {
+ sc->sc_ohci.sc_flags |= OHCI_SCFLG_DONEINIT;
+ err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev);
+ }
+
+error:
+ if (err) {
+ ar71xx_ohci_detach(dev);
+ return (err);
+ }
+ return (err);
+}
+
+static int
+ar71xx_ohci_detach(device_t dev)
+{
+ struct ar71xx_ohci_softc *sc = device_get_softc(dev);
+
+ if (sc->sc_ohci.sc_flags & OHCI_SCFLG_DONEINIT) {
+ ohci_detach(&sc->sc_ohci, 0);
+ sc->sc_ohci.sc_flags &= ~OHCI_SCFLG_DONEINIT;
+ }
+
+ if (sc->sc_ohci.ih) {
+ bus_teardown_intr(dev, sc->sc_ohci.irq_res, sc->sc_ohci.ih);
+ sc->sc_ohci.ih = NULL;
+ }
+
+ if (sc->sc_ohci.sc_bus.parent_dmatag != NULL)
+ bus_dma_tag_destroy(sc->sc_ohci.sc_bus.parent_dmatag);
+ if (sc->sc_ohci.sc_bus.buffer_dmatag != NULL)
+ bus_dma_tag_destroy(sc->sc_ohci.sc_bus.buffer_dmatag);
+
+ if (sc->sc_ohci.sc_bus.bdev) {
+ device_delete_child(dev, sc->sc_ohci.sc_bus.bdev);
+ sc->sc_ohci.sc_bus.bdev = NULL;
+ }
+ if (sc->sc_ohci.irq_res) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.irq_res);
+ sc->sc_ohci.irq_res = NULL;
+ }
+ if (sc->sc_ohci.io_res) {
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_ohci.io_res);
+ sc->sc_ohci.io_res = NULL;
+ sc->sc_ohci.iot = 0;
+ sc->sc_ohci.ioh = 0;
+ }
+ return (0);
+}
+
+static device_method_t ohci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ar71xx_ohci_probe),
+ DEVMETHOD(device_attach, ar71xx_ohci_attach),
+ DEVMETHOD(device_detach, ar71xx_ohci_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+ {0, 0}
+};
+
+static driver_t ohci_driver = {
+ "ohci",
+ ohci_methods,
+ sizeof(struct ar71xx_ohci_softc),
+};
+
+static devclass_t ohci_devclass;
+
+DRIVER_MODULE(ohci, apb, ohci_driver, ohci_devclass, 0, 0);
diff --git a/sys/mips/atheros/ar71xx_pci.c b/sys/mips/atheros/ar71xx_pci.c
new file mode 100644
index 0000000..d3a9295
--- /dev/null
+++ b/sys/mips/atheros/ar71xx_pci.c
@@ -0,0 +1,429 @@
+/*-
+ * Copyright (c) 2009, 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 unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sys/bus.h>
+#include <sys/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/atheros/ar71xxreg.h"
+
+#undef AR71XX_PCI_DEBUG
+#ifdef AR71XX_PCI_DEBUG
+#define dprintf printf
+#else
+#define dprintf(x, arg...)
+#endif
+
+struct ar71xx_pci_softc {
+ device_t sc_dev;
+
+ int sc_busno;
+ struct rman sc_mem_rman;
+ struct rman sc_irq_rman;
+
+ struct resource *sc_irq;
+ void *sc_ih;
+};
+
+/*
+ * get bitmask for bytes of interest:
+ * 0 - we want this byte, 1 - ignore it. e.g: we read 1 byte
+ * from register 7. Bitmask would be: 0111
+ */
+static uint32_t
+ar71xx_get_bytes_to_read(int reg, int bytes)
+{
+ uint32_t bytes_to_read = 0;
+ if ((bytes % 4) == 0)
+ bytes_to_read = 0;
+ else if ((bytes % 4) == 1)
+ bytes_to_read = (~(1 << (reg % 4))) & 0xf;
+ else if ((bytes % 4) == 2)
+ bytes_to_read = (~(3 << (reg % 4))) & 0xf;
+ else
+ panic("%s: wrong combination", __func__);
+
+ return (bytes_to_read);
+}
+
+static int
+ar71xx_pci_check_bus_error(void)
+{
+ uint32_t error, addr, has_errors = 0;
+ error = ATH_READ_REG(AR71XX_PCI_ERROR) & 0x3;
+ dprintf("%s: PCI error = %02x\n", __func__, error);
+ if (error) {
+ addr = ATH_READ_REG(AR71XX_PCI_ERROR_ADDR);
+
+ /* Do not report it yet */
+#if 0
+ printf("PCI bus error %d at addr 0x%08x\n", error, addr);
+#endif
+ ATH_WRITE_REG(AR71XX_PCI_ERROR, error);
+ has_errors = 1;
+ }
+
+ error = ATH_READ_REG(AR71XX_PCI_AHB_ERROR) & 0x1;
+ dprintf("%s: AHB error = %02x\n", __func__, error);
+ if (error) {
+ addr = ATH_READ_REG(AR71XX_PCI_AHB_ERROR_ADDR);
+ /* Do not report it yet */
+#if 0
+ printf("AHB bus error %d at addr 0x%08x\n", error, addr);
+#endif
+ ATH_WRITE_REG(AR71XX_PCI_AHB_ERROR, error);
+ has_errors = 1;
+ }
+
+ return (has_errors);
+}
+
+static uint32_t
+ar71xx_pci_make_addr(int bus, int slot, int func, int reg)
+{
+ if (bus == 0) {
+ return ((1 << slot) | (func << 8) | (reg & ~3));
+ } else {
+ return ((bus << 16) | (slot << 11) | (func << 8)
+ | (reg & ~3) | 1);
+ }
+}
+
+static int
+ar71xx_pci_conf_setup(int bus, int slot, int func, int reg, int bytes,
+ uint32_t cmd)
+{
+ uint32_t addr = ar71xx_pci_make_addr(bus, slot, func, (reg & ~3));
+ cmd |= (ar71xx_get_bytes_to_read(reg, bytes) << 4);
+
+ ATH_WRITE_REG(AR71XX_PCI_CONF_ADDR, addr);
+ ATH_WRITE_REG(AR71XX_PCI_CONF_CMD, cmd);
+
+ dprintf("%s: tag (%x, %x, %x) %d/%d addr=%08x, cmd=%08x\n", __func__,
+ bus, slot, func, reg, bytes, addr, cmd);
+
+ return ar71xx_pci_check_bus_error();
+}
+
+static uint32_t
+ar71xx_pci_read_config(device_t dev, int bus, int slot, int func, int reg,
+ int bytes)
+{
+ uint32_t data;
+ uint32_t cmd, shift, mask;
+
+ /* register access is 32-bit aligned */
+ shift = (reg & 3) * 8;
+ if (shift)
+ mask = (1 << shift) - 1;
+ else
+ mask = 0xffffffff;
+
+ dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot,
+ func, reg, bytes);
+
+ if ((bus == 0) && (slot == 0) && (func == 0)) {
+ cmd = PCI_LCONF_CMD_READ | (reg & ~3);
+ ATH_WRITE_REG(AR71XX_PCI_LCONF_CMD, cmd);
+ data = ATH_READ_REG(AR71XX_PCI_LCONF_READ_DATA);
+ } else {
+ if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes,
+ PCI_CONF_CMD_READ) == 0)
+ data = ATH_READ_REG(AR71XX_PCI_CONF_READ_DATA);
+ else
+ data = -1;
+ }
+
+ /* get request bytes from 32-bit word */
+ data = (data >> shift) & mask;
+
+ dprintf("%s: read 0x%x\n", __func__, data);
+
+ return (data);
+}
+
+static void
+ar71xx_pci_write_config(device_t dev, int bus, int slot, int func, int reg,
+ uint32_t data, int bytes)
+{
+ uint32_t cmd;
+
+ dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot,
+ func, reg, bytes);
+
+ data = data << (8*(reg % 4));
+
+ if ((bus == 0) && (slot == 0) && (func == 0)) {
+ cmd = PCI_LCONF_CMD_WRITE | (reg & ~3);
+ cmd |= ar71xx_get_bytes_to_read(reg, bytes) << 20;
+ ATH_WRITE_REG(AR71XX_PCI_LCONF_CMD, cmd);
+ ATH_WRITE_REG(AR71XX_PCI_LCONF_WRITE_DATA, data);
+ } else {
+ if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes,
+ PCI_CONF_CMD_WRITE) == 0)
+ ATH_WRITE_REG(AR71XX_PCI_CONF_WRITE_DATA, data);
+ }
+}
+
+static int
+at71xx_pci_intr(void *v)
+{
+ panic("Implement me: %s\n", __func__);
+ return FILTER_HANDLED;
+}
+
+static int
+ar71xx_pci_probe(device_t dev)
+{
+
+ return (0);
+}
+
+static int
+ar71xx_pci_attach(device_t dev)
+{
+ int busno = 0;
+ int rid = 0;
+ uint32_t reset;
+ struct ar71xx_pci_softc *sc = device_get_softc(dev);
+
+ sc->sc_mem_rman.rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman.rm_descr = "ar71xx PCI memory window";
+ if (rman_init(&sc->sc_mem_rman) != 0 ||
+ rman_manage_region(&sc->sc_mem_rman, AR71XX_PCI_MEM_BASE,
+ AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1) != 0) {
+ panic("ar71xx_pci_attach: failed to set up I/O rman");
+ }
+
+ sc->sc_irq_rman.rm_type = RMAN_ARRAY;
+ sc->sc_irq_rman.rm_descr = "ar71xx PCI IRQs";
+ if (rman_init(&sc->sc_irq_rman) != 0 ||
+ rman_manage_region(&sc->sc_irq_rman, AR71XX_PCI_IRQ_START,
+ AR71XX_PCI_IRQ_END) != 0)
+ panic("ar71xx_pci_attach: failed to set up IRQ rman");
+
+
+ ATH_WRITE_REG(AR71XX_PCI_INTR_STATUS, 0);
+ ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, 0);
+
+ /* Hook up our interrupt handler. */
+ if ((sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+ device_printf(dev, "unable to allocate IRQ resource\n");
+ return ENXIO;
+ }
+
+ if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC,
+ at71xx_pci_intr, NULL, sc, &sc->sc_ih))) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ return ENXIO;
+ }
+
+ /* reset PCI core and PCI bus */
+ reset = ATH_READ_REG(AR71XX_RST_RESET);
+ reset |= (RST_RESET_PCI_CORE | RST_RESET_PCI_BUS);
+ ATH_WRITE_REG(AR71XX_RST_RESET, reset);
+ DELAY(1000);
+
+ reset &= ~(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS);
+ ATH_WRITE_REG(AR71XX_RST_RESET, reset);
+ DELAY(1000);
+
+ /* Init PCI windows */
+ ATH_WRITE_REG(AR71XX_PCI_WINDOW0, PCI_WINDOW0_ADDR);
+ ATH_WRITE_REG(AR71XX_PCI_WINDOW1, PCI_WINDOW1_ADDR);
+ ATH_WRITE_REG(AR71XX_PCI_WINDOW2, PCI_WINDOW2_ADDR);
+ ATH_WRITE_REG(AR71XX_PCI_WINDOW3, PCI_WINDOW3_ADDR);
+ ATH_WRITE_REG(AR71XX_PCI_WINDOW4, PCI_WINDOW4_ADDR);
+ ATH_WRITE_REG(AR71XX_PCI_WINDOW5, PCI_WINDOW5_ADDR);
+ ATH_WRITE_REG(AR71XX_PCI_WINDOW6, PCI_WINDOW6_ADDR);
+ ATH_WRITE_REG(AR71XX_PCI_WINDOW7, PCI_WINDOW7_CONF_ADDR);
+ DELAY(1000);
+
+ ar71xx_pci_check_bus_error();
+
+ /* Fixup internal PCI bridge */
+ ar71xx_pci_write_config(dev, 0, 0, 0, PCIR_COMMAND,
+ PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN
+ | PCIM_CMD_SERRESPEN | PCIM_CMD_BACKTOBACK
+ | PCIM_CMD_PERRESPEN | PCIM_CMD_MWRICEN, 2);
+
+ device_add_child(dev, "pci", busno);
+ return (bus_generic_attach(dev));
+}
+
+static int
+ar71xx_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct ar71xx_pci_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
+ar71xx_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
+{
+ struct ar71xx_pci_softc * sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ sc->sc_busno = result;
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+static struct resource *
+ar71xx_pci_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 ar71xx_pci_softc *sc = device_get_softc(bus);
+ struct resource *rv = NULL;
+ struct rman *rm;
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &sc->sc_irq_rman;
+ break;
+ case SYS_RES_MEMORY:
+ rm = &sc->sc_mem_rman;
+ break;
+ default:
+ return (NULL);
+ }
+
+ rv = rman_reserve_resource(rm, 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
+ar71xx_pci_teardown_intr(device_t dev, device_t child, struct resource *res,
+ void *cookie)
+{
+
+ return (intr_event_remove_handler(cookie));
+}
+
+static int
+ar71xx_pci_maxslots(device_t dev)
+{
+
+ return (PCI_SLOTMAX);
+}
+
+static int
+ar71xx_pci_route_interrupt(device_t pcib, device_t device, int pin)
+{
+
+ return (pin);
+}
+
+static device_method_t ar71xx_pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ar71xx_pci_probe),
+ DEVMETHOD(device_attach, ar71xx_pci_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, ar71xx_pci_read_ivar),
+ DEVMETHOD(bus_write_ivar, ar71xx_pci_write_ivar),
+ DEVMETHOD(bus_alloc_resource, ar71xx_pci_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, ar71xx_pci_teardown_intr),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, ar71xx_pci_maxslots),
+ DEVMETHOD(pcib_read_config, ar71xx_pci_read_config),
+ DEVMETHOD(pcib_write_config, ar71xx_pci_write_config),
+ DEVMETHOD(pcib_route_interrupt, ar71xx_pci_route_interrupt),
+
+ {0, 0}
+};
+
+static driver_t ar71xx_pci_driver = {
+ "pcib",
+ ar71xx_pci_methods,
+ sizeof(struct ar71xx_pci_softc),
+};
+
+static devclass_t ar71xx_pci_devclass;
+
+DRIVER_MODULE(ar71xx_pci, nexus, ar71xx_pci_driver, ar71xx_pci_devclass, 0, 0);
diff --git a/sys/mips/atheros/ar71xxreg.h b/sys/mips/atheros/ar71xxreg.h
new file mode 100644
index 0000000..9367792
--- /dev/null
+++ b/sys/mips/atheros/ar71xxreg.h
@@ -0,0 +1,317 @@
+/*-
+ * Copyright (c) 2009 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 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.
+ */
+#ifndef _AR71XX_REG_H_
+#define _AR71XX_REG_H_
+
+#define ATH_READ_REG(reg) \
+ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1((reg)))
+
+#define ATH_WRITE_REG(reg, val) \
+ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1((reg))) = (val)
+
+/* PCI region */
+#define AR71XX_PCI_MEM_BASE 0x10000000
+/*
+ * PCI mem windows is 0x08000000 bytes long but we exclude control
+ * region from the resource manager
+ */
+#define AR71XX_PCI_MEM_SIZE 0x07000000
+#define AR71XX_PCI_IRQ_START 0
+#define AR71XX_PCI_IRQ_END 2
+
+/* PCI config registers */
+#define AR71XX_PCI_LCONF_CMD 0x17010000
+#define PCI_LCONF_CMD_READ 0x00000000
+#define PCI_LCONF_CMD_WRITE 0x00010000
+#define AR71XX_PCI_LCONF_WRITE_DATA 0x17010004
+#define AR71XX_PCI_LCONF_READ_DATA 0x17010008
+#define AR71XX_PCI_CONF_ADDR 0x1701000C
+#define AR71XX_PCI_CONF_CMD 0x17010010
+#define PCI_CONF_CMD_READ 0x0000000A
+#define PCI_CONF_CMD_WRITE 0x0000000B
+#define AR71XX_PCI_CONF_WRITE_DATA 0x17010014
+#define AR71XX_PCI_CONF_READ_DATA 0x17010018
+#define AR71XX_PCI_ERROR 0x1701001C
+#define AR71XX_PCI_ERROR_ADDR 0x17010020
+#define AR71XX_PCI_AHB_ERROR 0x17010024
+#define AR71XX_PCI_AHB_ERROR_ADDR 0x17010028
+
+/* APB region */
+/* DDR registers */
+#define AR71XX_DDR_CONFIG 0x18000000
+#define AR71XX_DDR_CONFIG2 0x18000004
+#define AR71XX_DDR_MODE_REGISTER 0x18000008
+#define AR71XX_DDR_EXT_MODE_REGISTER 0x1800000C
+#define AR71XX_DDR_CONTROL 0x18000010
+#define AR71XX_DDR_REFRESH 0x18000014
+#define AR71XX_DDR_RD_DATA_THIS_CYCLE 0x18000018
+#define AR71XX_TAP_CONTROL0 0x1800001C
+#define AR71XX_TAP_CONTROL1 0x18000020
+#define AR71XX_TAP_CONTROL2 0x18000024
+#define AR71XX_TAP_CONTROL3 0x18000028
+#define AR71XX_PCI_WINDOW0 0x1800007C
+#define AR71XX_PCI_WINDOW1 0x18000080
+#define AR71XX_PCI_WINDOW2 0x18000084
+#define AR71XX_PCI_WINDOW3 0x18000088
+#define AR71XX_PCI_WINDOW4 0x1800008C
+#define AR71XX_PCI_WINDOW5 0x18000090
+#define AR71XX_PCI_WINDOW6 0x18000094
+#define AR71XX_PCI_WINDOW7 0x18000098
+#define AR71XX_WB_FLUSH_GE0 0x1800009C
+#define AR71XX_WB_FLUSH_GE1 0x180000A0
+#define AR71XX_WB_FLUSH_USB 0x180000A4
+#define AR71XX_WB_FLUSH_PCI 0x180000A8
+
+/*
+ * Values for PCI_WINDOW_X registers
+ */
+#define PCI_WINDOW0_ADDR 0x10000000
+#define PCI_WINDOW1_ADDR 0x11000000
+#define PCI_WINDOW2_ADDR 0x12000000
+#define PCI_WINDOW3_ADDR 0x13000000
+#define PCI_WINDOW4_ADDR 0x14000000
+#define PCI_WINDOW5_ADDR 0x15000000
+#define PCI_WINDOW6_ADDR 0x16000000
+#define PCI_WINDOW7_ADDR 0x17000000
+/* This value enables acces to PCI config registers */
+#define PCI_WINDOW7_CONF_ADDR 0x07000000
+
+#define AR71XX_UART_ADDR 0x18020000
+
+#define AR71XX_USB_CTRL_FLADJ 0x18030000
+#define USB_CTRL_FLADJ_HOST_SHIFT 12
+#define USB_CTRL_FLADJ_A5_SHIFT 10
+#define USB_CTRL_FLADJ_A4_SHIFT 8
+#define USB_CTRL_FLADJ_A3_SHIFT 6
+#define USB_CTRL_FLADJ_A2_SHIFT 4
+#define USB_CTRL_FLADJ_A1_SHIFT 2
+#define USB_CTRL_FLADJ_A0_SHIFT 0
+#define AR71XX_USB_CTRL_CONFIG 0x18030004
+#define USB_CTRL_CONFIG_OHCI_DES_SWAP (1 << 19)
+#define USB_CTRL_CONFIG_OHCI_BUF_SWAP (1 << 18)
+#define USB_CTRL_CONFIG_EHCI_DES_SWAP (1 << 17)
+#define USB_CTRL_CONFIG_EHCI_BUF_SWAP (1 << 16)
+#define USB_CTRL_CONFIG_DISABLE_XTL (1 << 13)
+#define USB_CTRL_CONFIG_OVERRIDE_XTL (1 << 12)
+#define USB_CTRL_CONFIG_CLK_SEL_SHIFT 4
+#define USB_CTRL_CONFIG_CLK_SEL_MASK 3
+#define USB_CTRL_CONFIG_CLK_SEL_12 0
+#define USB_CTRL_CONFIG_CLK_SEL_24 1
+#define USB_CTRL_CONFIG_CLK_SEL_48 2
+#define USB_CTRL_CONFIG_OVER_CURRENT_AS_GPIO (1 << 8)
+#define USB_CTRL_CONFIG_SS_SIMULATION_MODE (1 << 2)
+#define USB_CTRL_CONFIG_RESUME_UTMI_PLS_DIS (1 << 1)
+#define USB_CTRL_CONFIG_UTMI_BACKWARD_ENB (1 << 0)
+
+#define AR71XX_PLL_CPU_CONFIG 0x18050000
+#define AR71XX_PLL_SEC_CONFIG 0x18050004
+#define AR71XX_PLL_CPU_CLK_CTRL 0x18050008
+#define AR71XX_PLL_ETH_INT0_CLK 0x18050010
+#define AR71XX_PLL_ETH_INT1_CLK 0x18050014
+#define XPLL_ETH_INT_CLK_10 0x00991099
+#define XPLL_ETH_INT_CLK_100 0x00441011
+#define XPLL_ETH_INT_CLK_1000 0x13110000
+#define XPLL_ETH_INT_CLK_1000_GMII 0x14110000
+#define PLL_ETH_INT_CLK_10 0x00991099
+#define PLL_ETH_INT_CLK_100 0x00001099
+#define PLL_ETH_INT_CLK_1000 0x00110000
+#define AR71XX_PLL_ETH_EXT_CLK 0x18050018
+#define AR71XX_PLL_PCI_CLK 0x1805001C
+
+/*
+ * APB interrupt status and mask register and interrupt bit numbers for
+ */
+#define AR71XX_MISC_INTR_STATUS 0x18060010
+#define AR71XX_MISC_INTR_MASK 0x18060014
+#define MISC_INTR_TIMER 0
+#define MISC_INTR_ERROR 1
+#define MISC_INTR_GPIO 2
+#define MISC_INTR_UART 3
+#define MISC_INTR_WATCHDOG 4
+#define MISC_INTR_PERF 5
+#define MISC_INTR_OHCI 6
+#define MISC_INTR_DMA 7
+
+#define AR71XX_PCI_INTR_STATUS 0x18060018
+#define AR71XX_PCI_INTR_MASK 0x1806001C
+#define PCI_INTR_CORE (1 << 4)
+
+#define AR71XX_RST_RESET 0x18060024
+#define RST_RESET_FULL_CHIP (1 << 24) /* Same as pulling
+ the reset pin */
+#define RST_RESET_CPU_COLD (1 << 20) /* Cold reset */
+#define RST_RESET_GE1_MAC (1 << 13)
+#define RST_RESET_GE1_PHY (1 << 12)
+#define RST_RESET_GE0_MAC (1 << 9)
+#define RST_RESET_GE0_PHY (1 << 8)
+#define RST_RESET_USB_OHCI_DLL (1 << 6)
+#define RST_RESET_USB_HOST (1 << 5)
+#define RST_RESET_USB_PHY (1 << 4)
+#define RST_RESET_PCI_BUS (1 << 1)
+#define RST_RESET_PCI_CORE (1 << 0)
+
+/*
+ * GigE adapters region
+ */
+#define AR71XX_MAC0_BASE 0x19000000
+#define AR71XX_MAC1_BASE 0x1A000000
+
+#define AR71XX_MAC_CFG1 0x00
+#define MAC_CFG1_SOFT_RESET (1 << 31)
+#define MAC_CFG1_SIMUL_RESET (1 << 30)
+#define MAC_CFG1_MAC_RX_BLOCK_RESET (1 << 19)
+#define MAC_CFG1_MAC_TX_BLOCK_RESET (1 << 18)
+#define MAC_CFG1_RX_FUNC_RESET (1 << 17)
+#define MAC_CFG1_TX_FUNC_RESET (1 << 16)
+#define MAC_CFG1_LOOPBACK (1 << 8)
+#define MAC_CFG1_RXFLOW_CTRL (1 << 5)
+#define MAC_CFG1_TXFLOW_CTRL (1 << 4)
+#define MAC_CFG1_SYNC_RX (1 << 3)
+#define MAC_CFG1_RX_ENABLE (1 << 2)
+#define MAC_CFG1_SYNC_TX (1 << 1)
+#define MAC_CFG1_TX_ENABLE (1 << 0)
+#define AR71XX_MAC_CFG2 0x04
+#define MAC_CFG2_PREAMBLE_LEN_MASK 0xf
+#define MAC_CFG2_PREAMBLE_LEN_SHIFT 12
+#define MAC_CFG2_IFACE_MODE_1000 (2 << 8)
+#define MAC_CFG2_IFACE_MODE_10_100 (1 << 8)
+#define MAC_CFG2_IFACE_MODE_SHIFT 8
+#define MAC_CFG2_IFACE_MODE_MASK 3
+#define MAC_CFG2_HUGE_FRAME (1 << 5)
+#define MAC_CFG2_LENGTH_FIELD (1 << 4)
+#define MAC_CFG2_ENABLE_PADCRC (1 << 2)
+#define MAC_CFG2_ENABLE_CRC (1 << 1)
+#define MAC_CFG2_FULL_DUPLEX (1 << 0)
+#define AR71XX_MAC_IFG 0x08
+#define AR71XX_MAC_HDUPLEX 0x0C
+#define AR71XX_MAC_MAX_FRAME_LEN 0x10
+#define AR71XX_MAC_MII_CFG 0x20
+#define MAC_MII_CFG_RESET (1 << 31)
+#define MAC_MII_CFG_SCAN_AUTO_INC (1 << 5)
+#define MAC_MII_CFG_PREAMBLE_SUP (1 << 4)
+#define MAC_MII_CFG_CLOCK_SELECT_MASK 0x7
+#define MAC_MII_CFG_CLOCK_DIV_4 0
+#define MAC_MII_CFG_CLOCK_DIV_6 2
+#define MAC_MII_CFG_CLOCK_DIV_8 3
+#define MAC_MII_CFG_CLOCK_DIV_10 4
+#define MAC_MII_CFG_CLOCK_DIV_14 5
+#define MAC_MII_CFG_CLOCK_DIV_20 6
+#define MAC_MII_CFG_CLOCK_DIV_28 7
+#define AR71XX_MAC_MII_CMD 0x24
+#define MAC_MII_CMD_SCAN_CYCLE (1 << 1)
+#define MAC_MII_CMD_READ 1
+#define MAC_MII_CMD_WRITE 0
+#define AR71XX_MAC_MII_ADDR 0x28
+#define MAC_MII_PHY_ADDR_SHIFT 8
+#define MAC_MII_PHY_ADDR_MASK 0xff
+#define MAC_MII_REG_MASK 0x1f
+#define AR71XX_MAC_MII_CONTROL 0x2C
+#define MAC_MII_CONTROL_MASK 0xffff
+#define AR71XX_MAC_MII_STATUS 0x30
+#define MAC_MII_STATUS_MASK 0xffff
+#define AR71XX_MAC_MII_INDICATOR 0x34
+#define MAC_MII_INDICATOR_NOT_VALID (1 << 2)
+#define MAC_MII_INDICATOR_SCANNING (1 << 1)
+#define MAC_MII_INDICATOR_BUSY (1 << 0)
+#define AR71XX_MAC_IFCONTROL 0x38
+#define MAC_IFCONTROL_SPEED (1 << 16)
+#define AR71XX_MAC_STA_ADDR1 0x40
+#define AR71XX_MAC_STA_ADDR2 0x44
+#define AR71XX_MAC_FIFO_CFG0 0x48
+#define FIFO_CFG0_TX_FABRIC (1 << 4)
+#define FIFO_CFG0_TX_SYSTEM (1 << 3)
+#define FIFO_CFG0_RX_FABRIC (1 << 2)
+#define FIFO_CFG0_RX_SYSTEM (1 << 1)
+#define FIFO_CFG0_WATERMARK (1 << 0)
+#define FIFO_CFG0_ALL ((1 << 5) - 1)
+#define FIFO_CFG0_ENABLE_SHIFT 8
+#define AR71XX_MAC_FIFO_CFG1 0x4C
+#define AR71XX_MAC_FIFO_CFG2 0x50
+#define AR71XX_MAC_FIFO_TX_THRESHOLD 0x54
+#define AR71XX_MAC_FIFO_RX_FILTMATCH 0x58
+#define FIFO_RX_FILTMATCH_ALL ((1 << 18) - 1)
+#define AR71XX_MAC_FIFO_RX_FILTMASK 0x5C
+#define FIFO_RX_FILTMASK_BYTE_MODE (1 << 19)
+#define FIFO_RX_FILTMASK_NO_SHORT_FRAME (1 << 18)
+#define FIFO_RX_FILTMASK_ALL ((1 << 20) - 1)
+/*
+ * These flags applicable both to AR71XX_MAC_FIFO_RX_FILTMASK and
+ * to AR71XX_MAC_FIFO_RX_FILTMATCH
+ */
+#define FIFO_RX_FILT_UNICAST (1 << 17)
+#define FIFO_RX_FILT_TRUNC_FRAME (1 << 16)
+#define FIFO_RX_FILT_VLAN_TAG (1 << 15)
+#define FIFO_RX_FILT_UNSUP_OPCODE (1 << 14)
+#define FIFO_RX_FILT_PAUSE_FRAME (1 << 13)
+#define FIFO_RX_FILT_CTRL_FRAME (1 << 12)
+#define FIFO_RX_FILT_LONG_EVENT (1 << 11)
+#define FIFO_RX_FILT_DRIBBLE_NIBBLE (1 << 10)
+#define FIFO_RX_FILT_BCAST (1 << 9)
+#define FIFO_RX_FILT_MCAST (1 << 8)
+#define FIFO_RX_FILT_OK (1 << 7)
+#define FIFO_RX_FILT_OORANGE (1 << 6)
+#define FIFO_RX_FILT_LEN_MSMTCH (1 << 5)
+#define FIFO_RX_FILT_CRC_ERROR (1 << 4)
+#define FIFO_RX_FILT_CODE_ERROR (1 << 3)
+#define FIFO_RX_FILT_FALSE_CARRIER (1 << 2)
+#define FIFO_RX_FILT_RX_DV_EVENT (1 << 1)
+#define FIFO_RX_FILT_DROP_EVENT (1 << 0)
+#define AR71XX_MAC_FIFO_RAM0 0x60
+#define AR71XX_MAC_FIFO_RAM1 0x64
+#define AR71XX_MAC_FIFO_RAM2 0x68
+#define AR71XX_MAC_FIFO_RAM3 0x6C
+#define AR71XX_MAC_FIFO_RAM4 0x70
+#define AR71XX_MAC_FIFO_RAM5 0x74
+#define AR71XX_MAC_FIFO_RAM6 0x78
+#define AR71XX_DMA_TX_CONTROL 0x180
+#define DMA_TX_CONTROL_EN (1 << 0)
+#define AR71XX_DMA_TX_DESC 0x184
+#define AR71XX_DMA_TX_STATUS 0x188
+#define DMA_TX_STATUS_PCOUNT_MASK 0xff
+#define DMA_TX_STATUS_PCOUNT_SHIFT 16
+#define DMA_TX_STATUS_BUS_ERROR (1 << 3)
+#define DMA_TX_STATUS_UNDERRUN (1 << 1)
+#define DMA_TX_STATUS_PKT_SENT (1 << 0)
+#define AR71XX_DMA_RX_CONTROL 0x18C
+#define DMA_RX_CONTROL_EN (1 << 0)
+#define AR71XX_DMA_RX_DESC 0x190
+#define AR71XX_DMA_RX_STATUS 0x194
+#define DMA_RX_STATUS_PCOUNT_MASK 0xff
+#define DMA_RX_STATUS_PCOUNT_SHIFT 16
+#define DMA_RX_STATUS_BUS_ERROR (1 << 3)
+#define DMA_RX_STATUS_OVERFLOW (1 << 1)
+#define DMA_RX_STATUS_PKT_RECVD (1 << 0)
+#define AR71XX_DMA_INTR 0x198
+#define AR71XX_DMA_INTR_STATUS 0x19C
+#define DMA_INTR_ALL ((1 << 8) - 1)
+#define DMA_INTR_RX_BUS_ERROR (1 << 7)
+#define DMA_INTR_RX_OVERFLOW (1 << 6)
+#define DMA_INTR_RX_PKT_RCVD (1 << 4)
+#define DMA_INTR_TX_BUS_ERROR (1 << 3)
+#define DMA_INTR_TX_UNDERRUN (1 << 1)
+#define DMA_INTR_TX_PKT_SENT (1 << 0)
+
+#endif /* _AR71XX_REG_H_ */
diff --git a/sys/mips/atheros/files.ar71xx b/sys/mips/atheros/files.ar71xx
new file mode 100644
index 0000000..78e1d9c
--- /dev/null
+++ b/sys/mips/atheros/files.ar71xx
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+mips/atheros/apb.c standard
+mips/atheros/ar71xx_machdep.c standard
+mips/atheros/ar71xx_ohci.c optional ohci
+mips/atheros/ar71xx_pci.c optional pci
+mips/atheros/if_arge.c optional arge
+mips/atheros/uart_bus_ar71xx.c optional uart
+mips/atheros/uart_cpu_ar71xx.c optional uart
diff --git a/sys/mips/atheros/if_arge.c b/sys/mips/atheros/if_arge.c
new file mode 100644
index 0000000..7dbfe70
--- /dev/null
+++ b/sys/mips/atheros/if_arge.c
@@ -0,0 +1,1657 @@
+/*-
+ * Copyright (c) 2009, 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 unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * AR71XX gigabit ethernet 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/cache.h>
+#include <machine/resource.h>
+#include <vm/vm_param.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/pmap.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(arge, ether, 1, 1, 1);
+MODULE_DEPEND(arge, miibus, 1, 1, 1);
+
+#include "miibus_if.h"
+
+#include <mips/atheros/ar71xxreg.h>
+#include <mips/atheros/if_argevar.h>
+
+#undef ARGE_DEBUG
+#ifdef ARGE_DEBUG
+#define dprintf printf
+#else
+#define dprintf(x, arg...)
+#endif
+
+static int arge_attach(device_t);
+static int arge_detach(device_t);
+static int arge_fix_chain(struct mbuf **mp);
+static void arge_flush_ddr(struct arge_softc *);
+static int arge_ifmedia_upd(struct ifnet *);
+static void arge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int arge_ioctl(struct ifnet *, u_long, caddr_t);
+static void arge_init(void *);
+static void arge_init_locked(struct arge_softc *);
+static void arge_link_task(void *, int);
+static int arge_miibus_readreg(device_t, int, int);
+static void arge_miibus_statchg(device_t);
+static int arge_miibus_writereg(device_t, int, int, int);
+static int arge_probe(device_t);
+static void arge_reset_dma(struct arge_softc *);
+static int arge_resume(device_t);
+static int arge_rx_ring_init(struct arge_softc *);
+static int arge_tx_ring_init(struct arge_softc *);
+static void arge_shutdown(device_t);
+static void arge_start(struct ifnet *);
+static void arge_start_locked(struct ifnet *);
+static void arge_stop(struct arge_softc *);
+static int arge_suspend(device_t);
+
+static void arge_rx_locked(struct arge_softc *);
+static void arge_tx_locked(struct arge_softc *);
+static void arge_intr(void *);
+static int arge_intr_filter(void *);
+static void arge_tx_intr(struct arge_softc *, uint32_t);
+static void arge_rx_intr(struct arge_softc *, uint32_t);
+static void arge_tick(void *);
+
+static void arge_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+static int arge_dma_alloc(struct arge_softc *);
+static void arge_dma_free(struct arge_softc *);
+static int arge_newbuf(struct arge_softc *, int);
+static __inline void arge_fixup_rx(struct mbuf *);
+
+static device_method_t arge_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, arge_probe),
+ DEVMETHOD(device_attach, arge_attach),
+ DEVMETHOD(device_detach, arge_detach),
+ DEVMETHOD(device_suspend, arge_suspend),
+ DEVMETHOD(device_resume, arge_resume),
+ DEVMETHOD(device_shutdown, arge_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, arge_miibus_readreg),
+ DEVMETHOD(miibus_writereg, arge_miibus_writereg),
+ DEVMETHOD(miibus_statchg, arge_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t arge_driver = {
+ "arge",
+ arge_methods,
+ sizeof(struct arge_softc)
+};
+
+static devclass_t arge_devclass;
+
+DRIVER_MODULE(arge, nexus, arge_driver, arge_devclass, 0, 0);
+DRIVER_MODULE(miibus, arge, miibus_driver, miibus_devclass, 0, 0);
+
+/*
+ * Flushes all
+ */
+static void
+arge_flush_ddr(struct arge_softc *sc)
+{
+
+ ATH_WRITE_REG(sc->arge_ddr_flush_reg, 1);
+ while (ATH_READ_REG(sc->arge_ddr_flush_reg) & 1)
+ ;
+
+ ATH_WRITE_REG(sc->arge_ddr_flush_reg, 1);
+ while (ATH_READ_REG(sc->arge_ddr_flush_reg) & 1)
+ ;
+}
+
+static int
+arge_probe(device_t dev)
+{
+
+ device_set_desc(dev, "Atheros AR71xx built-in ethernet interface");
+ return (0);
+}
+
+static int
+arge_attach(device_t dev)
+{
+ uint8_t eaddr[ETHER_ADDR_LEN];
+ struct ifnet *ifp;
+ struct arge_softc *sc;
+ int error = 0, rid, phynum;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+ sc->arge_dev = dev;
+ sc->arge_mac_unit = device_get_unit(dev);
+
+ KASSERT(((sc->arge_mac_unit == 0) || (sc->arge_mac_unit == 1)),
+ ("if_arge: Only MAC0 and MAC1 supported"));
+ if (sc->arge_mac_unit == 0) {
+ sc->arge_ddr_flush_reg = AR71XX_WB_FLUSH_GE0;
+ sc->arge_pll_reg = AR71XX_PLL_ETH_INT0_CLK;
+ } else {
+ sc->arge_ddr_flush_reg = AR71XX_WB_FLUSH_GE1;
+ sc->arge_pll_reg = AR71XX_PLL_ETH_INT1_CLK;
+ }
+
+ /*
+ * Get which PHY of 5 available we should use for this unit
+ */
+ if (resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "phy", &phynum) != 0) {
+ /*
+ * Use port 4 (WAN) for GE0. For any other port use
+ * its PHY the same as its unit number
+ */
+ if (sc->arge_mac_unit == 0)
+ phynum = 4;
+ else
+ phynum = sc->arge_mac_unit;
+
+ device_printf(dev, "No PHY specified, using %d\n", phynum);
+ }
+
+ sc->arge_phy_num = phynum;
+
+
+ mtx_init(&sc->arge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF);
+ callout_init_mtx(&sc->arge_stat_callout, &sc->arge_mtx, 0);
+ TASK_INIT(&sc->arge_link_task, 0, arge_link_task, sc);
+
+ /* Map control/status registers. */
+ sc->arge_rid = 0;
+ sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->arge_rid, RF_ACTIVE);
+
+ if (sc->arge_res == NULL) {
+ device_printf(dev, "couldn't map memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Allocate interrupts */
+ rid = 0;
+ sc->arge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->arge_irq == NULL) {
+ device_printf(dev, "couldn't map interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Allocate ifnet structure. */
+ ifp = sc->arge_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 = arge_ioctl;
+ ifp->if_start = arge_start;
+ ifp->if_init = arge_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] = 0x15;
+ eaddr[2] = 0x6d;
+ eaddr[3] = 0xc1;
+ eaddr[4] = 0x28;
+ eaddr[5] = 0x2e;
+
+ if (arge_dma_alloc(sc) != 0) {
+ error = ENXIO;
+ goto fail;
+ }
+
+ ARGE_WRITE(sc, AR71XX_MAC_CFG1,
+ MAC_CFG1_SYNC_RX | MAC_CFG1_RX_ENABLE |
+ MAC_CFG1_SYNC_TX | MAC_CFG1_TX_ENABLE);
+
+ reg = ARGE_READ(sc, AR71XX_MAC_CFG2);
+ reg |= MAC_CFG2_ENABLE_PADCRC | MAC_CFG2_LENGTH_FIELD ;
+ ARGE_WRITE(sc, AR71XX_MAC_CFG2, reg);
+
+ ARGE_WRITE(sc, AR71XX_MAC_MAX_FRAME_LEN, 1536);
+
+ /* Reset MII bus */
+ ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_RESET);
+ DELAY(100);
+ ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_CLOCK_DIV_28);
+ DELAY(100);
+
+ /*
+ * Set all Ethernet address registers to the same initial values
+ * set all four addresses to 66-88-aa-cc-dd-ee
+ */
+ ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR1, 0x6dc1282e);
+ ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR2, 0x00000015);
+
+ ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG0,
+ FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT);
+ ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0fff0000);
+ ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x00001fff);
+
+ reg = FIFO_RX_FILTMATCH_ALL;
+ ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMATCH, reg);
+
+ reg = FIFO_RX_FILTMASK_ALL;
+ reg &= ~FIFO_RX_FILTMASK_BYTE_MODE;
+ ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK, reg);
+
+ /* Do MII setup. */
+ if (mii_phy_probe(dev, &sc->arge_miibus,
+ arge_ifmedia_upd, arge_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->arge_irq, INTR_TYPE_NET | INTR_MPSAFE,
+ arge_intr_filter, arge_intr, sc, &sc->arge_intrhand);
+
+ if (error) {
+ device_printf(dev, "couldn't set up irq\n");
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+
+fail:
+ if (error)
+ arge_detach(dev);
+
+ return (error);
+}
+
+static int
+arge_detach(device_t dev)
+{
+ struct arge_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = sc->arge_ifp;
+
+ KASSERT(mtx_initialized(&sc->arge_mtx), ("arge mutex not initialized"));
+
+ /* These should only be active if attach succeeded */
+ if (device_is_attached(dev)) {
+ ARGE_LOCK(sc);
+ sc->arge_detach = 1;
+ arge_stop(sc);
+ ARGE_UNLOCK(sc);
+ taskqueue_drain(taskqueue_swi, &sc->arge_link_task);
+ ether_ifdetach(ifp);
+ }
+
+ if (sc->arge_miibus)
+ device_delete_child(dev, sc->arge_miibus);
+ bus_generic_detach(dev);
+
+ if (sc->arge_intrhand)
+ bus_teardown_intr(dev, sc->arge_irq, sc->arge_intrhand);
+
+ if (sc->arge_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->arge_rid,
+ sc->arge_res);
+
+ if (ifp)
+ if_free(ifp);
+
+ arge_dma_free(sc);
+
+ mtx_destroy(&sc->arge_mtx);
+
+ return (0);
+
+}
+
+static int
+arge_suspend(device_t dev)
+{
+
+ panic("%s", __func__);
+ return 0;
+}
+
+static int
+arge_resume(device_t dev)
+{
+
+ panic("%s", __func__);
+ return 0;
+}
+
+static void
+arge_shutdown(device_t dev)
+{
+ struct arge_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ ARGE_LOCK(sc);
+ arge_stop(sc);
+ ARGE_UNLOCK(sc);
+}
+
+static int
+arge_miibus_readreg(device_t dev, int phy, int reg)
+{
+ struct arge_softc * sc = device_get_softc(dev);
+ int i, result;
+ uint32_t addr = 0x1000 | (phy << MAC_MII_PHY_ADDR_SHIFT)
+ | (reg & MAC_MII_REG_MASK);
+
+ if (phy != sc->arge_phy_num)
+ return (0);
+
+ ARGE_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
+ ARGE_WRITE(sc, AR71XX_MAC_MII_ADDR, addr);
+ ARGE_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_READ);
+
+ i = ARGE_MII_TIMEOUT;
+ while ((ARGE_READ(sc, AR71XX_MAC_MII_INDICATOR) &
+ MAC_MII_INDICATOR_BUSY) && (i--))
+ DELAY(5);
+
+ if (i < 0) {
+ dprintf("%s timedout\n", __func__);
+ /* XXX: return ERRNO istead? */
+ return (-1);
+ }
+
+ result = ARGE_READ(sc, AR71XX_MAC_MII_STATUS) & MAC_MII_STATUS_MASK;
+ ARGE_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
+ dprintf("%s: phy=%d, reg=%02x, value[%08x]=%04x\n", __func__,
+ phy, reg, addr, result);
+
+ return (result);
+}
+
+static int
+arge_miibus_writereg(device_t dev, int phy, int reg, int data)
+{
+ struct arge_softc * sc = device_get_softc(dev);
+ int i;
+ uint32_t addr = 0x1000
+ | (phy << MAC_MII_PHY_ADDR_SHIFT) | (reg & MAC_MII_REG_MASK);
+
+ dprintf("%s: phy=%d, reg=%02x, value=%04x\n", __func__,
+ phy, reg, data);
+
+ ARGE_WRITE(sc, AR71XX_MAC_MII_ADDR, addr);
+ ARGE_WRITE(sc, AR71XX_MAC_MII_CONTROL, data);
+
+ i = ARGE_MII_TIMEOUT;
+ while ((ARGE_READ(sc, AR71XX_MAC_MII_INDICATOR) &
+ MAC_MII_INDICATOR_BUSY) && (i--))
+ DELAY(5);
+
+ if (i < 0) {
+ dprintf("%s timedout\n", __func__);
+ /* XXX: return ERRNO istead? */
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+arge_miibus_statchg(device_t dev)
+{
+ struct arge_softc *sc;
+
+ sc = device_get_softc(dev);
+ taskqueue_enqueue(taskqueue_swi, &sc->arge_link_task);
+}
+
+static void
+arge_link_task(void *arg, int pending)
+{
+ struct arge_softc *sc;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ uint32_t media;
+ uint32_t cfg, ifcontrol, rx_filtmask, pll, sec_cfg;
+
+ sc = (struct arge_softc *)arg;
+
+ ARGE_LOCK(sc);
+ mii = device_get_softc(sc->arge_miibus);
+ ifp = sc->arge_ifp;
+ if (mii == NULL || ifp == NULL ||
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ ARGE_UNLOCK(sc);
+ return;
+ }
+
+ if (mii->mii_media_status & IFM_ACTIVE) {
+
+ media = IFM_SUBTYPE(mii->mii_media_active);
+
+ if (media != IFM_NONE) {
+ sc->arge_link_status = 1;
+
+ cfg = ARGE_READ(sc, AR71XX_MAC_CFG2);
+ ifcontrol = ARGE_READ(sc, AR71XX_MAC_IFCONTROL);
+ rx_filtmask =
+ ARGE_READ(sc, AR71XX_MAC_FIFO_RX_FILTMASK);
+
+ cfg &= ~(MAC_CFG2_IFACE_MODE_1000
+ | MAC_CFG2_IFACE_MODE_10_100
+ | MAC_CFG2_FULL_DUPLEX);
+ ifcontrol &= ~MAC_IFCONTROL_SPEED;
+ rx_filtmask &= ~FIFO_RX_FILTMASK_BYTE_MODE;
+
+ switch(media) {
+ case IFM_10_T:
+ cfg |= MAC_CFG2_IFACE_MODE_10_100;
+ pll = PLL_ETH_INT_CLK_10;
+ break;
+ case IFM_100_TX:
+ cfg |= MAC_CFG2_IFACE_MODE_10_100;
+ ifcontrol |= MAC_IFCONTROL_SPEED;
+ pll = PLL_ETH_INT_CLK_100;
+ break;
+ case IFM_1000_T:
+ case IFM_1000_SX:
+ cfg |= MAC_CFG2_IFACE_MODE_1000;
+ rx_filtmask |= FIFO_RX_FILTMASK_BYTE_MODE;
+ pll = PLL_ETH_INT_CLK_1000;
+ break;
+ default:
+ pll = PLL_ETH_INT_CLK_100;
+ device_printf(sc->arge_dev,
+ "Unknown media %d\n", media);
+ }
+
+ ARGE_WRITE(sc, AR71XX_MAC_FIFO_TX_THRESHOLD,
+ 0x008001ff);
+
+ ARGE_WRITE(sc, AR71XX_MAC_CFG2, cfg);
+ ARGE_WRITE(sc, AR71XX_MAC_IFCONTROL, ifcontrol);
+ ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK,
+ rx_filtmask);
+
+ /* set PLL registers */
+ sec_cfg = ATH_READ_REG(AR71XX_PLL_CPU_CONFIG);
+ sec_cfg &= ~(3 << 17);
+ sec_cfg |= (2 << 17);
+
+ ATH_WRITE_REG(AR71XX_PLL_CPU_CONFIG, sec_cfg);
+ DELAY(100);
+
+ ATH_WRITE_REG(sc->arge_pll_reg, pll);
+
+ sec_cfg |= (3 << 17);
+ ATH_WRITE_REG(AR71XX_PLL_CPU_CONFIG, sec_cfg);
+ DELAY(100);
+
+ sec_cfg &= ~(3 << 17);
+ ATH_WRITE_REG(AR71XX_PLL_CPU_CONFIG, sec_cfg);
+ DELAY(100);
+ }
+ } else
+ sc->arge_link_status = 0;
+
+ ARGE_UNLOCK(sc);
+}
+
+static void
+arge_reset_dma(struct arge_softc *sc)
+{
+ unsigned int i;
+
+ ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, 0);
+ ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, 0);
+
+ ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, 0);
+ ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, 0);
+
+ /* Clear all possible RX interrupts */
+ for (i = 0; i < ARGE_RX_RING_COUNT; i++)
+ ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD);
+
+ /*
+ * Clear all possible TX interrupts
+ */
+ for (i = 0; i < ARGE_TX_RING_COUNT; i++)
+ ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT);
+
+ /*
+ * Now Rx/Tx errors
+ */
+ ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS,
+ DMA_RX_STATUS_BUS_ERROR | DMA_RX_STATUS_OVERFLOW);
+ ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS,
+ DMA_TX_STATUS_BUS_ERROR | DMA_TX_STATUS_UNDERRUN);
+}
+
+
+
+static void
+arge_init(void *xsc)
+{
+ struct arge_softc *sc = xsc;
+
+ ARGE_LOCK(sc);
+ arge_init_locked(sc);
+ ARGE_UNLOCK(sc);
+}
+
+static void
+arge_init_locked(struct arge_softc *sc)
+{
+ struct ifnet *ifp = sc->arge_ifp;
+ struct mii_data *mii;
+
+ ARGE_LOCK_ASSERT(sc);
+
+ mii = device_get_softc(sc->arge_miibus);
+
+ arge_stop(sc);
+
+ /* Init circular RX list. */
+ if (arge_rx_ring_init(sc) != 0) {
+ device_printf(sc->arge_dev,
+ "initialization failed: no memory for rx buffers\n");
+ arge_stop(sc);
+ return;
+ }
+
+ /* Init tx descriptors. */
+ arge_tx_ring_init(sc);
+
+ arge_reset_dma(sc);
+
+ sc->arge_link_status = 0;
+ mii_mediachg(mii);
+
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc);
+ ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, ARGE_TX_RING_ADDR(sc, 0));
+ ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, ARGE_RX_RING_ADDR(sc, 0));
+
+ /* Start listening */
+ ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN);
+
+ /* Enable interrupts */
+ ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int
+arge_encap(struct arge_softc *sc, struct mbuf **m_head)
+{
+ struct arge_txdesc *txd;
+ struct arge_desc *desc, *prev_desc;
+ bus_dma_segment_t txsegs[ARGE_MAXFRAGS];
+ int error, i, nsegs, prod, si, prev_prod;
+
+ ARGE_LOCK_ASSERT(sc);
+
+ prod = sc->arge_cdata.arge_tx_prod;
+ txd = &sc->arge_cdata.arge_txdesc[prod];
+ error = bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_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->arge_cdata.arge_tx_cnt + nsegs >= (ARGE_TX_RING_COUNT - 1)) {
+ bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap);
+ return (ENOBUFS);
+ }
+
+ txd->tx_m = *m_head;
+ bus_dmamap_sync(sc->arge_cdata.arge_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 arge_link is not zero.
+ */
+ prev_prod = prod;
+ desc = prev_desc = NULL;
+ for (i = 0; i < nsegs; i++) {
+ desc = &sc->arge_rdata.arge_tx_ring[prod];
+ desc->packet_ctrl = ARGE_DMASIZE(txsegs[i].ds_len);
+
+ desc->packet_addr = txsegs[i].ds_addr;
+ /* link with previous descriptor */
+ if (prev_desc)
+ prev_desc->packet_ctrl |= ARGE_DESC_MORE;
+
+ sc->arge_cdata.arge_tx_cnt++;
+ prev_desc = desc;
+ ARGE_INC(prod, ARGE_TX_RING_COUNT);
+ }
+
+ /* Update producer index. */
+ sc->arge_cdata.arge_tx_prod = prod;
+
+ /* Sync descriptors. */
+ bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
+ sc->arge_cdata.arge_tx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /* Start transmitting */
+ ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, DMA_TX_CONTROL_EN);
+ return (0);
+}
+
+static void
+arge_start(struct ifnet *ifp)
+{
+ struct arge_softc *sc;
+
+ sc = ifp->if_softc;
+
+ ARGE_LOCK(sc);
+ arge_start_locked(ifp);
+ ARGE_UNLOCK(sc);
+}
+
+static void
+arge_start_locked(struct ifnet *ifp)
+{
+ struct arge_softc *sc;
+ struct mbuf *m_head;
+ int enq;
+
+ sc = ifp->if_softc;
+
+ ARGE_LOCK_ASSERT(sc);
+
+ if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING || sc->arge_link_status == 0 )
+ return;
+
+ arge_flush_ddr(sc);
+
+ for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
+ sc->arge_cdata.arge_tx_cnt < ARGE_TX_RING_COUNT - 2; ) {
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ /*
+ * Fix mbuf chain, all fragments should be 4 bytes aligned and
+ * even 4 bytes
+ */
+ arge_fix_chain(&m_head);
+
+ if (m_head == NULL) {
+ dprintf("failed to adjust mbuf chain\n");
+ }
+
+ /*
+ * Pack the data into the transmit ring.
+ */
+ if (arge_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
+arge_stop(struct arge_softc *sc)
+{
+ struct ifnet *ifp;
+
+ ARGE_LOCK_ASSERT(sc);
+
+ ifp = sc->arge_ifp;
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ callout_stop(&sc->arge_stat_callout);
+
+ /* mask out interrupts */
+ ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
+
+ arge_reset_dma(sc);
+}
+
+
+static int
+arge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct arge_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
+ int error;
+
+ switch (command) {
+ case SIOCSIFFLAGS:
+ printf("Implement me: SIOCSIFFLAGS\n");
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ printf("Implement me: SIOCDELMULTI\n");
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ printf("Implement me: SIOCSIFMEDIA\n");
+ mii = device_get_softc(sc->arge_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ case SIOCSIFCAP:
+ error = 0;
+ ifp->if_hwassist = 0;
+ printf("Implement me: SIOCSIFCAP\n");
+ break;
+ default:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ }
+
+ return (error);
+}
+
+/*
+ * Set media options.
+ */
+static int
+arge_ifmedia_upd(struct ifnet *ifp)
+{
+ struct arge_softc *sc;
+ struct mii_data *mii;
+ struct mii_softc *miisc;
+ int error;
+
+ sc = ifp->if_softc;
+ ARGE_LOCK(sc);
+ mii = device_get_softc(sc->arge_miibus);
+ if (mii->mii_instance) {
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ mii_phy_reset(miisc);
+ }
+ error = mii_mediachg(mii);
+ ARGE_UNLOCK(sc);
+
+ return (error);
+}
+
+/*
+ * Report current media status.
+ */
+static void
+arge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct arge_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+
+ mii = device_get_softc(sc->arge_miibus);
+ ARGE_LOCK(sc);
+ mii_pollstat(mii);
+ ARGE_UNLOCK(sc);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+}
+
+struct arge_dmamap_arg {
+ bus_addr_t arge_busaddr;
+};
+
+static void
+arge_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct arge_dmamap_arg *ctx;
+
+ if (error != 0)
+ return;
+ ctx = arg;
+ ctx->arge_busaddr = segs[0].ds_addr;
+}
+
+static int
+arge_dma_alloc(struct arge_softc *sc)
+{
+ struct arge_dmamap_arg ctx;
+ struct arge_txdesc *txd;
+ struct arge_rxdesc *rxd;
+ int error, i;
+
+ /* Create parent DMA tag. */
+ error = bus_dma_tag_create(
+ bus_get_dma_tag(sc->arge_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->arge_cdata.arge_parent_tag);
+ if (error != 0) {
+ device_printf(sc->arge_dev, "failed to create parent DMA tag\n");
+ goto fail;
+ }
+ /* Create tag for Tx ring. */
+ error = bus_dma_tag_create(
+ sc->arge_cdata.arge_parent_tag, /* parent */
+ ARGE_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ ARGE_TX_DMA_SIZE, /* maxsize */
+ 1, /* nsegments */
+ ARGE_TX_DMA_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->arge_cdata.arge_tx_ring_tag);
+ if (error != 0) {
+ device_printf(sc->arge_dev, "failed to create Tx ring DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Rx ring. */
+ error = bus_dma_tag_create(
+ sc->arge_cdata.arge_parent_tag, /* parent */
+ ARGE_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ ARGE_RX_DMA_SIZE, /* maxsize */
+ 1, /* nsegments */
+ ARGE_RX_DMA_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->arge_cdata.arge_rx_ring_tag);
+ if (error != 0) {
+ device_printf(sc->arge_dev, "failed to create Rx ring DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Tx buffers. */
+ error = bus_dma_tag_create(
+ sc->arge_cdata.arge_parent_tag, /* parent */
+ sizeof(uint32_t), 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MCLBYTES * ARGE_MAXFRAGS, /* maxsize */
+ ARGE_MAXFRAGS, /* nsegments */
+ MCLBYTES, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->arge_cdata.arge_tx_tag);
+ if (error != 0) {
+ device_printf(sc->arge_dev, "failed to create Tx DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Rx buffers. */
+ error = bus_dma_tag_create(
+ sc->arge_cdata.arge_parent_tag, /* parent */
+ ARGE_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->arge_cdata.arge_rx_tag);
+ if (error != 0) {
+ device_printf(sc->arge_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->arge_cdata.arge_tx_ring_tag,
+ (void **)&sc->arge_rdata.arge_tx_ring, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->arge_cdata.arge_tx_ring_map);
+ if (error != 0) {
+ device_printf(sc->arge_dev,
+ "failed to allocate DMA'able memory for Tx ring\n");
+ goto fail;
+ }
+
+ ctx.arge_busaddr = 0;
+ error = bus_dmamap_load(sc->arge_cdata.arge_tx_ring_tag,
+ sc->arge_cdata.arge_tx_ring_map, sc->arge_rdata.arge_tx_ring,
+ ARGE_TX_DMA_SIZE, arge_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.arge_busaddr == 0) {
+ device_printf(sc->arge_dev,
+ "failed to load DMA'able memory for Tx ring\n");
+ goto fail;
+ }
+ sc->arge_rdata.arge_tx_ring_paddr = ctx.arge_busaddr;
+
+ /* Allocate DMA'able memory and load the DMA map for Rx ring. */
+ error = bus_dmamem_alloc(sc->arge_cdata.arge_rx_ring_tag,
+ (void **)&sc->arge_rdata.arge_rx_ring, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->arge_cdata.arge_rx_ring_map);
+ if (error != 0) {
+ device_printf(sc->arge_dev,
+ "failed to allocate DMA'able memory for Rx ring\n");
+ goto fail;
+ }
+
+ ctx.arge_busaddr = 0;
+ error = bus_dmamap_load(sc->arge_cdata.arge_rx_ring_tag,
+ sc->arge_cdata.arge_rx_ring_map, sc->arge_rdata.arge_rx_ring,
+ ARGE_RX_DMA_SIZE, arge_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.arge_busaddr == 0) {
+ device_printf(sc->arge_dev,
+ "failed to load DMA'able memory for Rx ring\n");
+ goto fail;
+ }
+ sc->arge_rdata.arge_rx_ring_paddr = ctx.arge_busaddr;
+
+ /* Create DMA maps for Tx buffers. */
+ for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
+ txd = &sc->arge_cdata.arge_txdesc[i];
+ txd->tx_m = NULL;
+ txd->tx_dmamap = NULL;
+ error = bus_dmamap_create(sc->arge_cdata.arge_tx_tag, 0,
+ &txd->tx_dmamap);
+ if (error != 0) {
+ device_printf(sc->arge_dev,
+ "failed to create Tx dmamap\n");
+ goto fail;
+ }
+ }
+ /* Create DMA maps for Rx buffers. */
+ if ((error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0,
+ &sc->arge_cdata.arge_rx_sparemap)) != 0) {
+ device_printf(sc->arge_dev,
+ "failed to create spare Rx dmamap\n");
+ goto fail;
+ }
+ for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
+ rxd = &sc->arge_cdata.arge_rxdesc[i];
+ rxd->rx_m = NULL;
+ rxd->rx_dmamap = NULL;
+ error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0,
+ &rxd->rx_dmamap);
+ if (error != 0) {
+ device_printf(sc->arge_dev,
+ "failed to create Rx dmamap\n");
+ goto fail;
+ }
+ }
+
+fail:
+ return (error);
+}
+
+static void
+arge_dma_free(struct arge_softc *sc)
+{
+ struct arge_txdesc *txd;
+ struct arge_rxdesc *rxd;
+ int i;
+
+ /* Tx ring. */
+ if (sc->arge_cdata.arge_tx_ring_tag) {
+ if (sc->arge_cdata.arge_tx_ring_map)
+ bus_dmamap_unload(sc->arge_cdata.arge_tx_ring_tag,
+ sc->arge_cdata.arge_tx_ring_map);
+ if (sc->arge_cdata.arge_tx_ring_map &&
+ sc->arge_rdata.arge_tx_ring)
+ bus_dmamem_free(sc->arge_cdata.arge_tx_ring_tag,
+ sc->arge_rdata.arge_tx_ring,
+ sc->arge_cdata.arge_tx_ring_map);
+ sc->arge_rdata.arge_tx_ring = NULL;
+ sc->arge_cdata.arge_tx_ring_map = NULL;
+ bus_dma_tag_destroy(sc->arge_cdata.arge_tx_ring_tag);
+ sc->arge_cdata.arge_tx_ring_tag = NULL;
+ }
+ /* Rx ring. */
+ if (sc->arge_cdata.arge_rx_ring_tag) {
+ if (sc->arge_cdata.arge_rx_ring_map)
+ bus_dmamap_unload(sc->arge_cdata.arge_rx_ring_tag,
+ sc->arge_cdata.arge_rx_ring_map);
+ if (sc->arge_cdata.arge_rx_ring_map &&
+ sc->arge_rdata.arge_rx_ring)
+ bus_dmamem_free(sc->arge_cdata.arge_rx_ring_tag,
+ sc->arge_rdata.arge_rx_ring,
+ sc->arge_cdata.arge_rx_ring_map);
+ sc->arge_rdata.arge_rx_ring = NULL;
+ sc->arge_cdata.arge_rx_ring_map = NULL;
+ bus_dma_tag_destroy(sc->arge_cdata.arge_rx_ring_tag);
+ sc->arge_cdata.arge_rx_ring_tag = NULL;
+ }
+ /* Tx buffers. */
+ if (sc->arge_cdata.arge_tx_tag) {
+ for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
+ txd = &sc->arge_cdata.arge_txdesc[i];
+ if (txd->tx_dmamap) {
+ bus_dmamap_destroy(sc->arge_cdata.arge_tx_tag,
+ txd->tx_dmamap);
+ txd->tx_dmamap = NULL;
+ }
+ }
+ bus_dma_tag_destroy(sc->arge_cdata.arge_tx_tag);
+ sc->arge_cdata.arge_tx_tag = NULL;
+ }
+ /* Rx buffers. */
+ if (sc->arge_cdata.arge_rx_tag) {
+ for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
+ rxd = &sc->arge_cdata.arge_rxdesc[i];
+ if (rxd->rx_dmamap) {
+ bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag,
+ rxd->rx_dmamap);
+ rxd->rx_dmamap = NULL;
+ }
+ }
+ if (sc->arge_cdata.arge_rx_sparemap) {
+ bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag,
+ sc->arge_cdata.arge_rx_sparemap);
+ sc->arge_cdata.arge_rx_sparemap = 0;
+ }
+ bus_dma_tag_destroy(sc->arge_cdata.arge_rx_tag);
+ sc->arge_cdata.arge_rx_tag = NULL;
+ }
+
+ if (sc->arge_cdata.arge_parent_tag) {
+ bus_dma_tag_destroy(sc->arge_cdata.arge_parent_tag);
+ sc->arge_cdata.arge_parent_tag = NULL;
+ }
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int
+arge_tx_ring_init(struct arge_softc *sc)
+{
+ struct arge_ring_data *rd;
+ struct arge_txdesc *txd;
+ bus_addr_t addr;
+ int i;
+
+ sc->arge_cdata.arge_tx_prod = 0;
+ sc->arge_cdata.arge_tx_cons = 0;
+ sc->arge_cdata.arge_tx_cnt = 0;
+ sc->arge_cdata.arge_tx_pkts = 0;
+
+ rd = &sc->arge_rdata;
+ bzero(rd->arge_tx_ring, sizeof(rd->arge_tx_ring));
+ for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
+ if (i == ARGE_TX_RING_COUNT - 1)
+ addr = ARGE_TX_RING_ADDR(sc, 0);
+ else
+ addr = ARGE_TX_RING_ADDR(sc, i + 1);
+ rd->arge_tx_ring[i].packet_ctrl = ARGE_DESC_EMPTY;
+ rd->arge_tx_ring[i].next_desc = addr;
+ txd = &sc->arge_cdata.arge_txdesc[i];
+ txd->tx_m = NULL;
+ }
+
+ bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
+ sc->arge_cdata.arge_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
+arge_rx_ring_init(struct arge_softc *sc)
+{
+ struct arge_ring_data *rd;
+ struct arge_rxdesc *rxd;
+ bus_addr_t addr;
+ int i;
+
+ sc->arge_cdata.arge_rx_cons = 0;
+
+ rd = &sc->arge_rdata;
+ bzero(rd->arge_rx_ring, sizeof(rd->arge_rx_ring));
+ for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
+ rxd = &sc->arge_cdata.arge_rxdesc[i];
+ rxd->rx_m = NULL;
+ rxd->desc = &rd->arge_rx_ring[i];
+ if (i == ARGE_RX_RING_COUNT - 1)
+ addr = ARGE_RX_RING_ADDR(sc, 0);
+ else
+ addr = ARGE_RX_RING_ADDR(sc, i + 1);
+ rd->arge_rx_ring[i].packet_ctrl = ARGE_DESC_EMPTY;
+ rd->arge_rx_ring[i].next_desc = addr;
+ if (arge_newbuf(sc, i) != 0)
+ return (ENOBUFS);
+ }
+
+ bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
+ sc->arge_cdata.arge_rx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int
+arge_newbuf(struct arge_softc *sc, int idx)
+{
+ struct arge_desc *desc;
+ struct arge_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->arge_cdata.arge_rx_tag,
+ sc->arge_cdata.arge_rx_sparemap, m, segs, &nsegs, 0) != 0) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
+
+ rxd = &sc->arge_cdata.arge_rxdesc[idx];
+ if (rxd->rx_m != NULL) {
+ bus_dmamap_sync(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap);
+ }
+ map = rxd->rx_dmamap;
+ rxd->rx_dmamap = sc->arge_cdata.arge_rx_sparemap;
+ sc->arge_cdata.arge_rx_sparemap = map;
+ bus_dmamap_sync(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_PREREAD);
+ rxd->rx_m = m;
+ desc = rxd->desc;
+ desc->packet_addr = segs[0].ds_addr;
+ desc->packet_ctrl = (desc->packet_ctrl & ~ARGE_DESC_SIZE_MASK)
+ | ARGE_DMASIZE(segs[0].ds_len);
+
+ return (0);
+}
+
+static __inline void
+arge_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
+arge_tx_locked(struct arge_softc *sc)
+{
+ struct arge_txdesc *txd;
+ struct arge_desc *cur_tx;
+ struct ifnet *ifp;
+ uint32_t ctrl;
+ int cons, prod;
+
+ ARGE_LOCK_ASSERT(sc);
+
+ cons = sc->arge_cdata.arge_tx_cons;
+ prod = sc->arge_cdata.arge_tx_prod;
+ if (cons == prod)
+ return;
+
+ bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
+ sc->arge_cdata.arge_tx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ ifp = sc->arge_ifp;
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ for (; cons != prod; ARGE_INC(cons, ARGE_TX_RING_COUNT)) {
+ cur_tx = &sc->arge_rdata.arge_tx_ring[cons];
+ ctrl = cur_tx->packet_ctrl;
+ /* Check if descriptor has "finished" flag */
+ if ((ctrl & ARGE_DESC_EMPTY) == 0)
+ break;
+
+ ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT);
+
+ sc->arge_cdata.arge_tx_cnt--;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ txd = &sc->arge_cdata.arge_txdesc[cons];
+
+ cur_tx->packet_ctrl = ARGE_DESC_EMPTY;
+
+ ifp->if_opackets++;
+
+ bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->arge_cdata.arge_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->packet_ctrl = ARGE_DESC_EMPTY;
+ cur_tx->packet_addr = 0;
+ }
+
+ sc->arge_cdata.arge_tx_cons = cons;
+
+ bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
+ sc->arge_cdata.arge_tx_ring_map, BUS_DMASYNC_PREWRITE);
+}
+
+
+static void
+arge_rx_locked(struct arge_softc *sc)
+{
+ struct arge_rxdesc *rxd;
+ struct ifnet *ifp = sc->arge_ifp;
+ int cons, prog, packet_len;
+ struct arge_desc *cur_rx;
+ struct mbuf *m;
+
+ ARGE_LOCK_ASSERT(sc);
+
+ cons = sc->arge_cdata.arge_rx_cons;
+
+ bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
+ sc->arge_cdata.arge_rx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ for (prog = 0; prog < ARGE_RX_RING_COUNT;
+ ARGE_INC(cons, ARGE_RX_RING_COUNT)) {
+ cur_rx = &sc->arge_rdata.arge_rx_ring[cons];
+ rxd = &sc->arge_cdata.arge_rxdesc[cons];
+ m = rxd->rx_m;
+
+ if ((cur_rx->packet_ctrl & ARGE_DESC_EMPTY) != 0)
+ break;
+
+ ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD);
+
+ prog++;
+
+ packet_len = ARGE_DMASIZE(cur_rx->packet_ctrl);
+ bus_dmamap_sync(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_PREREAD);
+ m = rxd->rx_m;
+
+ arge_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++;
+
+ ARGE_UNLOCK(sc);
+ (*ifp->if_input)(ifp, m);
+ ARGE_LOCK(sc);
+
+ /* Reinit descriptor */
+ cur_rx->packet_ctrl = ARGE_DESC_EMPTY;
+ cur_rx->packet_addr = 0;
+ if (arge_newbuf(sc, cons) != 0) {
+ device_printf(sc->arge_dev,
+ "Failed to allocate buffer\n");
+ break;
+ }
+
+ bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
+ sc->arge_cdata.arge_rx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ }
+
+ if (prog > 0) {
+ sc->arge_cdata.arge_rx_cons = cons;
+
+ bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
+ sc->arge_cdata.arge_rx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ }
+}
+
+static void
+arge_rx_intr(struct arge_softc *sc, uint32_t status)
+{
+
+ ARGE_LOCK(sc);
+ /* interrupts are masked by filter */
+ arge_rx_locked(sc);
+
+ /* unmask interrupts */
+ ARGE_SET_BITS(sc,
+ AR71XX_DMA_INTR, DMA_INTR_RX_OVERFLOW | DMA_INTR_RX_PKT_RCVD);
+ ARGE_UNLOCK(sc);
+}
+
+static int
+arge_intr_filter(void *arg)
+{
+ struct arge_softc *sc = arg;
+ uint32_t status, ints;
+
+ status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS);
+ ints = ARGE_READ(sc, AR71XX_DMA_INTR);
+
+#if 0
+ dprintf("int mask(filter) = %b\n", ints,
+ "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD"
+ "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
+ dprintf("status(filter) = %b\n", status,
+ "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD"
+ "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
+#endif
+
+ if (status & DMA_INTR_ALL) {
+ if (status & (DMA_INTR_RX_PKT_RCVD | DMA_INTR_RX_OVERFLOW))
+ ARGE_CLEAR_BITS(sc, AR71XX_DMA_INTR,
+ DMA_INTR_RX_OVERFLOW | DMA_INTR_RX_PKT_RCVD);
+
+ if (status & (DMA_INTR_TX_PKT_SENT | DMA_INTR_TX_UNDERRUN))
+ ARGE_CLEAR_BITS(sc, AR71XX_DMA_INTR,
+ DMA_INTR_TX_UNDERRUN | DMA_INTR_TX_PKT_SENT);
+
+ sc->arge_intr_status = status;
+ return (FILTER_SCHEDULE_THREAD);
+ }
+
+ sc->arge_intr_status = 0;
+ return (FILTER_STRAY);
+}
+
+static void
+arge_intr(void *arg)
+{
+ struct arge_softc *sc = arg;
+ uint32_t status;
+
+ status = sc->arge_intr_status;
+
+#if 0
+ dprintf("int status(intr) = %b\n", status,
+ "\20\10\7RX_OVERFLOW\5RX_PKT_RCVD"
+ "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
+#endif
+
+ /*
+ * Is it our interrupt at all?
+ */
+ if (status == 0)
+ return;
+
+ if (status & DMA_INTR_RX_BUS_ERROR) {
+ ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_BUS_ERROR);
+ device_printf(sc->arge_dev, "RX bus error");
+ return;
+ }
+
+ if (status & DMA_INTR_TX_BUS_ERROR) {
+ ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_BUS_ERROR);
+ device_printf(sc->arge_dev, "TX bus error");
+ return;
+ }
+
+ if (status & (DMA_INTR_RX_PKT_RCVD | DMA_INTR_RX_OVERFLOW))
+ arge_rx_intr(sc, status);
+
+ if (status & (DMA_INTR_TX_PKT_SENT | DMA_INTR_TX_UNDERRUN))
+ arge_tx_intr(sc, status);
+}
+
+static void
+arge_tx_intr(struct arge_softc *sc, uint32_t status)
+{
+ ARGE_LOCK(sc);
+
+ /* Interrupts are masked by filter */
+ arge_tx_locked(sc);
+
+ ARGE_UNLOCK(sc);
+}
+
+static void
+arge_tick(void *xsc)
+{
+ struct arge_softc *sc = xsc;
+ struct mii_data *mii;
+
+ ARGE_LOCK_ASSERT(sc);
+
+ mii = device_get_softc(sc->arge_miibus);
+ mii_tick(mii);
+ callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc);
+}
+
+/*
+ * Create a copy of a single mbuf. It can have either internal or
+ * external data, it may have a packet header. External data is really
+ * copied, so the new buffer is writeable.
+ */
+static struct mbuf *
+copy_mbuf(struct mbuf *m)
+{
+ struct mbuf *new;
+
+ MGET(new, M_DONTWAIT, MT_DATA);
+ if (new == NULL)
+ return (NULL);
+
+ if (m->m_flags & M_PKTHDR) {
+ M_MOVE_PKTHDR(new, m);
+ if (m->m_len > MHLEN)
+ MCLGET(new, M_WAIT);
+ } else {
+ if (m->m_len > MLEN)
+ MCLGET(new, M_WAIT);
+ }
+
+ bcopy(m->m_data, new->m_data, m->m_len);
+ new->m_len = m->m_len;
+ new->m_flags &= ~M_RDONLY;
+
+ return (new);
+}
+
+
+
+static int
+arge_fix_chain(struct mbuf **mp)
+{
+ struct mbuf *m = *mp, *prev = NULL, *next, *new;
+ u_int mlen = 0, fill = 0;
+ int first, off;
+ u_char *d, *cp;
+
+ do {
+ next = m->m_next;
+
+ if ((uintptr_t)mtod(m, void *) % 4 != 0 ||
+ (m->m_len % 4 != 0 && next)) {
+ /*
+ * Needs fixing
+ */
+ first = (m == *mp);
+
+ d = mtod(m, u_char *);
+ if ((off = (uintptr_t)(void *)d % 4) != 0) {
+ if (M_WRITABLE(m)) {
+ bcopy(d, d - off, m->m_len);
+ m->m_data = (caddr_t)(d - off);
+ } else {
+ if ((new = copy_mbuf(m)) == NULL) {
+ goto fail;
+ }
+ if (prev)
+ prev->m_next = new;
+ new->m_next = next;
+ m_free(m);
+ m = new;
+ }
+ }
+
+ if ((off = m->m_len % 4) != 0) {
+ if (!M_WRITABLE(m)) {
+ if ((new = copy_mbuf(m)) == NULL) {
+ goto fail;
+ }
+ if (prev)
+ prev->m_next = new;
+ new->m_next = next;
+ m_free(m);
+ m = new;
+ }
+ d = mtod(m, u_char *) + m->m_len;
+ off = 4 - off;
+ while (off) {
+ if (next == NULL) {
+ *d++ = 0;
+ fill++;
+ } else if (next->m_len == 0) {
+ next = m_free(next);
+ continue;
+ } else {
+ cp = mtod(next, u_char *);
+ *d++ = *cp++;
+ next->m_len--;
+ next->m_data = (caddr_t)cp;
+ }
+ off--;
+ m->m_len++;
+ }
+ }
+
+ if (first)
+ *mp = m;
+ }
+
+ mlen += m->m_len;
+ prev = m;
+ } while ((m = next) != NULL);
+
+ return (mlen - fill);
+
+ fail:
+ m_freem(*mp);
+ *mp = NULL;
+ return (0);
+}
diff --git a/sys/mips/atheros/if_argevar.h b/sys/mips/atheros/if_argevar.h
new file mode 100644
index 0000000..1966e61
--- /dev/null
+++ b/sys/mips/atheros/if_argevar.h
@@ -0,0 +1,138 @@
+/*-
+ * Copyright (c) 2009, 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 unmodified, 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.
+ */
+
+#ifndef __IF_ARGEVAR_H__
+#define __IF_ARGEVAR_H__
+
+#define ARGE_TX_RING_COUNT 128
+#define ARGE_RX_RING_COUNT 128
+#define ARGE_RX_DMA_SIZE ARGE_RX_RING_COUNT * sizeof(struct arge_desc)
+#define ARGE_TX_DMA_SIZE ARGE_TX_RING_COUNT * sizeof(struct arge_desc)
+#define ARGE_MAXFRAGS 8
+#define ARGE_RING_ALIGN sizeof(struct arge_desc)
+#define ARGE_RX_ALIGN sizeof(uint32_t)
+#define ARGE_MAXFRAGS 8
+#define ARGE_TX_RING_ADDR(sc, i) \
+ ((sc)->arge_rdata.arge_tx_ring_paddr + sizeof(struct arge_desc) * (i))
+#define ARGE_RX_RING_ADDR(sc, i) \
+ ((sc)->arge_rdata.arge_rx_ring_paddr + sizeof(struct arge_desc) * (i))
+#define ARGE_INC(x,y) (x) = (((x) + 1) % y)
+
+
+#define ARGE_MII_TIMEOUT 1000
+
+#define ARGE_LOCK(_sc) mtx_lock(&(_sc)->arge_mtx)
+#define ARGE_UNLOCK(_sc) mtx_unlock(&(_sc)->arge_mtx)
+#define ARGE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->arge_mtx, MA_OWNED)
+
+/*
+ * register space access macros
+ */
+#define ARGE_WRITE(sc, reg, val) do { \
+ bus_write_4(sc->arge_res, (reg), (val)); \
+ } while (0)
+
+#define ARGE_READ(sc, reg) bus_read_4(sc->arge_res, (reg))
+
+#define ARGE_SET_BITS(sc, reg, bits) \
+ ARGE_WRITE(sc, reg, ARGE_READ(sc, (reg)) | (bits))
+
+#define ARGE_CLEAR_BITS(sc, reg, bits) \
+ ARGE_WRITE(sc, reg, ARGE_READ(sc, (reg)) & ~(bits))
+
+#define ARGE_DESC_EMPTY (1 << 31)
+#define ARGE_DESC_MORE (1 << 24)
+#define ARGE_DESC_SIZE_MASK ((1 << 12) - 1)
+#define ARGE_DMASIZE(len) ((len) & ARGE_DESC_SIZE_MASK)
+struct arge_desc {
+ uint32_t packet_addr;
+ uint32_t packet_ctrl;
+ uint32_t next_desc;
+ uint32_t padding;
+};
+
+struct arge_txdesc {
+ struct mbuf *tx_m;
+ bus_dmamap_t tx_dmamap;
+};
+
+struct arge_rxdesc {
+ struct mbuf *rx_m;
+ bus_dmamap_t rx_dmamap;
+ struct arge_desc *desc;
+};
+
+struct arge_chain_data {
+ bus_dma_tag_t arge_parent_tag;
+ bus_dma_tag_t arge_tx_tag;
+ struct arge_txdesc arge_txdesc[ARGE_TX_RING_COUNT];
+ bus_dma_tag_t arge_rx_tag;
+ struct arge_rxdesc arge_rxdesc[ARGE_RX_RING_COUNT];
+ bus_dma_tag_t arge_tx_ring_tag;
+ bus_dma_tag_t arge_rx_ring_tag;
+ bus_dmamap_t arge_tx_ring_map;
+ bus_dmamap_t arge_rx_ring_map;
+ bus_dmamap_t arge_rx_sparemap;
+ int arge_tx_pkts;
+ int arge_tx_prod;
+ int arge_tx_cons;
+ int arge_tx_cnt;
+ int arge_rx_cons;
+};
+
+struct arge_ring_data {
+ struct arge_desc *arge_rx_ring;
+ struct arge_desc *arge_tx_ring;
+ bus_addr_t arge_rx_ring_paddr;
+ bus_addr_t arge_tx_ring_paddr;
+};
+
+struct arge_softc {
+ struct ifnet *arge_ifp; /* interface info */
+ device_t arge_dev;
+ struct resource *arge_res;
+ int arge_rid;
+ struct resource *arge_irq;
+ void *arge_intrhand;
+ device_t arge_miibus;
+ bus_dma_tag_t arge_parent_tag;
+ bus_dma_tag_t arge_tag;
+ struct mtx arge_mtx;
+ struct callout arge_stat_callout;
+ struct task arge_link_task;
+ struct arge_chain_data arge_cdata;
+ struct arge_ring_data arge_rdata;
+ int arge_link_status;
+ int arge_detach;
+ uint32_t arge_intr_status;
+ int arge_mac_unit;
+ int arge_phy_num;
+ uint32_t arge_ddr_flush_reg;
+ uint32_t arge_pll_reg;
+};
+
+#endif /* __IF_ARGEVAR_H__ */
diff --git a/sys/mips/atheros/uart_bus_ar71xx.c b/sys/mips/atheros/uart_bus_ar71xx.c
new file mode 100644
index 0000000..1cb611c
--- /dev/null
+++ b/sys/mips/atheros/uart_bus_ar71xx.c
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2009, 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 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
+ */
+#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 <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+
+#include <mips/atheros/ar71xxreg.h>
+
+#include "uart_if.h"
+
+static int uart_ar71xx_probe(device_t dev);
+extern struct uart_class uart_ar71xx_uart_class;
+
+static device_method_t uart_ar71xx_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_ar71xx_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_ar71xx_driver = {
+ uart_driver_name,
+ uart_ar71xx_methods,
+ sizeof(struct uart_softc),
+};
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+
+static int
+uart_ar71xx_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));
+
+ return (uart_bus_probe(dev, 2, 85000000, 0, 0));
+}
+
+DRIVER_MODULE(uart, apb, uart_ar71xx_driver, uart_devclass, 0, 0);
diff --git a/sys/mips/atheros/uart_cpu_ar71xx.c b/sys/mips/atheros/uart_cpu_ar71xx.c
new file mode 100644
index 0000000..4d6b7e7
--- /dev/null
+++ b/sys/mips/atheros/uart_cpu_ar71xx.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2009 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 AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <mips/atheros/ar71xxreg.h>
+
+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)
+{
+ di->ops = uart_getops(&uart_ns8250_class);
+ di->bas.chan = 0;
+ di->bas.bst = MIPS_BUS_SPACE_MEM;
+ di->bas.regshft = 2;
+ /* TODO: calculate proper AHB freq using PLL registers */
+ di->bas.rclk = 85000000;
+ di->baudrate = 115200;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+
+ /* TODO: check if uart_bus_space_io mandatory to set */
+ uart_bus_space_io = MIPS_BUS_SPACE_IO;
+ uart_bus_space_mem = MIPS_BUS_SPACE_MEM;
+ /*
+ * FIXME:
+ * 3 is to compensate big endian, uart operates
+ * with bus_space_read_1/bus_space_write_1 and hence gets
+ * highest byte instead of lowest one. Actual fix will involve
+ * MIPS bus_space fixing.
+ */
+ di->bas.bsh = MIPS_PHYS_TO_KSEG1(AR71XX_UART_ADDR) + 3;
+ return (0);
+}
diff --git a/sys/mips/conf/ADM5120 b/sys/mips/conf/ADM5120
index a03d102..7a47abe 100644
--- a/sys/mips/conf/ADM5120
+++ b/sys/mips/conf/ADM5120
@@ -25,7 +25,6 @@ makeoptions MIPS_LITTLE_ENDIAN=defined
# Don't build any modules yet.
makeoptions MODULES_OVERRIDE=""
-options KERNVIRTADDR=0x80100000
include "../adm5120/std.adm5120"
hints "ADM5120.hints" #Default places to look for devices.
diff --git a/sys/mips/conf/ALCHEMY b/sys/mips/conf/ALCHEMY
new file mode 100644
index 0000000..c1fb59a
--- /dev/null
+++ b/sys/mips/conf/ALCHEMY
@@ -0,0 +1,66 @@
+# ALCHEMY -- Generic kernel for Alchemy Au1xxx CPUs.
+#
+# For more information on this file, please read the handbook section on
+# Kernel Configuration Files:
+#
+# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD$
+
+ident ALCHEMY
+
+makeoptions ARCH_FLAGS=-march=mips32
+makeoptions MIPS_LITTLE_ENDIAN=defined
+
+# Don't build any modules yet.
+makeoptions MODULES_OVERRIDE=""
+
+include "../alchemy/std.alchemy"
+
+hints "ALCHEMY.hints" #Default places to look for devices.
+
+makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
+
+options DDB
+options KDB
+
+options SCHED_4BSD #4BSD scheduler
+options INET #InterNETworking
+options NFSCLIENT #Network Filesystem Client
+options NFS_ROOT #NFS usable as /, requires NFSCLIENT
+options PSEUDOFS #Pseudo-filesystem framework
+# options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+
+options BOOTP
+options BOOTP_NFSROOT
+options BOOTP_NFSV3
+options BOOTP_WIRED_TO=admsw0
+options BOOTP_COMPAT
+
+# options FFS #Berkeley Fast Filesystem
+# options SOFTUPDATES #Enable FFS soft updates support
+# options UFS_ACL #Support for access control lists
+# options UFS_DIRHASH #Improve performance on big directories
+options ROOTDEVNAME=\"nfs:10.0.0.1:/mnt/bsd\"
+
+
+# Debugging for use in -current
+options INVARIANTS #Enable calls of extra sanity checking
+options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS
+#options WITNESS #Enable checks to detect deadlocks and cycles
+#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed
+
+device loop
+device ether
+device uart
+# device md
diff --git a/sys/mips/conf/AR71XX b/sys/mips/conf/AR71XX
new file mode 100644
index 0000000..936d0f1
--- /dev/null
+++ b/sys/mips/conf/AR71XX
@@ -0,0 +1,37 @@
+#
+# $FreeBSD$
+#
+
+ident AR71XX
+cpu CPU_MIPS4KC
+options CPU_NOFPU
+options ISA_MIPS32
+makeoptions TARGET_BIG_ENDIAN
+makeoptions KERNLOADADDR=0x80050000
+
+files "../atheros/files.ar71xx"
+hints "AR71XX.hints"
+
+makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
+makeoptions MODULES_OVERRIDE=""
+
+options DDB
+options KDB
+
+options SCHED_4BSD #4BSD scheduler
+options INET #InterNETworking
+options NFSCLIENT #Network Filesystem Client
+options NFS_ROOT #NFS usable as /, requires NFSCLIENT
+options PSEUDOFS #Pseudo-filesystem framework
+options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+
+# Debugging for use in -current
+options INVARIANTS
+options INVARIANT_SUPPORT
+
+device pci
+device uart
+
+device loop
+device ether
+device md
diff --git a/sys/mips/conf/AR71XX.hints b/sys/mips/conf/AR71XX.hints
new file mode 100644
index 0000000..58fbdde
--- /dev/null
+++ b/sys/mips/conf/AR71XX.hints
@@ -0,0 +1,25 @@
+# $FreeBSD$
+hint.apb.0.at="nexus0"
+hint.apb.0.maddr=0x18000000
+hint.apb.0.msize=0x01000000
+hint.apb.0.irq=4
+
+# uart0
+hint.uart.0.at="apb0"
+# see atheros/uart_cpu_ar71xx.c why +3
+hint.uart.0.maddr=0x18020003
+hint.uart.0.msize=0x18
+hint.uart.0.irq=3
+
+# pci
+hint.pcib.0.at="nexus0"
+hint.pcib.0.irq=0
+
+hint.arge.0.at="nexus0"
+hint.arge.0.maddr=0x19000000
+hint.arge.0.msize=0x1000
+hint.arge.0.irq=2
+# hint.arge.1.at="nexus0"
+# hint.arge.1.maddr=0x1A000000
+# hint.arge.1.msize=0x1000
+# hint.arge.1.irq=3
diff --git a/sys/mips/conf/MALTA b/sys/mips/conf/MALTA
index 9771c55..022cc52 100644
--- a/sys/mips/conf/MALTA
+++ b/sys/mips/conf/MALTA
@@ -27,7 +27,6 @@ options YAMON
# Don't build any modules yet.
makeoptions MODULES_OVERRIDE=""
-options KERNVIRTADDR=0x80100000
options TICK_USE_YAMON_FREQ=defined
#options TICK_USE_MALTA_RTC=defined
diff --git a/sys/mips/conf/QEMU b/sys/mips/conf/QEMU
index 0a2b122..bc7d649 100644
--- a/sys/mips/conf/QEMU
+++ b/sys/mips/conf/QEMU
@@ -27,7 +27,6 @@ makeoptions ARCH_FLAGS=-march=mips32
# Don't build any modules yet.
makeoptions MODULES_OVERRIDE=""
-options KERNVIRTADDR=0x80100000
include "../adm5120/std.adm5120"
#hints "GENERIC.hints" #Default places to look for devices.
diff --git a/sys/mips/conf/SENTRY5 b/sys/mips/conf/SENTRY5
index 7611e44..c3918e2 100644
--- a/sys/mips/conf/SENTRY5
+++ b/sys/mips/conf/SENTRY5
@@ -41,13 +41,6 @@ options CFE
options CFE_CONSOLE
options ALT_BREAK_TO_DEBUGGER
-# cfe loader expects kernel at 0x80001000 for mips32 w/o backwards
-# offsets in the linked elf image (see ldscript hack)
-# XXX can we conditionalize the linker stuff on options CFE?
-options KERNVIRTADDR=0x80001000
-
-makeoptions LDSCRIPT_NAME= ldscript.mips.cfe
-
#makeoptions ARCH_FLAGS=-march=mips32
makeoptions MIPS_LITTLE_ENDIAN=defined
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
@@ -73,8 +66,8 @@ options INVARIANT_SUPPORT
device siba # Sonics SiliconBackplane
device pci # siba_pcib
-device bfe # XXX will build both pci and siba
-device miibus # attachments
+# device bfe # XXX will build both pci and siba
+# device miibus # attachments
# pci devices
# notyet:
diff --git a/sys/mips/include/bus.h b/sys/mips/include/bus.h
index 92557d7..42ac1df 100644
--- a/sys/mips/include/bus.h
+++ b/sys/mips/include/bus.h
@@ -101,9 +101,8 @@
* Map a region of device bus space into CPU virtual address space.
*/
-static __inline int bus_space_map(bus_space_tag_t t, bus_addr_t addr,
- bus_size_t size, int flags,
- bus_space_handle_t *bshp);
+__inline int bus_space_map(bus_space_tag_t t, bus_addr_t addr,
+ bus_size_t size, int flags, bus_space_handle_t *bshp);
static __inline int
bus_space_map(bus_space_tag_t t __unused, bus_addr_t addr,
diff --git a/sys/mips/mips/elf_machdep.c b/sys/mips/mips/elf_machdep.c
index 19cb1a1..163d0ee 100644
--- a/sys/mips/mips/elf_machdep.c
+++ b/sys/mips/mips/elf_machdep.c
@@ -86,8 +86,7 @@ static Elf32_Brandinfo freebsd_brand_info = {
.interp_path = "/libexec/ld-elf.so.1",
.sysvec = &elf32_freebsd_sysvec,
.interp_newpath = NULL,
- .brand_note = &elf32_freebsd_brandnote,
- .flags = BI_BRAND_NOTE
+ .flags = 0
};
SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/mips/mips/elf_trampoline.c b/sys/mips/mips/elf_trampoline.c
new file mode 100644
index 0000000..0f2ccc9
--- /dev/null
+++ b/sys/mips/mips/elf_trampoline.c
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard. 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 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 <machine/asm.h>
+#include <sys/param.h>
+#include <sys/elf32.h>
+#include <sys/inflate.h>
+#include <machine/elf.h>
+#include <machine/cpufunc.h>
+#include <machine/stdarg.h>
+
+/*
+ * Since we are compiled outside of the normal kernel build process, we
+ * need to include opt_global.h manually.
+ */
+#include "opt_global.h"
+#include "opt_kernname.h"
+
+extern char kernel_start[];
+extern char kernel_end[];
+
+static __inline void *
+memcpy(void *dst, const void *src, int len)
+{
+ const char *s = src;
+ char *d = dst;
+
+ while (len) {
+ if (0 && len >= 4 && !((vm_offset_t)d & 3) &&
+ !((vm_offset_t)s & 3)) {
+ *(uint32_t *)d = *(uint32_t *)s;
+ s += 4;
+ d += 4;
+ len -= 4;
+ } else {
+ *d++ = *s++;
+ len--;
+ }
+ }
+ return (dst);
+}
+
+static __inline void
+bzero(void *addr, int count)
+{
+ char *tmp = (char *)addr;
+
+ while (count > 0) {
+ if (count >= 4 && !((vm_offset_t)tmp & 3)) {
+ *(uint32_t *)tmp = 0;
+ tmp += 4;
+ count -= 4;
+ } else {
+ *tmp = 0;
+ tmp++;
+ count--;
+ }
+ }
+}
+
+/*
+ * Relocate PT_LOAD segements of kernel ELF image to their respective
+ * virtual addresses and return entry point
+ */
+void *
+load_kernel(void * kstart)
+{
+ Elf32_Ehdr *eh;
+ Elf32_Phdr phdr[64] /* XXX */;
+ int i;
+ void *entry_point;
+
+ eh = (Elf32_Ehdr *)kstart;
+ entry_point = (void*)eh->e_entry;
+ memcpy(phdr, (void *)(kstart + eh->e_phoff ),
+ eh->e_phnum * sizeof(phdr[0]));
+
+ for (i = 0; i < eh->e_phnum; i++) {
+ volatile char c;
+
+ if (phdr[i].p_type != PT_LOAD)
+ continue;
+
+ memcpy((void *)(phdr[i].p_vaddr),
+ (void*)(kstart + phdr[i].p_offset), phdr[i].p_filesz);
+ /* Clean space from oversized segments, eg: bss. */
+ if (phdr[i].p_filesz < phdr[i].p_memsz)
+ bzero((void *)(phdr[i].p_vaddr + phdr[i].p_filesz),
+ phdr[i].p_memsz - phdr[i].p_filesz);
+ }
+
+ return entry_point;
+}
+
+void
+_startC(register_t a0, register_t a1, register_t a2, register_t a3)
+{
+ unsigned int * code;
+ int i;
+ void (*entry_point)(register_t, register_t, register_t, register_t);
+
+ /*
+ * Relocate segment to the predefined memory location
+ * Most likely it will be KSEG0/KSEG1 address
+ */
+ entry_point = load_kernel(kernel_start);
+
+ /* Pass saved registers to original _start */
+ entry_point(a0, a1, a2, a3);
+}
diff --git a/sys/mips/mips/inckern.S b/sys/mips/mips/inckern.S
new file mode 100644
index 0000000..8610196
--- /dev/null
+++ b/sys/mips/mips/inckern.S
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard. 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 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 "opt_kernname.h"
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$")
+.section ".real_kernel","aw"
+.globl kernel_start;
+kernel_start:
+.incbin KERNNAME
+.globl kernel_end;
+kernel_end:
diff --git a/sys/mips/mips/nexus.c b/sys/mips/mips/nexus.c
index 64cba66..e96eeab 100644
--- a/sys/mips/mips/nexus.c
+++ b/sys/mips/mips/nexus.c
@@ -249,6 +249,8 @@ nexus_hinted_child(device_t bus, const char *dname, int dunit)
long maddr;
int msize;
int result;
+ int irq;
+ int mem_hints_count;
child = BUS_ADD_CHILD(bus, 0, dname, dunit);
@@ -256,17 +258,34 @@ nexus_hinted_child(device_t bus, const char *dname, int 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);
-
- dprintf("%s: discovered hinted child %s at maddr %p(%d)\n",
- __func__, device_get_nameunit(child),
- (void *)(intptr_t)maddr, msize);
+ mem_hints_count = 0;
+ if (resource_long_value(dname, dunit, "maddr", &maddr) == 0)
+ mem_hints_count++;
+ if (resource_int_value(dname, dunit, "msize", &msize) == 0)
+ mem_hints_count++;
+
+ /* check if all info for mem resource has been provided */
+ if ((mem_hints_count > 0) && (mem_hints_count < 2)) {
+ printf("Either maddr or msize hint is missing for %s%d\n",
+ dname, dunit);
+ } else if (mem_hints_count) {
+ dprintf("%s: discovered hinted child %s at maddr %p(%d)\n",
+ __func__, device_get_nameunit(child),
+ (void *)(intptr_t)maddr, msize);
+
+ result = bus_set_resource(child, SYS_RES_MEMORY, MIPS_MEM_RID,
+ maddr, msize);
+ if (result != 0) {
+ device_printf(bus,
+ "warning: bus_set_resource() failed\n");
+ }
+ }
- result = bus_set_resource(child, SYS_RES_MEMORY, MIPS_MEM_RID,
- 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");
}
}
diff --git a/sys/mips/sentry5/files.sentry5 b/sys/mips/sentry5/files.sentry5
index 61038e0..7992509 100644
--- a/sys/mips/sentry5/files.sentry5
+++ b/sys/mips/sentry5/files.sentry5
@@ -4,11 +4,4 @@
# for USB 1.1 OHCI, Ethernet and IPSEC cores
# which are believed to be devices we have drivers for
# which just need to be tweaked for attachment to an SSB system bus.
-
mips/sentry5/s5_machdep.c standard
-dev/siba/siba.c optional siba
-dev/siba/siba_pcib.c optional siba pci
-mips/sentry5/siba_cc.c optional siba
-
-# notyet
-#mips/sentry5/siba_mips.c optional siba
OpenPOWER on IntegriCloud