Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 26 Dec 2009 00:48:17 +0700
From:      Yohanes Nugroho <yohanes@gmail.com>
To:        freebsd-arm@freebsd.org
Subject:   Re: CNS11XX FreeBSD port completed
Message-ID:  <260bb65e0912250948w6f714367w672a1ebf037fb7f7@mail.gmail.com>
In-Reply-To: <260bb65e0912110627o6b67b399vabaae57477b91023@mail.gmail.com>
References:  <260bb65e0912110627o6b67b399vabaae57477b91023@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Hi,

To make it easy for others to read the changes I have made, attached
is the diff version against SVN head. There is one change that may be
should not be commited. In vfs_mount.c, I added

pause("WAIT", hz * 10);

That line can be removed if the patch from this:

http://lists.freebsd.org/pipermail/freebsd-current/2009-October/012361.html

is applied

-- 
Regards
Yohanes
http://yohan.es/


On Fri, Dec 11, 2009 at 9:27 PM, Yohanes Nugroho <yohanes@gmail.com> wrote:
> Hi,
>
> Today I have "completed" the CNS11XX (Cavium Econa ARM formerly known
> as StarSemi STR9104) FreeBSD ARM Port. By "complete" I mean I have
> written all the drivers (usb, network, and flash). I haven't checked
> the correctness of the implementation. The device is a network
> attached storage, Emprex NSD-100, sent to me by Bruce Simpson.
>
> This is my first FreeBSD port, so I think there will be mistakes on my
> code. So I am requesting anyone who have time to have a look at the
> code, or if you have the same device, may be you can try it. You will
> need to solder a serial port to the device to try it.
>
> From the usability point of view, the port is usable. I can put the
> FreeBSD kernel to the flash, and boot it from there with the root
> filesystem on a USB disk (the boot loader also supports booting from
> tftp, and during the development I boot using tftp). The device can
> enter multi user mode, and I can ssh/ftp to the device, and compile
> some things on the device itself.
>
> The only problem left (at least what is visible from user space) is
> the slow network speed (2 megabyte per second, while the linux version
> is around 3.8 megabyte per second). Pyun YongHyeon have helped me a
> lot with the network driver (I am currently asking him to have a final
> look at the driver). I have tried following all of his suggestions to
> make a better (more correct driver), and I suspect the problem is not
> on the network driver itself.
>
> I am suspecting that the problem is in pmap. There has been several
> pmap related problems lately (see
> http://lists.freebsd.org/pipermail/freebsd-arm/2009-October/002030.html).
> It is also possible that the pmap code is now fine, and I have made
> errors when porting the NetBSD CPU code for FA526 to FreeBSD.
>
> If I compile my current code with the latest code from HEAD, and
> activated WITNESS and DIAGNOSTIC i will get the error at err-1.txt,
> and  If I activated WITNESS, DIAGNOSTIC and INVARIANT i got this the
> message in err-2.txt. With the same options I didn't get this error
> several months ago .
>
> My code is available at
>
> http://p4db.freebsd.org/depotTreeBrowser.cgi?FSPC=//depot/projects/str91xx/src/sys/arm/econa&HIDEDEL=NO
>
> plus additional code from to support FA526 CPU adapted from NetBSD:
>
> http://p4db.freebsd.org/fileLogView.cgi?FSPC=//depot/projects/str91xx/src/sys/arm/arm/cpufunc_asm_fa526.S
> http://p4db.freebsd.org/fileViewer.cgi?FSPC=//depot/projects/str91xx/src/sys/arm/arm/cpufunc.c
>
> Instruction to compile, and write to flash using dd to cfi0 is available at:
>
> http://tinyhack.com/2009/09/28/cnx11xxstr91xx-freebsd-progress/
> http://tinyhack.com/2009/12/11/cns11xx-freebsd-port-completed/
>
> --
> Regards
> Yohanes
> http://yohan.es/
>

[-- Attachment #2 --]
Index: sys/arm/arm/elf_trampoline.c
===================================================================
--- sys/arm/arm/elf_trampoline.c	(revision 200988)
+++ sys/arm/arm/elf_trampoline.c	(working copy)
@@ -57,6 +57,8 @@
 #define cpu_idcache_wbinv_all	arm8_cache_purgeID
 #elif defined(CPU_ARM9)
 #define cpu_idcache_wbinv_all	arm9_idcache_wbinv_all
+#elif defined(CPU_FA526)
+#define cpu_idcache_wbinv_all	fa526_idcache_wbinv_all
 #elif defined(CPU_ARM9E)
 #define cpu_idcache_wbinv_all	armv5_ec_idcache_wbinv_all
 #elif defined(CPU_ARM10)
Index: sys/arm/arm/cpufunc.c
===================================================================
--- sys/arm/arm/cpufunc.c	(revision 200988)
+++ sys/arm/arm/cpufunc.c	(working copy)
@@ -781,6 +781,73 @@
 	xscale_setup			/* cpu setup		*/
 };
 #endif /* CPU_XSCALE_81342 */
+
+
+#if defined(CPU_FA526)
+struct cpu_functions fa526_cpufuncs = {
+	/* CPU functions */
+	
+	.cf_id			= cpufunc_id,
+	.cf_cpwait		= cpufunc_nullop,
+
+	/* MMU functions */
+
+	.cf_control		= cpufunc_control,
+	.cf_domains		= cpufunc_domains,
+	.cf_setttb		= fa526_setttb,
+	.cf_faultstatus		= cpufunc_faultstatus,
+	.cf_faultaddress	= cpufunc_faultaddress,
+
+	/* TLB functions */
+
+	.cf_tlb_flushID		= armv4_tlb_flushID,
+	.cf_tlb_flushID_SE	= fa526_tlb_flushID_SE,
+	.cf_tlb_flushI		= armv4_tlb_flushI,
+	.cf_tlb_flushI_SE	= fa526_tlb_flushI_SE,
+	.cf_tlb_flushD		= armv4_tlb_flushD,
+	.cf_tlb_flushD_SE	= armv4_tlb_flushD_SE,
+
+	/* Cache operations */
+
+	.cf_icache_sync_all	= fa526_icache_sync_all,
+	.cf_icache_sync_range	= fa526_icache_sync_range,
+
+	.cf_dcache_wbinv_all	= fa526_dcache_wbinv_all,
+	.cf_dcache_wbinv_range	= fa526_dcache_wbinv_range,
+	.cf_dcache_inv_range	= fa526_dcache_inv_range,
+	.cf_dcache_wb_range	= fa526_dcache_wb_range,
+
+	.cf_idcache_wbinv_all	= fa526_idcache_wbinv_all,
+	.cf_idcache_wbinv_range	= fa526_idcache_wbinv_range,
+
+
+	.cf_l2cache_wbinv_all = cpufunc_nullop,
+	.cf_l2cache_wbinv_range = (void *)cpufunc_nullop,
+	.cf_l2cache_inv_range = (void *)cpufunc_nullop,
+	.cf_l2cache_wb_range = (void *)cpufunc_nullop,
+
+
+	/* Other functions */
+
+	.cf_flush_prefetchbuf	= fa526_flush_prefetchbuf,
+	.cf_drain_writebuf	= armv4_drain_writebuf,
+	.cf_flush_brnchtgt_C	= cpufunc_nullop,
+	.cf_flush_brnchtgt_E	= fa526_flush_brnchtgt_E,
+
+	.cf_sleep		= fa526_cpu_sleep,
+
+	/* Soft functions */
+
+	.cf_dataabt_fixup	= cpufunc_null_fixup,
+	.cf_prefetchabt_fixup	= cpufunc_null_fixup,
+
+	.cf_context_switch	= fa526_context_switch,
+
+	.cf_setup		= fa526_setup
+};          
+#endif	/* CPU_FA526 */
+
+
 /*
  * Global constants also used by locore.s
  */
@@ -793,6 +860,7 @@
   defined (CPU_ARM9E) || defined (CPU_ARM10) ||			       \
   defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) ||	       \
   defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) ||	       \
+  defined(CPU_FA526) ||					       \
   defined(CPU_XSCALE_80219) || defined(CPU_XSCALE_81342)
 
 static void get_cachetype_cp15(void);
@@ -1073,6 +1141,19 @@
 		goto out;
 	}
 #endif	/* CPU_SA1110 */
+#ifdef CPU_FA526
+	if (cputype == CPU_ID_FA526) {
+		cpufuncs = fa526_cpufuncs;
+		cpu_reset_needs_v4_MMU_disable = 1;	/* SA needs it	*/
+		get_cachetype_cp15();
+		pmap_pte_init_generic();
+
+		/* Use powersave on this CPU. */
+		cpu_do_powersave = 1;
+
+		goto out;
+	}
+#endif	/* CPU_FA526 */
 #ifdef CPU_IXP12X0
         if (cputype == CPU_ID_IXP1200) {
                 cpufuncs = ixp12x0_cpufuncs;
@@ -1547,7 +1628,8 @@
   defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) ||		\
   defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) ||		\
   defined(CPU_XSCALE_80219) || defined(CPU_XSCALE_81342) || \
-  defined(CPU_ARM10) ||  defined(CPU_ARM11)
+  defined(CPU_ARM10) ||  defined(CPU_ARM11) || \
+  defined(CPU_FA526)
 
 #define IGN	0
 #define OR	1
@@ -2013,6 +2095,60 @@
 }
 #endif	/* CPU_SA1100 || CPU_SA1110 */
 
+#if defined(CPU_FA526)
+struct cpu_option fa526_options[] = {
+#ifdef COMPAT_12
+	{ "nocache",		IGN, BIC, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+	{ "nowritebuf",		IGN, BIC, CPU_CONTROL_WBUF_ENABLE },
+#endif	/* COMPAT_12 */
+	{ "cpu.cache",		BIC, OR,  (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+	{ "cpu.nocache",	OR,  BIC, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+	{ "cpu.writebuf",	BIC, OR,  CPU_CONTROL_WBUF_ENABLE },
+	{ "cpu.nowritebuf",	OR,  BIC, CPU_CONTROL_WBUF_ENABLE },
+	{ NULL,			IGN, IGN, 0 }
+};
+
+void
+fa526_setup(char *args)
+{
+	int cpuctrl, cpuctrlmask;
+
+	cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+		 | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+		 | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
+		 | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_LABT_ENABLE;
+	cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+		 | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+		 | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
+		 | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_ROM_ENABLE
+		 | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE
+		 | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_BPRD_ENABLE
+		 | CPU_CONTROL_CPCLK | CPU_CONTROL_VECRELOC;
+
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+	cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+
+	cpuctrl = parse_cpu_options(args, fa526_options, cpuctrl);
+
+#ifdef __ARMEB__
+	cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+
+	if (vector_page == ARM_VECTORS_HIGH)
+		cpuctrl |= CPU_CONTROL_VECRELOC;
+
+	/* Clear out the cache */
+	cpu_idcache_wbinv_all();
+
+	/* Set the control register */    
+	//curcpu()->ci_ctrl = cpuctrl;
+	ctrl = cpuctrl;
+	cpu_control(0xffffffff, cpuctrl);
+}
+#endif	/* CPU_FA526 */
+
+
 #if defined(CPU_IXP12X0)
 struct cpu_option ixp12x0_options[] = {
 	{ "cpu.cache",		BIC, OR,  (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
Index: sys/arm/arm/cpufunc_asm_fa526.S
===================================================================
--- sys/arm/arm/cpufunc_asm_fa526.S	(revision 0)
+++ sys/arm/arm/cpufunc_asm_fa526.S	(revision 0)
@@ -0,0 +1,209 @@
+/*	$NetBSD: cpufunc_asm_fa526.S,v 1.3 2008/10/15 16:56:49 matt Exp $	*/
+/*-
+ * Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas <matt@3am-software.com>
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <machine/asm.h>
+
+#define	CACHELINE_SIZE	16
+
+ENTRY(fa526_setttb)
+	mov	r1, #0
+	mcr	p15, 0, r1, c7, c14, 0	/* clean and invalidate D$ */
+	mcr	p15, 0, r1, c7, c5, 0	/* invalidate I$ */
+	mcr	p15, 0, r1, c7, c5, 6	/* invalidate BTB */
+	mcr	p15, 0, r1, c7, c10, 4	/* drain write and fill buffer */
+
+	mcr	p15, 0, r0, c2, c0, 0	/* Write the TTB */ 
+
+	/* If we have updated the TTB we must flush the TLB */
+	mcr	p15, 0, r1, c8, c7, 0	/* invalidate I+D TLB */
+
+	/* Make sure that pipeline is emptied */
+	mov	r0, r0
+	mov	r0, r0
+	mov	pc, lr
+
+/*
+ * TLB functions
+ */
+ENTRY(fa526_tlb_flushID_SE)
+	mcr	p15, 0, r0, c8, c7, 1	/* flush Utlb single entry */
+	mov	pc, lr
+
+/*
+ * TLB functions
+ */
+ENTRY(fa526_tlb_flushI_SE)
+	mcr	p15, 0, r0, c8, c5, 1	/* flush Itlb single entry */
+	mov	pc, lr
+
+ENTRY(fa526_cpu_sleep)
+	mov	r0, #0
+/*	nop
+	nop*/
+	//mcr	p15, 0, r0, c7, c5, 5	// Enter sleep mode ? invalidate iscratcpad ram*/
+	mcr	p15, 0, r0, c7, c0, 4		/* Wait for interrupt (IDLE mode)	*/
+	mov	pc, lr
+
+ENTRY(fa526_flush_prefetchbuf)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 4	/* Pre-fetch flush */
+	mov	pc, lr
+
+/*
+ * Cache functions
+ */
+ENTRY(fa526_idcache_wbinv_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean and invalidate D$ */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I$ */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+	mov	pc, lr
+
+ENTRY(fa526_icache_sync_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I$ */
+	mov	pc, lr
+
+ENTRY(fa526_dcache_wbinv_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean and invalidate D$ */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+	mov	pc, lr
+
+/*
+ * Soft functions
+ */
+ENTRY(fa526_dcache_wbinv_range)
+	cmp	r1, #0x4000
+	bhs	_C_LABEL(fa526_dcache_wbinv_all)
+
+	and	r2, r0, #(CACHELINE_SIZE-1)
+	add	r1, r1, r2
+	bic	r0, r0, #(CACHELINE_SIZE-1)
+
+1:	mcr	p15, 0, r0, c7, c14, 1	/* clean and invalidate D$ entry */
+	add	r0, r0, #CACHELINE_SIZE
+	subs	r1, r1, #CACHELINE_SIZE
+	bhi	1b
+
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+	mov	pc, lr
+
+ENTRY(fa526_dcache_wb_range)
+	cmp	r1, #0x4000
+	bls	1f
+
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c10, 0	/* clean entire D$ */
+	b	3f
+
+1:	and	r2, r0, #(CACHELINE_SIZE-1)
+	add	r1, r1, r2
+	bic	r0, r0, #(CACHELINE_SIZE-1)
+
+2:	mcr	p15, 0, r0, c7, c10, 1	/* clean D$ entry */
+	add	r0, r0, #CACHELINE_SIZE
+	subs	r1, r1, #CACHELINE_SIZE
+	bhi	2b
+
+3:	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+	mov	pc, lr
+
+ENTRY(fa526_dcache_inv_range)
+	and	r2, r0, #(CACHELINE_SIZE-1)
+	add	r1, r1, r2
+	bic	r0, r0, #(CACHELINE_SIZE-1)
+
+1:	mcr	p15, 0, r0, c7, c6, 1	/* invalidate D$ single entry */
+	add	r0, r0, #CACHELINE_SIZE
+	subs	r1, r1, #CACHELINE_SIZE
+	bhi	1b
+
+	mov	pc, lr
+
+ENTRY(fa526_idcache_wbinv_range)
+	cmp	r1, #0x4000
+	bhs	_C_LABEL(fa526_idcache_wbinv_all)
+
+	and	r2, r0, #(CACHELINE_SIZE-1)
+	add	r1, r1, r2
+	bic	r0, r0, #(CACHELINE_SIZE-1)
+
+1:	mcr	p15, 0, r0, c7, c14, 1	/* clean and invalidate D$ entry */
+	mcr	p15, 0, r0, c7, c5, 1	/* invalidate I$ entry */
+	add	r0, r0, #CACHELINE_SIZE
+	subs	r1, r1, #CACHELINE_SIZE
+	bhi	1b
+
+2:	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+	mov	pc, lr
+
+ENTRY(fa526_icache_sync_range)
+	cmp	r1, #0x4000
+	bhs	_C_LABEL(fa526_icache_sync_all)
+
+	and	r2, r0, #(CACHELINE_SIZE-1)
+	add	r1, r1, r2
+	bic	r0, r0, #(CACHELINE_SIZE-1)
+
+1:	mcr	p15, 0, r0, c7, c10, 1	/* clean D$ entry */
+	mcr	p15, 0, r0, c7, c5, 1	/* invalidate I$ entry */
+	add	r0, r0, #CACHELINE_SIZE
+	subs	r1, r1, #CACHELINE_SIZE
+	bhi	1b
+
+2:	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+	mov	pc, lr
+
+ENTRY(fa526_flush_brnchtgt_E)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 6	/* invalidate BTB cache */
+	mov	pc, lr
+
+ENTRY(fa526_context_switch)
+	/*
+	 * CF_CACHE_PURGE_ID will *ALWAYS* be called prior to this.
+	 * Thus the data cache will contain only kernel data and the
+	 * instruction cache will contain only kernel code, and all
+	 * kernel mappings are shared by all processes.
+	 */
+
+	mcr	p15, 0, r0, c2, c0, 0	/* Write the TTB */
+
+	/* If we have updated the TTB we must flush the TLB */
+	mov	r0, #0
+	mcr	p15, 0, r0, c8, c7, 0	/* flush the I+D tlb */
+
+	/* Make sure that pipeline is emptied */
+	mov	r0, r0
+	mov	r0, r0
+	mov	pc, lr
+
Index: sys/arm/include/cpuconf.h
===================================================================
--- sys/arm/include/cpuconf.h	(revision 200988)
+++ sys/arm/include/cpuconf.h	(working copy)
@@ -61,6 +61,7 @@
 			 defined(CPU_XSCALE_80200) +			\
 			 defined(CPU_XSCALE_80321) +			\
 			 defined(CPU_XSCALE_PXA2X0) +			\
+			 defined(CPU_FA526) +				\
 			 defined(CPU_XSCALE_IXP425))
 
 /*
@@ -68,7 +69,7 @@
  */
 #if (defined(CPU_ARM7TDMI) || defined(CPU_ARM8) || defined(CPU_ARM9) ||	\
      defined(CPU_SA110) || defined(CPU_SA1100) || defined(CPU_SA1110) || \
-    defined(CPU_IXP12X0) || defined(CPU_XSCALE_IXP425))
+     defined(CPU_IXP12X0) || defined(CPU_XSCALE_IXP425) || defined(CPU_FA526))
 #define	ARM_ARCH_4	1
 #else
 #define	ARM_ARCH_4	0
@@ -125,7 +126,7 @@
 
 #if (defined(CPU_ARM6) || defined(CPU_ARM7) || defined(CPU_ARM7TDMI) ||	\
      defined(CPU_ARM8) || defined(CPU_ARM9) || defined(CPU_ARM9E) ||	\
-     defined(CPU_ARM10) || defined(CPU_ARM11))
+     defined(CPU_ARM10) || defined(CPU_ARM11) || defined(CPU_FA526))
 #define	ARM_MMU_GENERIC		1
 #else
 #define	ARM_MMU_GENERIC		0
Index: sys/arm/include/cpufunc.h
===================================================================
--- sys/arm/include/cpufunc.h	(revision 200988)
+++ sys/arm/include/cpufunc.h	(working copy)
@@ -283,6 +283,28 @@
 u_int	arm8_clock_config	(u_int, u_int);
 #endif
 
+
+#ifdef CPU_FA526
+void	fa526_setup		(char *arg);
+void	fa526_setttb		(u_int ttb);
+void	fa526_context_switch	(void);
+void	fa526_cpu_sleep		(int);
+void	fa526_tlb_flushI_SE	(u_int);
+void	fa526_tlb_flushID_SE	(u_int);
+void	fa526_flush_prefetchbuf	(void);
+void	fa526_flush_brnchtgt_E	(u_int);
+
+void	fa526_icache_sync_all	(void);
+void	fa526_icache_sync_range(vm_offset_t start, vm_size_t end);
+void	fa526_dcache_wbinv_all	(void);
+void	fa526_dcache_wbinv_range(vm_offset_t start, vm_size_t end);
+void	fa526_dcache_inv_range	(vm_offset_t start, vm_size_t end);
+void	fa526_dcache_wb_range	(vm_offset_t start, vm_size_t end);
+void	fa526_idcache_wbinv_all(void);
+void	fa526_idcache_wbinv_range(vm_offset_t start, vm_size_t end);
+#endif
+
+
 #ifdef CPU_SA110
 void	sa110_setup		(char *string);
 void	sa110_context_switch	(void);
@@ -445,6 +467,7 @@
 #if defined(CPU_ARM9) || defined(CPU_ARM9E) || defined(CPU_ARM10) || \
   defined(CPU_SA110) || defined(CPU_SA1100) || defined(CPU_SA1110) || \
   defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) ||	     \
+    defined(CPU_FA526) || \
   defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) ||	     \
   defined(CPU_XSCALE_80219) || defined(CPU_XSCALE_81342)
   
Index: sys/arm/econa/econa_var.h
===================================================================
--- sys/arm/econa/econa_var.h	(revision 0)
+++ sys/arm/econa/econa_var.h	(revision 0)
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2009 Yohanes Nugroho  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 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 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 _ARM_ECONA_VAR_H
+#define _ARM_ECONA_VAR_H
+
+extern bus_space_tag_t obio_tag;
+
+struct econa_softc {
+	device_t dev;
+	bus_space_tag_t sc_st;
+	bus_space_handle_t sc_sh;
+	bus_space_handle_t sc_sys_sh;
+	struct rman sc_irq_rman;
+	struct rman sc_mem_rman;
+};
+
+struct econa_ivar {
+	struct resource_list resources;
+};
+
+#endif
Index: sys/arm/econa/files.econa
===================================================================
--- sys/arm/econa/files.econa	(revision 0)
+++ sys/arm/econa/files.econa	(revision 0)
@@ -0,0 +1,14 @@
+# $FreeBSD $
+arm/arm/cpufunc_asm_fa526.S	standard
+arm/econa/econa_machdep.c		standard
+arm/econa/econa.c			standard
+arm/econa/timer.c			standard
+arm/econa/uart_bus_ec.c		optional	uart
+arm/econa/uart_cpu_ec.c		optional	uart
+dev/uart/uart_dev_ns8250.c	optional	uart
+arm/arm/irq_dispatch.S		standard
+arm/arm/bus_space_generic.c		standard
+arm/econa/ehci_ebus.c	standard	ehci
+arm/econa/ohci_ec.c	standard	ohci
+arm/econa/if_ece.c		standard
+arm/econa/cfi_bus_econa.c		optional	cfi
Index: sys/arm/econa/econa_machdep.c
===================================================================
--- sys/arm/econa/econa_machdep.c	(revision 0)
+++ sys/arm/econa/econa_machdep.c	(revision 0)
@@ -0,0 +1,430 @@
+/*-
+ * Copyright (c) 2009 Yohanes Nugroho
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "opt_msgbuf.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/signalvar.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/cons.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/buf.h>
+#include <sys/exec.h>
+#include <sys/kdb.h>
+#include <sys/msgbuf.h>
+#include <machine/reg.h>
+#include <machine/cpu.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_map.h>
+#include <vm/vnode_pager.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+#include <machine/pcb.h>
+#include <machine/undefined.h>
+#include <machine/machdep.h>
+#include <machine/metadata.h>
+#include <machine/armreg.h>
+#include <machine/bus.h>
+#include <sys/reboot.h>
+#include "econa_reg.h"
+
+#define KERNEL_PT_SYS		0	/* Page table for mapping proc0 zero page */
+#define KERNEL_PT_KERN		1
+#define KERNEL_PT_KERN_NUM	22
+#define KERNEL_PT_AFKERNEL	KERNEL_PT_KERN + KERNEL_PT_KERN_NUM	/* L2 table for mapping after kernel */
+#define	KERNEL_PT_AFKERNEL_NUM	5
+
+/* this should be evenly divisable by PAGE_SIZE / L2_TABLE_SIZE_REAL (or 4) */
+#define NUM_KERNEL_PTS		(KERNEL_PT_AFKERNEL + KERNEL_PT_AFKERNEL_NUM)
+
+/* Define various stack sizes in pages */
+#define IRQ_STACK_SIZE	1
+#define ABT_STACK_SIZE	1
+#define UND_STACK_SIZE	1
+
+extern u_int data_abort_handler_address;
+extern u_int prefetch_abort_handler_address;
+extern u_int undefined_handler_address;
+
+struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
+
+extern void *_end;
+
+extern int *end;
+
+struct pcpu __pcpu;
+struct pcpu *pcpup = &__pcpu;
+
+/* Physical and virtual addresses for some global pages */
+
+vm_paddr_t phys_avail[10];
+vm_paddr_t dump_avail[4];
+vm_offset_t physical_pages;
+
+struct pv_addr systempage;
+struct pv_addr msgbufpv;
+struct pv_addr irqstack;
+struct pv_addr undstack;
+struct pv_addr abtstack;
+struct pv_addr kernelstack;
+
+static void *boot_arg1;
+static void *boot_arg2;
+
+static struct trapframe proc0_tf;
+
+/* Static device mappings. */
+static const struct pmap_devmap econa_devmap[] = {
+	{
+		/*
+		 * This maps DDR SDRAM
+		 */
+		0x40000000, /*virtual*/
+		0x40000000, /*physical*/
+		0x1000000, /*size*/
+		VM_PROT_READ|VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	/*
+	 * Map the on-board devices VA == PA so that we can access them
+	 * with the MMU on or off.
+	 */
+	{
+		/*
+		 * This maps the interrupt controller, the UART
+		 * and the timer.
+		 */
+		0x70000000, /*virtual*/
+		0x70000000, /*physical*/
+		0xE000000, /*size*/
+		VM_PROT_READ|VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{
+		/*
+		 * OHCI + EHCI
+		 */
+		ECONA_OHCI_VBASE, /*virtual*/
+		ECONA_OHCI_PBASE, /*physical*/
+		ECONA_USB_SIZE, /*size*/
+		VM_PROT_READ|VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{
+		/*
+		 * NET
+		 */
+		ECONA_NET_VBASE, /*virtual*/
+		ECONA_NET_PBASE, /*physical*/
+		ECONA_NET_SIZE, /*size 16M*/
+		VM_PROT_READ|VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{
+		/*
+		 * CFI
+		 */
+		ECONA_CFI_VBASE, /*virtual*/
+		ECONA_CFI_PBASE, /*physical*/
+		ECONA_CFI_SIZE, /*size 16M*/
+		VM_PROT_READ|VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{
+		0,
+		0,
+		0,
+		0,
+		0,
+	}
+};
+
+
+void *
+initarm(void *arg, void *arg2)
+{
+	struct pv_addr  kernel_l1pt;
+	int loop, i;
+	u_int l1pagetable;
+	vm_offset_t freemempos;
+	vm_offset_t afterkern;
+	uint32_t memsize;
+	vm_offset_t lastaddr;
+	volatile uint32_t * ddr = (uint32_t *)0x4000000C;
+
+	boot_arg1 = arg;
+	boot_arg2 = arg2;
+	boothowto = RB_VERBOSE;
+	boothowto |=  RB_SINGLE;
+
+	set_cpufuncs();
+	lastaddr = fake_preload_metadata();
+	pcpu_init(pcpup, 0, sizeof(struct pcpu));
+	PCPU_SET(curthread, &thread0);
+
+
+	freemempos = (lastaddr + PAGE_MASK) & ~PAGE_MASK;
+	/* Define a macro to simplify memory allocation */
+#define valloc_pages(var, np)                   \
+	alloc_pages((var).pv_va, (np));         \
+	(var).pv_pa = (var).pv_va + (KERNPHYSADDR - KERNVIRTADDR);
+
+#define alloc_pages(var, np)			\
+	(var) = freemempos;		\
+	freemempos += (np * PAGE_SIZE);		\
+	memset((char *)(var), 0, ((np) * PAGE_SIZE));
+
+	while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0)
+		freemempos += PAGE_SIZE;
+	valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
+	for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) {
+		if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
+			valloc_pages(kernel_pt_table[loop],
+			    L2_TABLE_SIZE / PAGE_SIZE);
+		} else {
+			kernel_pt_table[loop].pv_va = freemempos -
+			    (loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) *
+			    L2_TABLE_SIZE_REAL;
+			kernel_pt_table[loop].pv_pa =
+			    kernel_pt_table[loop].pv_va - KERNVIRTADDR +
+			    KERNPHYSADDR;
+		}
+		i++;
+	}
+
+
+	/*
+	 * Allocate a page for the system page mapped to V0x00000000
+	 * This page will just contain the system vectors and can be
+	 * shared by all processes.
+	 */
+	valloc_pages(systempage, 1);
+
+	/* Allocate stacks for all modes */
+	valloc_pages(irqstack, IRQ_STACK_SIZE);
+	valloc_pages(abtstack, ABT_STACK_SIZE);
+	valloc_pages(undstack, UND_STACK_SIZE);
+	valloc_pages(kernelstack, KSTACK_PAGES);
+	valloc_pages(msgbufpv, round_page(MSGBUF_SIZE) / PAGE_SIZE);
+
+	/*
+	 * Now we start construction of the L1 page table
+	 * We start by mapping the L2 page tables into the L1.
+	 * This means that we can replace L1 mappings later on if necessary
+	 */
+	l1pagetable = kernel_l1pt.pv_va;
+
+	/* Map the L2 pages tables in the L1 page table */
+	pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH,
+	    &kernel_pt_table[KERNEL_PT_SYS]);
+	for (i = 0; i < KERNEL_PT_KERN_NUM; i++)
+		pmap_link_l2pt(l1pagetable, KERNBASE + i * L1_S_SIZE,
+		    &kernel_pt_table[KERNEL_PT_KERN + i]);
+	pmap_map_chunk(l1pagetable, KERNBASE, PHYSADDR,
+	   (((uint32_t)lastaddr - KERNBASE) + PAGE_SIZE) & ~(PAGE_SIZE - 1),
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+	afterkern = round_page((lastaddr + L1_S_SIZE) & ~(L1_S_SIZE - 1));
+	for (i = 0; i < KERNEL_PT_AFKERNEL_NUM; i++) {
+		pmap_link_l2pt(l1pagetable, afterkern + i * L1_S_SIZE,
+		    &kernel_pt_table[KERNEL_PT_AFKERNEL + i]);
+	}
+
+	/* Map the vector page. */
+	pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+
+	/* Map the stack pages */
+	pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa,
+	    IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+	pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa,
+	    ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+	pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa,
+	    UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+	pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa,
+	    KSTACK_PAGES * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+	pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
+	    L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+	pmap_map_chunk(l1pagetable, msgbufpv.pv_va, msgbufpv.pv_pa,
+	    MSGBUF_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+	for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) {
+		pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va,
+		    kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE,
+		    VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+	}
+
+
+	pmap_devmap_bootstrap(l1pagetable, econa_devmap);
+
+	cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT);
+
+	setttb(kernel_l1pt.pv_pa);
+
+	cpu_tlb_flushID();
+
+	cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2));
+
+	cninit();
+
+	memsize = 32*1024*1024;
+
+	switch (((*ddr) >> 4) & 0x3) {
+	case 0:
+		memsize = 8*1024*1024;
+		break;
+	case 1:
+		memsize = 16*1024*1024;
+		break;
+	case 2:
+		memsize = 32*1024*1024;
+		break;
+	case 3:
+		memsize = 64*1024*1024;
+		break;
+	}
+
+
+	physmem = memsize / PAGE_SIZE;
+
+	/*
+	 * Pages were allocated during the secondary bootstrap for the
+	 * stacks for different CPU modes.
+	 * We must now set the r13 registers in the different CPU modes to
+	 * point to these stacks.
+	 * Since the ARM stacks use STMFD etc. we must set r13 to the top end
+	 * of the stack memory.
+	 */
+	cpu_control(CPU_CONTROL_MMU_ENABLE, CPU_CONTROL_MMU_ENABLE);
+
+	set_stackptr(PSR_IRQ32_MODE,
+	    irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE);
+	set_stackptr(PSR_ABT32_MODE,
+	    abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE);
+	set_stackptr(PSR_UND32_MODE,
+	    undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE);
+
+	/*
+	 * We must now clean the cache again....
+	 * Cleaning may be done by reading new data to displace any
+	 * dirty data in the cache. This will have happened in setttb()
+	 * but since we are boot strapping the addresses used for the read
+	 * may have just been remapped and thus the cache could be out
+	 * of sync. A re-clean after the switch will cure this.
+	 * After booting there are no gross relocations of the kernel thus
+	 * this problem will not occur after initarm().
+	 */
+	cpu_idcache_wbinv_all();
+
+	/* Set stack for exception handlers */
+
+	data_abort_handler_address = (u_int)data_abort_handler;
+	prefetch_abort_handler_address = (u_int)prefetch_abort_handler;
+	undefined_handler_address = (u_int)undefinedinstruction_bounce;
+	undefined_init();
+
+	proc_linkup0(&proc0, &thread0);
+	thread0.td_kstack = kernelstack.pv_va;
+	thread0.td_pcb = (struct pcb *)
+		(thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1;
+	thread0.td_pcb->pcb_flags = 0;
+	thread0.td_frame = &proc0_tf;
+	pcpup->pc_curpcb = thread0.td_pcb;
+
+
+	arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
+
+	pmap_curmaxkvaddr = afterkern + L1_S_SIZE * (KERNEL_PT_KERN_NUM - 1);
+
+	/*
+	 * ARM_USE_SMALL_ALLOC uses dump_avail, so it must be filled before
+	 * calling pmap_bootstrap.
+	 */
+	dump_avail[0] = PHYSADDR;
+	dump_avail[1] = PHYSADDR + memsize;
+	dump_avail[2] = 0;
+	dump_avail[3] = 0;
+
+	pmap_bootstrap(freemempos,
+	    KERNVIRTADDR + 3 * memsize,
+	    &kernel_l1pt);
+
+	msgbufp = (void*)msgbufpv.pv_va;
+	msgbufinit(msgbufp, MSGBUF_SIZE);
+
+	mutex_init();
+
+	i = 0;
+#if PHYSADDR != KERNPHYSADDR
+	phys_avail[i++] = PHYSADDR;
+	phys_avail[i++] = KERNPHYSADDR;
+#endif
+	phys_avail[i++] = virtual_avail - KERNVIRTADDR + KERNPHYSADDR;
+
+	phys_avail[i++] = PHYSADDR + memsize;
+	phys_avail[i++] = 0;
+	phys_avail[i++] = 0;
+	/* Do basic tuning, hz etc */
+	init_param1();
+	init_param2(physmem);
+	kdb_init();
+
+	return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -
+	    sizeof(struct pcb)));
+}
Index: sys/arm/econa/if_ece.c
===================================================================
--- sys/arm/econa/if_ece.c	(revision 0)
+++ sys/arm/econa/if_ece.c	(revision 0)
@@ -0,0 +1,2060 @@
+/*-
+ * Copyright (c) 2009 Yohanes Nugroho
+ *
+ * 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 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 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: src/sys/arm/econa/if_ece.c$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <machine/bus.h>
+#include <sys/taskqueue.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <arm/econa/if_ecereg.h>
+#include <arm/econa/if_ecevar.h>
+#include <machine/intr.h>
+
+#include "miibus_if.h"
+
+static uint8_t my_vlan0_mac[ETHER_ADDR_LEN] = { 0x00, 0xaa, 0xbb, 0xcc, 0xdd, 0x19 };
+
+
+/*boot loader expects the hardware state to be the same*/
+int initial_switch_config;
+int initial_cpu_config;
+int initial_port0_config;
+int initial_port1_config;
+
+
+static inline uint32_t
+RD4(struct ece_softc *sc, bus_size_t off)
+{
+	return bus_read_4(sc->mem_res, off);
+}
+
+static inline void
+WR4(struct ece_softc *sc, bus_size_t off, uint32_t val)
+{
+	bus_write_4(sc->mem_res, off, val);
+}
+
+#define ECE_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
+#define	ECE_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
+#define ECE_LOCK_INIT(_sc) \
+	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
+	    MTX_NETWORK_LOCK, MTX_DEF)
+
+
+#define ECE_TXLOCK(_sc)		mtx_lock(&(_sc)->sc_mtx_tx)
+#define	ECE_TXUNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx_tx)
+#define ECE_TXLOCK_INIT(_sc) \
+	mtx_init(&_sc->sc_mtx_tx, device_get_nameunit(_sc->dev), \
+	    "ECE TX Lock", MTX_DEF)
+
+
+#define ECE_CLEANUPLOCK(_sc)		mtx_lock(&(_sc)->sc_mtx_cleanup)
+#define	ECE_CLEANUPUNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx_cleanup)
+#define ECE_CLEANUPLOCK_INIT(_sc) \
+	mtx_init(&_sc->sc_mtx_cleanup, device_get_nameunit(_sc->dev), \
+	    "ECE cleanup Lock", MTX_DEF)
+
+
+#define ECE_RXLOCK(_sc)		mtx_lock(&(_sc)->sc_mtx_rx)
+#define	ECE_RXUNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx_rx)
+#define ECE_RXLOCK_INIT(_sc) \
+	mtx_init(&_sc->sc_mtx_rx, device_get_nameunit(_sc->dev), \
+	    "ECE RX Lock", MTX_DEF)
+
+#define ECE_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
+#define ECE_TXLOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx_tx);
+#define ECE_RXLOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx_rx);
+#define ECE_CLEANUPLOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx_cleanup);
+
+#define ECE_ASSERT_LOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define ECE_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+
+static devclass_t ece_devclass;
+
+/* ifnet entry points */
+
+static void eceinit_locked(void *);
+static void ecestart_locked(struct ifnet *);
+
+static void eceinit(void *);
+static void ecestart(struct ifnet *);
+static void ecestop(struct ece_softc *);
+static int eceioctl(struct ifnet * ifp, u_long, caddr_t);
+
+/* bus entry points */
+
+static int ece_probe(device_t dev);
+static int ece_attach(device_t dev);
+static int ece_detach(device_t dev);
+static void ece_intr(void *);
+static void ece_intr_qf(void *);
+static void ece_intr_status(void *xsc);
+
+
+/* helper routines */
+static int ece_activate(device_t dev);
+static void ece_deactivate(device_t dev);
+static int ece_ifmedia_upd(struct ifnet *ifp);
+static void ece_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
+static int ece_get_mac(struct ece_softc *sc, u_char *eaddr);
+static void ece_set_mac(struct ece_softc *sc, u_char *eaddr);
+static void poweron(void);
+static int configure_cpu_port(struct ece_softc *sc);
+static int configure_lan_port(struct ece_softc *sc, int phy_type);
+static void set_pvid(struct ece_softc *sc, int port0, int port1, int cpu);
+static void set_vlan_vid(struct ece_softc *sc, int vlan);
+static void set_vlan_member(struct ece_softc *sc, int vlan);
+static void set_vlan_tag(struct ece_softc *sc, int vlan);
+static int hardware_init(struct ece_softc *sc);
+static void ece_intr_rx_locked(struct ece_softc *sc, int count);
+
+static void ece_free_desc_dma_tx(struct ece_softc *sc);
+static void ece_free_desc_dma_rx(struct ece_softc *sc);
+
+static void ece_intr_task(void *arg, int pending __unused);
+static void ece_tx_task(void *arg, int pending __unused);
+static void ece_cleanup_task(void *arg, int pending __unused);
+
+static int ece_allocate_dma(struct ece_softc *sc);
+
+static void ece_intr_tx(void *xsc);
+
+static void clear_mac_entries(struct ece_softc *ec, int include_this_mac);
+
+
+static uint32_t read_mac_entry(struct ece_softc *ec,
+			       uint8_t *mac_result,
+			       int first);
+
+
+/*PHY related functions*/
+
+static inline int
+phy_read(struct ece_softc *sc, int phy, int reg)
+{
+	int val;
+	int ii;
+	int status;
+
+	WR4(sc, PHY_CONTROL, 1 << 15);
+	WR4(sc, PHY_CONTROL, ((phy & 0x1) |
+			      ((reg & 0x1F) << 8) | (0x1 << 14)));
+
+	for (ii = 0; ii < 0x1000; ii++) {
+		status = RD4(sc, PHY_CONTROL);
+		if (status & (0x1 << 15)) {
+			/* clear the rw_ok status, and clear other bits value */
+			WR4(sc, PHY_CONTROL, (0x1 << 15));
+			val =  ((status >> 16) & 0xFFFF);
+			return val;
+		}
+	}
+	return 0;
+}
+
+
+static inline void
+phy_write(struct ece_softc *sc, int phy, int reg, int data)
+{
+	int ii;
+
+	WR4(sc, PHY_CONTROL, 1 << 15);
+	WR4(sc, PHY_CONTROL,
+	    ((phy & 0x1) |  ((reg & 0x1F) << 8) |
+	     (0x1 << 13) | ((data & 0xFFFF) << 16)));
+	for (ii = 0; ii < 0x1000; ii++) {
+		if (RD4(sc, PHY_CONTROL) & (0x1 << 15)) {
+			/* clear the rw_ok status, and clear other bits value */
+			WR4(sc, PHY_CONTROL, (0x1 << 15));
+			return;
+		}
+	}
+}
+
+
+/*currently only ic_plus phy is supported*/
+static int get_phy_type(struct ece_softc *sc)
+{
+	uint16_t phy0_id = 0, phy1_id = 0;
+
+	/*
+	 * Use SMI (MDC/MDIO) to read Link Partner's PHY Identifier Register 1
+	 */
+	phy0_id = phy_read(sc, 0, 0x2);
+	phy1_id = phy_read(sc, 1, 0x2);
+
+	if ((phy0_id == 0xFFFF) && (phy1_id == 0x000F)) {
+		return ASIX_GIGA_PHY;
+	} else if ((phy0_id == 0x0243) && (phy1_id == 0x0243)) {
+		return TWO_SINGLE_PHY;
+	} else if ((phy0_id == 0xFFFF) && (phy1_id == 0x0007)) {
+		return VSC8601_GIGA_PHY;
+	} else if ((phy1_id == 0xFFFF) && (phy0_id == 0x0243)) {
+		return IC_PLUS_PHY;
+	}
+	return NOT_FOUND_PHY;
+}
+
+static int
+ece_probe(device_t dev)
+{
+	device_set_desc(dev, "Econa Ethernet Controller");
+	return (0);
+}
+
+/*make sure that the interface is not powered off*/
+static void
+poweron(void)
+{
+	int ii;
+	uint32_t cfg_reg;
+	/*TODO: handle power management properly*/
+	volatile uint32_t * power = (uint32_t *)0x77000004;
+
+	cfg_reg = *(power);
+	/* set reset bit to HIGH active; */
+	cfg_reg |= 0x10;
+	(*power) = cfg_reg;
+	/*pulse delay */
+	for (ii = 0; ii < 0xFFF; ii++)
+	DELAY(100);		;
+	/* set reset bit to LOW active; */
+	cfg_reg &= ~0x10;
+	(*power) = cfg_reg;
+	/*pulse delay */
+	for (ii = 0; ii < 0xFFF; ii++)
+		DELAY(100);		;
+	/* set reset bit to HIGH active; */
+	cfg_reg |= 0x10;
+	(*power) = cfg_reg;
+
+}
+
+
+static int
+ece_attach(device_t dev)
+{
+	struct ece_softc *sc = device_get_softc(dev);
+	struct ifnet *ifp = NULL;
+	struct sysctl_ctx_list *sctx;
+	struct sysctl_oid *soid;
+	int err = 0;
+	u_char eaddr[ETHER_ADDR_LEN];
+	uint32_t rnd;
+	int i, rid;
+
+	poweron();
+
+	sc->dev = dev;
+
+	rid = 0;
+	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+
+	if (sc->mem_res == NULL)
+		goto out;
+
+	rid = 0;
+	sc->irq_res_status = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (sc->irq_res_status == NULL)
+		goto out;
+
+	rid = 1; /*TSTC: Fm-Switch-Tx-Complete*/
+	sc->irq_res_tx = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (sc->irq_res_tx == NULL)
+		goto out;
+
+	rid = 2; /*FSRC: Fm-Switch-Rx-Complete*/
+	sc->irq_res_rec = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (sc->irq_res_rec == NULL)
+		goto out;
+
+	rid = 4; /*FSQF: Fm-Switch-Queue-Full*/
+	sc->irq_res_qf = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (sc->irq_res_qf == NULL)
+		goto out;
+
+	err = ece_activate(dev);
+	if (err)
+		goto out;
+
+	sc->use_rmii = (RD4(sc, ETH_CFG) & ETH_CFG_RMII) == ETH_CFG_RMII;
+
+	/* Sysctls */
+	sctx = device_get_sysctl_ctx(dev);
+	soid = device_get_sysctl_tree(dev);
+	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "rmii",
+	    CTLFLAG_RD, &sc->use_rmii, 0, "rmii in use");
+
+	ECE_LOCK_INIT(sc);
+
+	callout_init_mtx(&sc->tick_ch, &sc->sc_mtx, 0);
+
+	if ((err = ece_get_mac(sc, eaddr)) != 0) {
+		/*
+		 * No MAC address configured. Generate the random one.
+		 */
+		if  (bootverbose)
+			device_printf(dev,
+			    "Generating random ethernet address.\n");
+		rnd = arc4random();
+
+		/*from if_ae.c/if_ate.c*/
+		/*
+		 * Set OUI to convenient locally assigned address.  'b'
+		 * is 0x62, which has the locally assigned bit set, and
+		 * the broadcast/multicast bit clear.
+		 */
+		eaddr[0] = 'b';
+		eaddr[1] = 's';
+		eaddr[2] = 'd';
+		eaddr[3] = (rnd >> 16) & 0xff;
+		eaddr[4] = (rnd >> 8) & 0xff;
+		eaddr[5] = rnd & 0xff;
+
+		for (i=0; i<ETHER_ADDR_LEN; i++) {
+			eaddr[i] = my_vlan0_mac[i];
+		}
+
+	}
+	ece_set_mac(sc, eaddr);
+	sc->ifp = ifp = if_alloc(IFT_ETHER);
+	if (mii_phy_probe(dev, &sc->miibus, ece_ifmedia_upd, ece_ifmedia_sts)) {
+		device_printf(dev, "Cannot find my PHY.\n");
+		err = ENXIO;
+		goto out;
+	}
+	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_capabilities = IFCAP_HWCSUM;
+
+	ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP);
+	ifp->if_capenable = ifp->if_capabilities; /*  */
+	ifp->if_start = ecestart;
+	ifp->if_ioctl = eceioctl;
+	ifp->if_init = eceinit;
+	ifp->if_snd.ifq_drv_maxlen = ECE_MAX_TX_BUFFERS-1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, ECE_MAX_TX_BUFFERS-1);
+	IFQ_SET_READY(&ifp->if_snd);
+
+
+	/* Create local taskq. */
+
+	TASK_INIT(&sc->sc_intr_task, 0, ece_intr_task, sc);
+	TASK_INIT(&sc->sc_tx_task, 1, ece_tx_task, ifp);
+	TASK_INIT(&sc->sc_cleanup_task, 2, ece_cleanup_task, sc);
+	sc->sc_tq = taskqueue_create_fast("ece_taskq", M_WAITOK,
+	    taskqueue_thread_enqueue, &sc->sc_tq);
+	if (sc->sc_tq == NULL) {
+		device_printf(sc->dev, "could not create taskqueue\n");
+		goto out;
+
+	}
+
+	ether_ifattach(ifp, eaddr);
+
+	/*
+	 * Activate interrupts
+	 */
+	err = bus_setup_intr(dev, sc->irq_res_rec, INTR_TYPE_NET | INTR_MPSAFE,
+			     NULL, ece_intr, sc, &sc->intrhand);
+	if (err) {
+		ether_ifdetach(ifp);
+		ECE_LOCK_DESTROY(sc);
+		goto out;
+	}
+
+	err = bus_setup_intr(dev, sc->irq_res_status, INTR_TYPE_NET | INTR_MPSAFE,
+			     NULL, ece_intr_status, sc, &sc->intrhand_status);
+	if (err) {
+		ether_ifdetach(ifp);
+		ECE_LOCK_DESTROY(sc);
+		goto out;
+	}
+
+	err = bus_setup_intr(dev, sc->irq_res_qf, INTR_TYPE_NET | INTR_MPSAFE,
+	    NULL,ece_intr_qf,  sc, &sc->intrhand_qf);
+
+	if (err) {
+		ether_ifdetach(ifp);
+		ECE_LOCK_DESTROY(sc);
+		goto out;
+	}
+
+	err = bus_setup_intr(dev, sc->irq_res_tx, INTR_TYPE_NET | INTR_MPSAFE,
+	    NULL,ece_intr_tx,  sc, &sc->intrhand_tx);
+
+	if (err) {
+		ether_ifdetach(ifp);
+		ECE_LOCK_DESTROY(sc);
+		goto out;
+	}
+
+
+	ECE_TXLOCK_INIT(sc);
+	ECE_RXLOCK_INIT(sc);
+	ECE_CLEANUPLOCK_INIT(sc);
+
+	/*enable all interrupt sources*/
+	WR4(sc, INTERRUPT_MASK, 0x00000000);
+
+	/*enable port 0*/
+	WR4(sc, PORT_0_CONFIG, RD4(sc, PORT_0_CONFIG) & ~((0x1 << 18)));
+
+	taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq",
+	    device_get_nameunit(sc->dev));
+
+out:;
+	if (err)
+		ece_deactivate(dev);
+	if (err && ifp)
+		if_free(ifp);
+	return (err);
+}
+
+static int
+ece_detach(device_t dev)
+{
+	/*TODO: release resources*/
+
+	struct ece_softc *sc = device_get_softc(dev);
+	struct ifnet *ifp = sc->ifp;
+
+	ecestop(sc);
+	if (ifp != NULL) {
+		ether_ifdetach(ifp);
+		if_free(ifp);
+	}
+
+	ece_deactivate(dev);
+
+
+	return 0;
+}
+
+static void
+ece_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+	u_int32_t *paddr;
+	KASSERT(nsegs == 1, ("wrong number of segments, should be 1"));
+	paddr = arg;
+	*paddr = segs->ds_addr;
+}
+
+
+static int
+ece_alloc_desc_dma_tx(struct ece_softc *sc)
+{
+
+	int i;
+	int error;
+
+	/* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
+	error = bus_dma_tag_create(sc->sc_parent_tag,	/* parent */
+	    16, 0,				/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,			/* highaddr */
+	    NULL, NULL,				/* filtfunc, filtfuncarg */
+	    sizeof(eth_tx_desc_t)*ECE_MAX_TX_BUFFERS, 1,		/* maxsize, nsegments */
+	    sizeof(eth_tx_desc_t)*ECE_MAX_TX_BUFFERS, 0,		/* maxsegsz, flags */
+	    NULL, NULL,				/* lockfunc, lockfuncarg */
+	    &sc->dmatag_data_tx);		/* dmat */
+
+
+	/* allocate memory for tx ring */
+	error = bus_dmamem_alloc(sc->dmatag_data_tx,
+				 (void**)&(sc->desc_tx),
+				 BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
+				 &(sc->dmamap_ring_tx));
+
+	if (error) {
+		if_printf(sc->ifp, "failed to allocate DMA memory\n");
+		bus_dma_tag_destroy(sc->dmatag_data_tx);
+		sc->dmatag_data_tx = 0;
+		return (ENXIO);
+	}
+
+	/* load ring dma */
+	error = bus_dmamap_load(sc->dmatag_data_tx, sc->dmamap_ring_tx,
+				sc->desc_tx, sizeof(eth_tx_desc_t)*ECE_MAX_TX_BUFFERS, ece_getaddr,
+				&(sc->ring_paddr_tx), BUS_DMA_NOWAIT);
+
+	if (error) {
+		if_printf(sc->ifp, "can't load descriptor\n");
+		bus_dmamem_free(sc->dmatag_data_tx, sc->desc_tx,
+				sc->dmamap_ring_tx);
+		sc->desc_tx = NULL;
+		bus_dma_tag_destroy(sc->dmatag_data_tx);
+		sc->dmatag_data_tx = 0;
+		return (ENXIO);
+	}
+
+	/* Allocate a busdma tag for mbufs. Alignment is 2 bytes */
+	error = bus_dma_tag_create(sc->sc_parent_tag,	/* parent */
+	    1, 0,				/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,			/* highaddr */
+	    NULL, NULL,				/* filtfunc, filtfuncarg */
+	    MCLBYTES*MAX_FRAGMENT, MAX_FRAGMENT,			/* maxsize, nsegments */
+	    MCLBYTES, 0,			/* maxsegsz, flags */
+	    NULL, NULL,				/* lockfunc, lockfuncarg */
+	    &sc->dmatag_ring_tx);			/* dmat */
+
+
+	if (error) {
+		if_printf(sc->ifp, "failed to create busdma tag for mbufs\n");
+		return (ENXIO);
+	}
+
+	for (i=0; i<ECE_MAX_TX_BUFFERS; i++) {
+		/* create dma map for each descriptor */
+		error = bus_dmamap_create(sc->dmatag_ring_tx, 0,
+					  &(sc->tx_desc[i].dmamap));
+		if (error) {
+			if_printf(sc->ifp, "failed to create map for mbuf\n");
+			return (ENXIO);
+		}
+	}
+	return 0;
+}
+
+
+static void
+ece_free_desc_dma_tx(struct ece_softc *sc)
+{
+
+	int i;
+
+	for (i = 0; i < ECE_MAX_TX_BUFFERS; i++) {
+		if (sc->tx_desc[i].buff) {
+			m_freem(sc->tx_desc[i].buff);
+			sc->tx_desc[i].buff= 0;
+		}
+	}
+
+	if (sc->dmamap_ring_tx) {
+		bus_dmamap_unload(sc->dmatag_data_tx, sc->dmamap_ring_tx);
+		if (sc->desc_tx) {
+			bus_dmamem_free(sc->dmatag_data_tx,
+					sc->desc_tx, sc->dmamap_ring_tx);
+		}
+		sc->dmamap_ring_tx = 0;
+	}
+
+	if (sc->dmatag_data_tx) {
+		bus_dma_tag_destroy(sc->dmatag_data_tx);
+		sc->dmatag_data_tx = 0;
+	}
+
+	if (sc->dmatag_ring_tx) {
+		for (i = 0; i<ECE_MAX_TX_BUFFERS; i++) {
+			bus_dmamap_destroy(sc->dmatag_ring_tx,
+					   sc->tx_desc[i].dmamap);
+			sc->tx_desc[i].dmamap = 0;
+		}
+		bus_dma_tag_destroy(sc->dmatag_ring_tx);
+		sc->dmatag_ring_tx = 0;
+	}
+}
+
+
+static int
+ece_alloc_desc_dma_rx(struct ece_softc *sc)
+{
+	int error;
+
+
+	/* Allocate a busdma tag and DMA safe memory for RX descriptors. */
+	error = bus_dma_tag_create(sc->sc_parent_tag,	/* parent */
+	    16, 0,				/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,			/* highaddr */
+	    NULL, NULL,				/* filtfunc, filtfuncarg */
+	    sizeof(eth_rx_desc_t)*ECE_MAX_RX_BUFFERS, 1,		/* maxsize, nsegments */
+	    sizeof(eth_rx_desc_t)*ECE_MAX_RX_BUFFERS, 0,		/* maxsegsz, flags */
+	    NULL, NULL,				/* lockfunc, lockfuncarg */
+	    &sc->dmatag_data_rx);		/* dmat */
+
+	/*allocate ring*/
+	error = bus_dmamem_alloc(sc->dmatag_data_rx,
+				 (void**)&(sc->desc_rx),
+				 BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
+				 &(sc->dmamap_ring_rx));
+
+	if (error) {
+		if_printf(sc->ifp, "failed to allocate DMA memory\n");
+		return (ENXIO);
+	}
+
+	/* load dmamap */
+	error = bus_dmamap_load(sc->dmatag_data_rx, sc->dmamap_ring_rx,
+				sc->desc_rx,
+				sizeof(eth_rx_desc_t)*ECE_MAX_RX_BUFFERS,
+				ece_getaddr,
+				&(sc->ring_paddr_rx), BUS_DMA_NOWAIT);
+
+	if (error) {
+		if_printf(sc->ifp, "can't load descriptor\n");
+		bus_dmamem_free(sc->dmatag_data_rx, sc->desc_rx,
+				sc->dmamap_ring_rx);
+		bus_dma_tag_destroy(sc->dmatag_data_rx);
+		sc->desc_rx = NULL;
+		return (ENXIO);
+	}
+
+
+
+	/* Allocate a busdma tag for mbufs. */
+	error = bus_dma_tag_create(sc->sc_parent_tag,	/* parent */
+	    16, 0,				/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,			/* highaddr */
+	    NULL, NULL,				/* filtfunc, filtfuncarg */
+	    MCLBYTES, 1,			/* maxsize, nsegments */
+	    MCLBYTES, 0,			/* maxsegsz, flags */
+	    NULL, NULL,				/* lockfunc, lockfuncarg */
+	    &sc->dmatag_ring_rx);			/* dmat */
+
+
+	if (error) {
+		if_printf(sc->ifp, "failed to create busdma tag for mbufs\n");
+		return (ENXIO);
+	}
+
+
+	for (int i =0; i<ECE_MAX_RX_BUFFERS; i++) {
+		error = bus_dmamap_create(sc->dmatag_ring_rx, 0, &sc->rx_desc[i].dmamap);
+		if (error) {
+			if_printf(sc->ifp, "failed to create map for mbuf\n");
+			return (ENXIO);
+		}
+	}
+
+	error = bus_dmamap_create(sc->dmatag_ring_rx, 0, &sc->rx_sparemap);
+	if (error) {
+		if_printf(sc->ifp, "failed to create spare map\n");
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+
+static void
+ece_free_desc_dma_rx(struct ece_softc *sc)
+{
+	int i;
+
+	for (i = 0; i < ECE_MAX_RX_BUFFERS; i++) {
+		if (sc->rx_desc[i].buff) {
+			m_freem(sc->rx_desc[i].buff);
+			sc->rx_desc[i].buff= 0;
+		}
+	}
+
+	if (sc->dmatag_data_rx) {
+		bus_dmamap_unload(sc->dmatag_data_rx, sc->dmamap_ring_rx);
+		bus_dmamem_free(sc->dmatag_data_rx, sc->desc_rx,
+			sc->dmamap_ring_rx);
+		bus_dma_tag_destroy(sc->dmatag_data_rx);
+		sc->dmatag_data_rx = 0;
+		sc->dmamap_ring_rx = 0;
+		sc->desc_rx = 0;
+	}
+
+	if (sc->dmatag_ring_rx) {
+		for (i = 0; i<ECE_MAX_RX_BUFFERS; i++) {
+			bus_dmamap_destroy(sc->dmatag_ring_rx, sc->rx_desc[i].dmamap);
+		}
+		bus_dmamap_destroy(sc->dmatag_ring_rx, sc->rx_sparemap);
+		bus_dma_tag_destroy(sc->dmatag_ring_rx);
+		sc->dmatag_ring_rx = 0;
+	}
+
+}
+
+
+static int
+ece_new_rxbuf(struct ece_softc *sc, struct rx_desc_info* descinfo)
+{
+	struct mbuf *new_mbuf;
+	bus_dma_segment_t seg[1];
+	bus_dmamap_t map;
+	int error;
+	int nsegs;
+	bus_dma_tag_t tag;
+
+	tag = sc->dmatag_ring_rx;
+
+
+	new_mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+
+	if (new_mbuf == NULL)
+		return (ENOBUFS);
+
+	new_mbuf->m_len = new_mbuf->m_pkthdr.len = MCLBYTES;
+
+
+	error = bus_dmamap_load_mbuf_sg(tag, sc->rx_sparemap, new_mbuf, seg, &nsegs,
+	    BUS_DMA_NOWAIT);
+
+	KASSERT(nsegs == 1, ("Too many segments returned!"));
+
+	if (nsegs != 1 || error) {
+		m_free(new_mbuf);
+		return (ENOBUFS);
+	}
+
+	if (descinfo->buff != NULL) {
+		bus_dmamap_sync(tag, descinfo->dmamap, BUS_DMASYNC_POSTREAD);
+		bus_dmamap_unload(tag, descinfo->dmamap);
+	}
+
+	map = descinfo->dmamap;
+	descinfo->dmamap = sc->rx_sparemap;
+	sc->rx_sparemap = map;
+
+	bus_dmamap_sync(tag, descinfo->dmamap, BUS_DMASYNC_PREREAD);
+
+	descinfo->buff = new_mbuf;
+	descinfo->desc->data_ptr = seg->ds_addr;
+	descinfo->desc->length = seg->ds_len-2;
+
+	return (0);
+}
+
+static int
+ece_allocate_dma(struct ece_softc *sc)
+{
+	eth_tx_desc_t *desctx;
+	eth_rx_desc_t *descrx;
+	int i;
+	int error;
+
+	/*create parent tag for tx and rx*/
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(sc->dev),	/* parent */
+	    1, 0,				/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,			/* lowaddr */
+	    BUS_SPACE_MAXADDR,			/* highaddr */
+	    NULL, NULL,				/* filter, filterarg */
+	    BUS_SPACE_MAXSIZE_32BIT, 0,		/* maxsize, nsegments */
+	    BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
+	    0,					/* flags */
+	    NULL, NULL,				/* lockfunc, lockarg */
+	    &sc->sc_parent_tag);
+
+	ece_alloc_desc_dma_tx(sc);
+
+	for (i = 0; i < ECE_MAX_TX_BUFFERS; i++) {
+		desctx = (eth_tx_desc_t *)(&sc->desc_tx[i]);
+		memset(desctx, 0, sizeof(eth_tx_desc_t));
+		desctx->length = MAX_PACKET_LEN;
+		desctx->cown = 1;
+		if (i==ECE_MAX_TX_BUFFERS-1) {
+			desctx->eor = 1;
+		}
+	}
+
+	ece_alloc_desc_dma_rx(sc);
+
+	for (i = 0; i < ECE_MAX_RX_BUFFERS; i++) {
+		descrx = &(sc->desc_rx[i]);
+		memset(descrx, 0, sizeof(eth_rx_desc_t));
+		sc->rx_desc[i].desc = descrx;
+		sc->rx_desc[i].buff = 0;
+		ece_new_rxbuf(sc, &(sc->rx_desc[i]));
+
+		if (i==ECE_MAX_RX_BUFFERS-1) {
+			descrx->eor = 1;
+		}
+	}
+	sc->tx_prod = 0;
+	sc->tx_cons = 0;
+	sc->last_rx = 0;
+	sc->desc_curr_tx = 0;
+
+	return (0);
+}
+
+
+
+static int
+ece_activate(device_t dev)
+{
+	struct ece_softc *sc;
+	int err;
+	uint32_t mac_port_config;
+#if 0
+	int i;
+	int table_end;
+	char mac[ETHER_ADDR_LEN];
+#endif
+
+	struct ifnet *ifp;
+
+	sc = device_get_softc(dev);
+	ifp = sc->ifp;
+
+	initial_switch_config = RD4(sc, SWITCH_CONFIG);
+	initial_cpu_config = RD4(sc, CPU_PORT_CONFIG);
+	initial_port0_config = RD4(sc, MAC_PORT_0_CONFIG);
+	initial_port1_config = RD4(sc, MAC_PORT_1_CONFIG);
+
+#if 0
+	printf("initial_switch_config %08x\n", initial_switch_config);
+	printf("initial_cpu_config %08x\n", 	initial_cpu_config);
+	printf("initial_port0_config %08x\n", 	initial_port0_config);
+	printf("initial_port1_config %08x\n", 	initial_port1_config);
+
+	WR4(sc, SWITCH_CONFIG, 0x3aa730);
+	WR4(sc, CPU_PORT_CONFIG, 0x804c0000);
+	WR4(sc, MAC_PORT_0_CONFIG, 0xe6463d94);
+	WR4(sc, MAC_PORT_1_CONFIG, 0x463d96);
+
+	table_end = read_mac_entry(sc, mac, 1);
+	while (!table_end) {
+		for (i = 0; i<ETHER_ADDR_LEN; i++) {
+			printf("%02x ", mac[i]);
+		}
+		printf("\n");
+		table_end = read_mac_entry(sc, mac, 0);
+	}
+
+#endif
+	/*Disable Port 0 */
+	mac_port_config = RD4(sc, MAC_PORT_0_CONFIG);
+	mac_port_config |= ((0x1 << 18));
+	WR4(sc, MAC_PORT_0_CONFIG, mac_port_config);
+
+	/*Disable Port 1 */
+	mac_port_config = RD4(sc, MAC_PORT_1_CONFIG);
+	mac_port_config |= ((0x1 << 18));
+	WR4(sc, MAC_PORT_1_CONFIG, mac_port_config);
+
+
+	err = ece_allocate_dma(sc);
+	if (err) {
+		if_printf(sc->ifp, "failed allocating dma\n");
+		goto out;
+	}
+
+
+	WR4(sc, TS_DESCRIPTOR_POINTER, sc->ring_paddr_tx);
+	WR4(sc, TS_DESCRIPTOR_BASE_ADDR, sc->ring_paddr_tx);
+
+	WR4(sc, FS_DESCRIPTOR_POINTER, sc->ring_paddr_rx);
+	WR4(sc, FS_DESCRIPTOR_BASE_ADDR, sc->ring_paddr_rx);
+
+
+	WR4(sc, FS_DMA_CONTROL, 1);
+
+	return (0);
+out:
+	return (ENXIO);
+
+}
+
+static void
+ece_deactivate(device_t dev)
+{
+	struct ece_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (sc->intrhand)
+		bus_teardown_intr(dev, sc->irq_res_rec, sc->intrhand);
+
+	sc->intrhand = 0;
+
+	if (sc->intrhand_qf)
+		bus_teardown_intr(dev, sc->irq_res_qf, sc->intrhand_qf);
+
+	sc->intrhand_qf = 0;
+
+	bus_generic_detach(sc->dev);
+	if (sc->miibus)
+		device_delete_child(sc->dev, sc->miibus);
+	if (sc->mem_res)
+		bus_release_resource(dev, SYS_RES_IOPORT,
+		    rman_get_rid(sc->mem_res), sc->mem_res);
+	sc->mem_res = 0;
+	if (sc->irq_res_rec)
+		bus_release_resource(dev, SYS_RES_IRQ,
+		    rman_get_rid(sc->irq_res_rec), sc->irq_res_rec);
+
+	if (sc->irq_res_qf)
+		bus_release_resource(dev, SYS_RES_IRQ,
+		    rman_get_rid(sc->irq_res_qf), sc->irq_res_qf);
+
+	if (sc->irq_res_qf)
+		bus_release_resource(dev, SYS_RES_IRQ,
+		    rman_get_rid(sc->irq_res_status), sc->irq_res_status);
+
+	sc->irq_res_rec = 0;
+	sc->irq_res_qf = 0;
+	sc->irq_res_status = 0;
+	ECE_TXLOCK_DESTROY(sc);
+	ECE_RXLOCK_DESTROY(sc);
+
+	ece_free_desc_dma_tx(sc);
+	ece_free_desc_dma_rx(sc);
+
+
+	return;
+}
+
+/*
+ * Change media according to request.
+ */
+static int
+ece_ifmedia_upd(struct ifnet *ifp)
+{
+	struct ece_softc *sc = ifp->if_softc;
+	struct mii_data *mii;
+	int	error;
+
+	mii = device_get_softc(sc->miibus);
+	ECE_LOCK(sc);
+	error = mii_mediachg(mii);
+	ECE_UNLOCK(sc);
+	return (error);
+}
+
+/*
+ * Notify the world which media we're using.
+ */
+static void
+ece_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+	struct ece_softc *sc = ifp->if_softc;
+	struct mii_data *mii;
+
+	mii = device_get_softc(sc->miibus);
+	ECE_LOCK(sc);
+	mii_pollstat(mii);
+	ifmr->ifm_active = mii->mii_media_active;
+	ifmr->ifm_status = mii->mii_media_status;
+	ECE_UNLOCK(sc);
+}
+
+
+static void
+ece_tick(void *xsc)
+{
+	struct ece_softc *sc = xsc;
+	struct mii_data *mii;
+	int active;
+
+	mii = device_get_softc(sc->miibus);
+	active = mii->mii_media_active;
+	mii_tick(mii);
+
+	/*
+	 * Schedule another timeout one second from now.
+	 */
+	callout_reset(&sc->tick_ch, hz, ece_tick, sc);
+}
+
+
+static uint32_t read_mac_entry(struct ece_softc *ec,
+			       uint8_t *mac_result,
+	int first)
+{
+	uint32_t  ii;
+	struct arl_table_entry_t entry;
+	uint32_t *entry_val;
+	WR4(ec, ARL_TABLE_ACCESS_CONTROL_0, 0);
+	WR4(ec, ARL_TABLE_ACCESS_CONTROL_1, 0);
+	WR4(ec, ARL_TABLE_ACCESS_CONTROL_2, 0);
+	if (first)
+		WR4(ec, ARL_TABLE_ACCESS_CONTROL_0, 0x1);
+	else
+		WR4(ec, ARL_TABLE_ACCESS_CONTROL_0, 0x2);
+
+	for (ii = 0; ii < 0x1000; ii++) {
+		if (RD4(ec, ARL_TABLE_ACCESS_CONTROL_1) & (0x1))
+			break;
+	}
+	entry_val = (uint32_t*) (&entry);
+	entry_val[0] = RD4(ec, ARL_TABLE_ACCESS_CONTROL_1);
+	entry_val[1] = RD4(ec, ARL_TABLE_ACCESS_CONTROL_2);
+
+	if (mac_result)
+		memcpy(mac_result, entry.mac_addr, ETHER_ADDR_LEN);
+
+
+	return entry.table_end;
+}
+
+
+static uint32_t write_arl_table_entry(struct ece_softc *ec,
+				      uint32_t filter,
+				      uint32_t vlan_mac,
+				      uint32_t vlan_gid,
+				      uint32_t age_field,
+				      uint32_t port_map,
+				      const uint8_t *mac_addr)
+{
+	uint32_t  ii;
+	uint32_t *entry_val;
+	struct arl_table_entry_t entry;
+
+	memset(&entry, 0, sizeof(entry));
+
+	entry.filter = filter;
+	entry.vlan_mac = vlan_mac;
+	entry.vlan_gid = vlan_gid;
+	entry.age_field = age_field;
+	entry.port_map = port_map;
+	memcpy(entry.mac_addr, mac_addr, ETHER_ADDR_LEN);
+
+	entry_val = (uint32_t*) (&entry);
+
+	WR4(ec, ARL_TABLE_ACCESS_CONTROL_0, 0);
+	WR4(ec, ARL_TABLE_ACCESS_CONTROL_1, 0);
+	WR4(ec, ARL_TABLE_ACCESS_CONTROL_2, 0);
+
+	WR4(ec, ARL_TABLE_ACCESS_CONTROL_1, entry_val[0]);
+	WR4(ec, ARL_TABLE_ACCESS_CONTROL_2, entry_val[1]);
+
+	/* issue the write command */
+	WR4(ec, ARL_TABLE_ACCESS_CONTROL_0, (0x1 << 3));
+
+	for (ii = 0; ii < 0x1000; ii++) {
+		if (RD4(ec, ARL_TABLE_ACCESS_CONTROL_1) & (0x1))
+			return 1; /*write ok*/
+	}
+	/* write failed*/
+	return 0;
+}
+
+
+static void remove_mac_entry(struct ece_softc *sc,
+				 uint8_t *mac)
+{
+	/* invalid age_field mean erase this entry*/
+	write_arl_table_entry(sc, 0, 1, VLAN0_GROUP_ID,
+			      INVALID_ENTRY, VLAN0_GROUP,
+			      mac);
+
+}
+
+
+static void add_mac_entry(struct ece_softc *sc,
+			  uint8_t *mac)
+{
+	write_arl_table_entry(sc, 0, 1, VLAN0_GROUP_ID,
+			      NEW_ENTRY, VLAN0_GROUP,
+			      mac);
+}
+
+/**
+ * The behavior of ARL table reading and deletion is not well defined
+ * in the documentation. To be safe, all mac addresses are put to a
+ * list, then deleted.
+ *
+ */
+static void clear_mac_entries(struct ece_softc *ec, int include_this_mac)
+{
+	int table_end;
+	struct mac_list * temp;
+	struct mac_list * mac_list_header;
+	struct mac_list * current;
+	char mac[ETHER_ADDR_LEN];
+
+	current = 0;
+	mac_list_header = 0;
+
+	table_end = read_mac_entry(ec, mac, 1);
+	while (!table_end) {
+		if (!include_this_mac &&
+		    memcmp(mac, my_vlan0_mac, ETHER_ADDR_LEN)==0) {
+			/* read next entry */
+			table_end = read_mac_entry(ec, mac, 0);
+			continue;
+		}
+
+		temp = (struct mac_list*)malloc(sizeof(struct mac_list),M_DEVBUF, M_NOWAIT | M_ZERO);
+		memcpy(temp->mac_addr, mac, ETHER_ADDR_LEN);
+		temp->next = 0;
+		if (mac_list_header) {
+			current->next = temp;
+			current = temp;
+		} else {
+			mac_list_header = temp;
+			current = temp;
+		}
+		/*read next */
+		table_end = read_mac_entry(ec, mac, 0);
+	}
+
+	current = mac_list_header;
+
+	while (current) {
+		remove_mac_entry(ec, current->mac_addr);
+		temp = current;
+		current = current->next;
+		free(temp, M_DEVBUF);
+	}
+}
+
+
+
+static int configure_lan_port(struct ece_softc *sc, int phy_type)
+{
+	uint32_t sw_config;
+	uint32_t mac_port_config;
+
+
+	/*
+	 * Configure
+	 */
+	sw_config = RD4(sc, SWITCH_CONFIG);
+	/* enable fast aging */
+	sw_config |= (0xF);
+	/* CRC stripping */
+	//sw_config |= (0x1 << 21);
+	/* IVL learning */
+	sw_config |= (0x1 << 22);
+	/* HNAT disable */
+	sw_config &= ~(0x1 << 23);
+
+	sw_config |= (1 << 29 | 1 << 30 | 1 << 28);
+
+	WR4(sc, SWITCH_CONFIG, sw_config);
+
+	sw_config = RD4(sc, SWITCH_CONFIG);
+
+	mac_port_config = RD4(sc, MAC_PORT_0_CONFIG);
+
+	if (!(mac_port_config & 0x1) || (mac_port_config & 0x2))
+		if_printf(sc->ifp, "STR9104: Link Down, 0x%08x!\n",
+		       mac_port_config);
+	else {
+		WR4(sc, MAC_PORT_0_CONFIG, mac_port_config);
+	}
+	return 0;
+}
+
+static void set_pvid(struct ece_softc *sc, int port0, int port1, int cpu)
+{
+	uint32_t val;
+	val = RD4(sc, VLAN_PORT_PVID) & (~(0x7 << 0));
+	WR4(sc, VLAN_PORT_PVID, val);
+	val = RD4(sc, VLAN_PORT_PVID) | ((port0) & 0x07);
+	WR4(sc, VLAN_PORT_PVID, val);
+	val = RD4(sc, VLAN_PORT_PVID) & (~(0x7 << 4));
+	WR4(sc, VLAN_PORT_PVID, val);
+	val = RD4(sc, VLAN_PORT_PVID) | (((port1) & 0x07) << 4);
+	WR4(sc, VLAN_PORT_PVID, val);
+
+	val = RD4(sc, VLAN_PORT_PVID) & (~(0x7 << 8));
+	WR4(sc, VLAN_PORT_PVID, val);
+	val = RD4(sc, VLAN_PORT_PVID) | (((cpu) & 0x07) << 8);
+	WR4(sc, VLAN_PORT_PVID, val);
+
+}
+
+
+/* VLAN related functions */
+
+static void set_vlan_vid(struct ece_softc *sc, int vlan)
+{
+	const uint32_t regs[] = {
+		VLAN_VID_0_1,
+		VLAN_VID_0_1,
+		VLAN_VID_2_3,
+		VLAN_VID_2_3,
+		VLAN_VID_4_5,
+		VLAN_VID_4_5,
+		VLAN_VID_6_7,
+		VLAN_VID_6_7
+	};
+
+	const int vids[] = {
+		VLAN0_VID,
+		VLAN1_VID,
+		VLAN2_VID,
+		VLAN3_VID,
+		VLAN4_VID,
+		VLAN5_VID,
+		VLAN6_VID,
+		VLAN7_VID
+	};
+
+	uint32_t val;
+	uint32_t reg;
+	int vid;
+
+	reg = regs[vlan];
+	vid = vids[vlan];
+
+	if (vlan & 1) {
+		val = RD4(sc, reg);
+		WR4(sc, reg, val & (~(0xFFF << 0)));
+		val = RD4(sc, reg);
+		WR4(sc, reg, val|((vid & 0xFFF) << 0));
+	} else {
+		val = RD4(sc, reg);
+		WR4(sc, reg, val & (~(0xFFF << 12)));
+		val = RD4(sc, reg);
+		WR4(sc, reg, val|((vid & 0xFFF) << 12));
+	}
+}
+
+
+static void set_vlan_member(struct ece_softc *sc, int vlan)
+{
+	unsigned char shift;
+	uint32_t val;
+	int group;
+	const int groups[] = {
+		VLAN0_GROUP,
+		VLAN1_GROUP,
+		VLAN2_GROUP,
+		VLAN3_GROUP,
+		VLAN4_GROUP,
+		VLAN5_GROUP,
+		VLAN6_GROUP,
+		VLAN7_GROUP
+	};
+
+	group = groups[vlan];
+
+	shift = vlan*3;
+	val = RD4(sc, VLAN_MEMBER_PORT_MAP) &  (~(0x7 << shift));
+	WR4(sc, VLAN_MEMBER_PORT_MAP, val);
+	val = RD4(sc, VLAN_MEMBER_PORT_MAP);
+	WR4(sc, VLAN_MEMBER_PORT_MAP, val | ((group & 0x7) << shift));
+}
+
+
+static void set_vlan_tag(struct ece_softc *sc, int vlan)
+{
+	unsigned char shift;
+	uint32_t val;
+
+	int tag = 0; /* VLAN0_VLAN_TAG .. VLAN7_VLAN_TAG*/
+
+	shift = vlan*3;
+	val = RD4(sc, VLAN_TAG_PORT_MAP) &  (~(0x7 << shift));
+	WR4(sc, VLAN_TAG_PORT_MAP, val);
+	val = RD4(sc, VLAN_TAG_PORT_MAP);
+	WR4(sc, VLAN_TAG_PORT_MAP, val | ((tag & 0x7) << shift));
+}
+
+
+static int configure_cpu_port(struct ece_softc *sc)
+{
+	uint32_t cpu_port_config;
+	int i;
+
+	cpu_port_config = RD4(sc, CPU_PORT_CONFIG);
+	/*SA learning Disable */
+	cpu_port_config |= (0x1 << 19);
+	/*offset 4byte +2 */
+	cpu_port_config &= ~(1 << 31);
+
+
+	WR4(sc, CPU_PORT_CONFIG, cpu_port_config);
+
+	if (!write_arl_table_entry(sc, 0, 1, VLAN0_GROUP_ID,
+				   STATIC_ENTRY, VLAN0_GROUP,
+				   my_vlan0_mac)) {
+		return 1;
+	}
+
+	set_pvid(sc,  PORT0_PVID, PORT1_PVID, CPU_PORT_PVID);
+
+	for (i=0; i<8; i++) {
+		set_vlan_vid(sc, i);
+		set_vlan_member(sc, i);
+		set_vlan_tag(sc, i);
+	}
+
+	/* disable all interrupt status sources */
+	WR4(sc, INTERRUPT_MASK, 0xffff1fff);
+
+	/* clear previous interrupt sources */
+	WR4(sc, INTERRUPT_STATUS, 0x00001FFF);
+
+	WR4(sc, TS_DMA_CONTROL, 0);
+	WR4(sc, FS_DMA_CONTROL, 0);
+	return 0;
+}
+
+
+static int hardware_init(struct ece_softc *sc)
+{
+	int status = 0;
+	static int gw_phy_type;
+
+	gw_phy_type = get_phy_type(sc);
+	if (gw_phy_type != IC_PLUS_PHY) {
+		device_printf(sc->dev, "PHY type is not recognized (%d)\n",
+		       gw_phy_type);
+		return -1;
+	}
+	status = configure_lan_port(sc, gw_phy_type);
+	configure_cpu_port(sc);
+	return 0;
+}
+
+
+static void set_mac_address(struct ece_softc *sc, const char *mac, int mac_len)
+{
+	/* invalid age_field mean erase this entry*/
+	write_arl_table_entry(sc, 0, 1, VLAN0_GROUP_ID,
+			      INVALID_ENTRY, VLAN0_GROUP,
+			      mac);
+	memcpy(my_vlan0_mac, mac, ETHER_ADDR_LEN);
+
+	write_arl_table_entry(sc, 0, 1, VLAN0_GROUP_ID,
+			      STATIC_ENTRY, VLAN0_GROUP,
+			      mac);
+}
+
+
+static void
+ece_set_mac(struct ece_softc *sc, u_char *eaddr)
+{
+	memcpy(my_vlan0_mac, eaddr, ETHER_ADDR_LEN);
+	set_mac_address(sc, eaddr, ETHER_ADDR_LEN);
+}
+
+/* TODO: the device doesn't have MAC,
+ * should read the configuration stored in FLASH
+ */
+static int
+ece_get_mac(struct ece_softc *sc, u_char *eaddr)
+{
+	return (ENXIO);
+}
+
+/*version for one segment only*/
+static void
+ece_intr_rx_locked(struct ece_softc *sc, int count)
+{
+	struct ifnet *ifp = sc->ifp;
+	struct rx_desc_info *rxdesc;
+
+	uint32_t status;
+
+	int fssd_curr;
+	int fssd;
+	int rxcount;
+	int i;
+	int idx;
+	struct mbuf *mb;
+	eth_rx_desc_t *desc;
+
+	fssd_curr = RD4(sc, FS_DESCRIPTOR_POINTER);
+
+	fssd = (fssd_curr - (uint32_t)sc->ring_paddr_rx)>>4;
+
+	desc = sc->rx_desc[sc->last_rx].desc;
+
+	/*prepare to read the data in the ring*/
+	bus_dmamap_sync(sc->dmatag_ring_rx,
+	    sc->dmamap_ring_rx,
+	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+
+	if (fssd > sc->last_rx) {
+		rxcount = fssd - sc->last_rx;
+	} else if (fssd < sc->last_rx) {
+		rxcount = (ECE_MAX_RX_BUFFERS - sc->last_rx) + fssd;
+	} else {
+
+		if (desc->cown == 0) {
+			return;
+		} else {
+			rxcount = ECE_MAX_RX_BUFFERS;
+		}
+	}
+
+
+	for (i= 0; i<rxcount; i++) {
+		/* Get status */
+		status = desc->cown;
+		if (!status) {
+			break;
+		}
+
+		idx = sc->last_rx;
+		rxdesc = &sc->rx_desc[idx];
+		mb = rxdesc->buff;
+
+		if (desc->length < ETHER_MIN_LEN - ETHER_CRC_LEN ||
+		    desc->length > ETHER_MAX_LEN - ETHER_CRC_LEN + ETHER_VLAN_ENCAP_LEN) {
+			ifp->if_ierrors++;
+			desc->cown = 0;
+			desc->length = MCLBYTES - 2;
+			/*process next packet*/
+			continue;
+		}
+
+		if (ece_new_rxbuf(sc, rxdesc)!=0) {
+			ifp->if_iqdrops++;
+			desc->cown = 0;
+			desc->length = MCLBYTES - 2;
+			break;
+		}
+
+		/**
+		 * the device will write to X+2 So we need to adjust
+		 * this after the packet is received.
+		 */
+
+		mb->m_data += 2;
+		mb->m_len = mb->m_pkthdr.len = desc->length;
+
+		mb->m_flags |= M_PKTHDR;
+		mb->m_pkthdr.rcvif = ifp;
+		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
+			/*check for valid checksum*/
+			if ( (!desc->l4f)  && (desc->prot!=3)) {
+				mb->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
+				mb->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+				mb->m_pkthdr.csum_data = 0xffff;
+			}
+		}
+		ECE_RXUNLOCK(sc);
+		(*ifp->if_input)(ifp, mb);
+		ECE_RXLOCK(sc);
+
+
+		desc->cown = 0;
+		desc->length = MCLBYTES-2;
+
+		bus_dmamap_sync(sc->dmatag_ring_rx,
+				sc->dmamap_ring_rx,
+				BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+		if (sc->last_rx==ECE_MAX_RX_BUFFERS-1) {
+			sc->last_rx = 0;
+		} else {
+			sc->last_rx++;
+		}
+		desc = sc->rx_desc[sc->last_rx].desc;
+	}
+
+	/* sync updated flags */
+	bus_dmamap_sync(sc->dmatag_ring_rx,
+	    sc->dmamap_ring_rx,
+	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+	return;
+}
+
+
+static void
+ece_intr_task(void *arg, int pending __unused)
+{
+	struct ece_softc *sc = arg;
+	ECE_RXLOCK(sc);
+	ece_intr_rx_locked(sc, -1);
+	ECE_RXUNLOCK(sc);
+}
+
+
+static void
+ece_intr(void *xsc)
+{
+	struct ece_softc *sc = xsc;
+	struct ifnet *ifp = sc->ifp;
+
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+		WR4(sc, FS_DMA_CONTROL, 0);
+		return;
+	}
+
+	taskqueue_enqueue(sc->sc_tq, &sc->sc_intr_task);
+
+	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+		taskqueue_enqueue(sc->sc_tq, &sc->sc_tx_task);
+}
+
+static void
+ece_intr_status(void *xsc)
+{
+	struct ece_softc *sc = xsc;
+	struct ifnet *ifp = sc->ifp;
+	int stat;
+
+	stat = RD4(sc, INTERRUPT_STATUS);
+
+	WR4(sc, INTERRUPT_STATUS, stat);
+
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
+		if ((stat & ERROR_MASK)!=0)
+			ifp->if_iqdrops++;
+	}
+}
+
+static void
+ece_cleanup_locked(struct ece_softc *sc)
+{
+	eth_tx_desc_t *desc;
+
+	if (sc->tx_cons==sc->tx_prod) return;
+
+	/*prepare to read the ring (owner bit)*/
+	bus_dmamap_sync(sc->dmatag_ring_tx,
+	    sc->dmamap_ring_tx,
+	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+	while (sc->tx_cons!=sc->tx_prod) {
+		desc = sc->tx_desc[sc->tx_cons].desc;
+		if (desc->cown != 0) {
+			struct tx_desc_info *td = &(sc->tx_desc[sc->tx_cons]);
+			/*we are finished with this descriptor*/
+			/*sync*/
+			bus_dmamap_sync(sc->dmatag_data_tx, td->dmamap,
+					BUS_DMASYNC_POSTWRITE);
+			/*and unload, so we can reuse */
+			bus_dmamap_unload(sc->dmatag_data_tx, td->dmamap);
+			m_freem(td->buff);
+			td->buff = 0;
+			sc->tx_cons = (sc->tx_cons + 1) % ECE_MAX_TX_BUFFERS;
+		} else {
+			break;
+		}
+	}
+
+}
+
+static void
+ece_cleanup_task(void *arg, int pending __unused)
+{
+	struct ece_softc *sc = arg;
+	ECE_CLEANUPLOCK(sc);
+	ece_cleanup_locked(sc);
+	ECE_CLEANUPUNLOCK(sc);
+}
+
+
+static void
+ece_intr_tx(void *xsc)
+{
+	struct ece_softc *sc = xsc;
+	struct ifnet *ifp = sc->ifp;
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+		/*this should not happen, stop DMA*/
+		WR4(sc, FS_DMA_CONTROL, 0);
+		return;
+	}
+	taskqueue_enqueue(sc->sc_tq, &sc->sc_cleanup_task);
+}
+
+
+static void
+ece_intr_qf(void *xsc)
+{
+	struct ece_softc *sc = xsc;
+	struct ifnet *ifp = sc->ifp;
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+		/*this should not happen, stop DMA*/
+		WR4(sc, FS_DMA_CONTROL, 0);
+		return;
+	}
+	taskqueue_enqueue(sc->sc_tq, &sc->sc_intr_task);
+	WR4(sc, FS_DMA_CONTROL, 1);
+}
+
+/*
+ * Reset and initialize the chip
+ */
+static void
+eceinit_locked(void *xsc)
+{
+	struct ece_softc *sc = xsc;
+	struct ifnet *ifp = sc->ifp;
+ 	struct mii_data *mii;
+	uint32_t cfg_reg;
+	uint32_t cpu_port_config;
+	uint32_t mac_port_config;
+
+	while (1) {
+		cfg_reg = RD4(sc, BIST_RESULT_TEST_0);
+		if ((cfg_reg & (1<<17)))
+			break;
+		DELAY(100);
+	}
+	/* set to default values */
+	WR4(sc, SWITCH_CONFIG, 0x007AA7A1);
+	WR4(sc, MAC_PORT_0_CONFIG, 0x00423D00);
+	WR4(sc, MAC_PORT_1_CONFIG, 0x00423D80);
+	WR4(sc, CPU_PORT_CONFIG, 0x004C0000);
+
+
+	hardware_init(sc);
+
+	mac_port_config = RD4(sc, MAC_PORT_0_CONFIG);
+	mac_port_config &= (~(0x1 << 18));	/* Enable Port 0 */
+	WR4(sc, MAC_PORT_0_CONFIG, mac_port_config);
+
+
+	cpu_port_config = RD4(sc, CPU_PORT_CONFIG);
+	/* enable CPU */
+	cpu_port_config &= ~(0x1 << 18);
+	WR4(sc, CPU_PORT_CONFIG, cpu_port_config);
+
+
+	/*
+	 * Set 'running' flag, and clear output active flag
+	 * and attempt to start the output
+	 */
+	ifp->if_drv_flags |= IFF_DRV_RUNNING;
+	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+	mii = device_get_softc(sc->miibus);
+	mii_pollstat(mii);
+	/* enable dma */
+	WR4(sc, FS_DMA_CONTROL, 1);
+
+	callout_reset(&sc->tick_ch, hz, ece_tick, sc);
+}
+
+
+static inline int
+ece_encap(struct ece_softc *sc, struct mbuf *m0)
+{
+	struct ifnet *ifp;
+	bus_dma_segment_t segs[MAX_FRAGMENT];
+	bus_dmamap_t mapp;
+	int error;
+	int seg;
+	int nsegs;
+	int desc_no;
+	eth_tx_desc_t *desc = 0;
+
+	int csum_flags;
+
+	ifp = sc->ifp;
+
+	/* Fetch unused map */
+	mapp = sc->tx_desc[sc->tx_prod].dmamap;
+
+	error = bus_dmamap_load_mbuf_sg(sc->dmatag_ring_tx, mapp, m0, segs, &nsegs,
+	    BUS_DMA_NOWAIT);
+
+	if (error != 0) {
+		bus_dmamap_unload(sc->dmatag_ring_tx, mapp);
+		return ((error != 0) ? error : -1);
+	}
+
+
+	desc = &(sc->desc_tx[sc->desc_curr_tx]);
+	sc->tx_desc[sc->tx_prod].desc = desc;
+	sc->tx_desc[sc->tx_prod].buff = m0;
+	desc_no = sc->desc_curr_tx;
+
+	for (seg = 0; seg < nsegs; seg++) {
+
+		if (desc->cown == 0 ) {
+			if_printf(ifp, "ERROR: descriptor is still used\n");
+		}
+
+		desc->length = segs[seg].ds_len;
+		desc->data_ptr = segs[seg].ds_addr;
+
+		if (seg == 0) {
+			desc->fs = 1;
+		} else {
+			desc->fs = 0;
+		}
+		if (seg==nsegs-1) {
+			desc->ls = 1;
+		} else {
+			desc->ls = 0;
+		}
+
+		csum_flags = m0->m_pkthdr.csum_flags;
+
+		desc->fr =  1;
+		desc->pmap =  1;
+		desc->insv =  0;
+		desc->ico = 0;
+		desc->tco = 0;
+		desc->uco = 0;
+		desc->interrupt = 1;
+
+		if (csum_flags & CSUM_IP) {
+			desc->ico = 1;
+			if (csum_flags & CSUM_TCP)
+				desc->tco = 1;
+			if (csum_flags & CSUM_UDP)
+				desc->uco = 1;
+		}
+
+		desc++;
+		sc->desc_curr_tx = (sc->desc_curr_tx+1) % ECE_MAX_TX_BUFFERS;
+		if (sc->desc_curr_tx==0) {
+			desc = (eth_tx_desc_t *)&(sc->desc_tx[0]);
+		}
+	}
+
+	desc = sc->tx_desc[sc->tx_prod].desc;
+
+	sc->tx_prod = (sc->tx_prod+1) % ECE_MAX_TX_BUFFERS;
+
+	/*after all descriptors are set, we set the flag to start the sending process */
+	for (seg = 0; seg < nsegs; seg++) {
+		desc->cown = 0;
+		desc++;
+		desc_no = (desc_no+1) % ECE_MAX_TX_BUFFERS;
+		if (desc_no==0) {
+			desc = (eth_tx_desc_t *)&(sc->desc_tx[0]);
+		}
+
+	}
+
+	bus_dmamap_sync(sc->dmatag_data_tx, mapp,    BUS_DMASYNC_PREWRITE);
+
+	return (0);
+}
+
+
+
+
+/*
+ * dequeu packets and transmit
+ */
+static void
+ecestart_locked(struct ifnet *ifp)
+{
+	struct ece_softc *sc;
+	struct mbuf *m0;
+#if 0
+	struct mbuf *mdef;
+#endif
+	uint32_t queued = 0;
+
+	sc = ifp->if_softc;
+	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+	    IFF_DRV_RUNNING)
+		return;
+
+	bus_dmamap_sync(sc->dmatag_ring_tx,
+	    sc->dmamap_ring_tx,
+	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+	for (;;) {
+		/* Get packet from the queue */
+		IF_DEQUEUE(&ifp->if_snd, m0);
+		if (m0 == NULL)
+			break;
+#if 0
+		if (m0->m_next != NULL) {
+			mdef = m_defrag(m0, M_DONTWAIT);
+			if (mdef) {
+				m0 = mdef;
+			}
+		}
+#endif
+		if (ece_encap(sc, m0)) {
+			IF_PREPEND(&ifp->if_snd, m0);
+			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+			break;
+		}
+		queued++;
+		BPF_MTAP(ifp, m0);
+	}
+	if (queued) {
+		/*sync the ring*/
+		bus_dmamap_sync(sc->dmatag_ring_tx, sc->dmamap_ring_tx,
+				BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+		WR4(sc, TS_DMA_CONTROL, 1);
+	}
+}
+
+static void
+eceinit(void *xsc)
+{
+	struct ece_softc *sc = xsc;
+	ECE_LOCK(sc);
+	eceinit_locked(sc);
+	ECE_UNLOCK(sc);
+}
+
+
+static void
+ece_tx_task(void *arg, int pending __unused)
+{
+	struct ifnet *ifp;
+	ifp = (struct ifnet *)arg;
+	ecestart(ifp);
+}
+
+
+static void
+ecestart(struct ifnet *ifp)
+{
+	struct ece_softc *sc = ifp->if_softc;
+	ECE_TXLOCK(sc);
+	ecestart_locked(ifp);
+	ECE_TXUNLOCK(sc);
+}
+
+/*
+ * Turn off interrupts, and stop the nic.  Can be called with sc->ifp NULL
+ * so be careful.
+ */
+static void
+ecestop(struct ece_softc *sc)
+{
+	struct ifnet *ifp = sc->ifp;
+	uint32_t mac_port_config;
+
+
+	WR4(sc, TS_DMA_CONTROL, 0);
+	WR4(sc, FS_DMA_CONTROL, 0);
+
+	if (ifp) {
+		ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+	}
+
+	callout_stop(&sc->tick_ch);
+
+	/*Disable Port 0 */
+	mac_port_config = RD4(sc, MAC_PORT_0_CONFIG);
+	mac_port_config |= ((0x1 << 18));
+	WR4(sc, MAC_PORT_0_CONFIG, mac_port_config);
+
+	/*Disable Port 1 */
+	mac_port_config = RD4(sc, MAC_PORT_1_CONFIG);
+	mac_port_config |= ((0x1 << 18));
+	WR4(sc, MAC_PORT_1_CONFIG, mac_port_config);
+
+	/* disable all interrupt status sources */
+	WR4(sc, INTERRUPT_MASK, 0x00001FFF);
+
+	/* clear previous interrupt sources */
+	WR4(sc, INTERRUPT_STATUS, 0x00001FFF);
+
+	WR4(sc, SWITCH_CONFIG, initial_switch_config);
+	WR4(sc, CPU_PORT_CONFIG, initial_cpu_config);
+	WR4(sc, MAC_PORT_0_CONFIG, initial_port0_config);
+	WR4(sc, MAC_PORT_1_CONFIG, initial_port1_config);
+
+	clear_mac_entries(sc, 1);
+
+
+}
+
+static void
+ece_restart(struct ece_softc *sc)
+{
+	struct ifnet *ifp = sc->ifp;
+
+	ifp->if_drv_flags |= IFF_DRV_RUNNING;
+	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+	/*enable port 0*/
+	WR4(sc, PORT_0_CONFIG,
+	    RD4(sc, PORT_0_CONFIG) & ~((0x1 << 18)));
+	WR4(sc, INTERRUPT_MASK, 0x00000000);
+	WR4(sc, FS_DMA_CONTROL, 1);
+	callout_reset(&sc->tick_ch, hz, ece_tick, sc);
+}
+
+
+
+static void
+set_filter(struct ece_softc *sc)
+{
+	struct ifnet		*ifp;
+	struct ifmultiaddr	*ifma;
+	uint32_t mac_port_config;
+
+	ifp = sc->ifp;
+
+	clear_mac_entries(sc, 0);
+	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+		mac_port_config = RD4(sc, MAC_PORT_0_CONFIG);
+		mac_port_config &= (~(0x1 << 27));
+		mac_port_config &= (~(0x1 << 26));
+		WR4(sc, MAC_PORT_0_CONFIG, mac_port_config);
+		return;
+	}
+	if_maddr_rlock(ifp);
+	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+		if (ifma->ifma_addr->sa_family != AF_LINK)
+			continue;
+		add_mac_entry(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+	}
+	if_maddr_runlock(ifp);
+}
+
+static int
+eceioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+	struct ece_softc *sc = ifp->if_softc;
+ 	struct mii_data *mii;
+ 	struct ifreq *ifr = (struct ifreq *)data;
+	int mask, error = 0;
+
+	switch (cmd) {
+	case SIOCSIFFLAGS:
+		ECE_LOCK(sc);
+		if ((ifp->if_flags & IFF_UP) == 0 &&
+		    ifp->if_drv_flags & IFF_DRV_RUNNING) {
+			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+			ecestop(sc);
+		} else {
+			/* reinitialize card on any parameter change */
+			if ((ifp->if_flags & IFF_UP) &&
+			    !(ifp->if_drv_flags & IFF_DRV_RUNNING)
+			   ){
+				ece_restart(sc);
+			}
+		}
+		ECE_UNLOCK(sc);
+		break;
+
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		ECE_LOCK(sc);
+		set_filter(sc);
+		ECE_UNLOCK(sc);
+		break;
+
+  	case SIOCSIFMEDIA:
+  	case SIOCGIFMEDIA:
+ 		mii = device_get_softc(sc->miibus);
+ 		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
+  		break;
+	case SIOCSIFCAP:
+		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
+		if (mask & IFCAP_VLAN_MTU) {
+			ECE_LOCK(sc);
+			ECE_UNLOCK(sc);
+		}
+	default:
+		error = ether_ioctl(ifp, cmd, data);
+		break;
+	}
+	return (error);
+}
+
+static void
+ece_child_detached(device_t dev, device_t child)
+{
+	struct ece_softc *sc;
+
+	sc = device_get_softc(dev);
+	if (child == sc->miibus)
+		sc->miibus = NULL;
+}
+
+/*
+ * MII bus support routines.
+ */
+static int
+ece_miibus_readreg(device_t dev, int phy, int reg)
+{
+	struct ece_softc *sc;
+	/*only one phy*/
+	if (phy>0) return 0;
+	sc = device_get_softc(dev);
+	return phy_read(sc, phy, reg);
+}
+
+static int
+ece_miibus_writereg(device_t dev, int phy, int reg, int data)
+{
+	struct ece_softc *sc;
+	sc = device_get_softc(dev);
+	phy_write(sc, phy, reg, data);
+	return 0;
+}
+
+static device_method_t ece_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		ece_probe),
+	DEVMETHOD(device_attach,	ece_attach),
+	DEVMETHOD(device_detach,	ece_detach),
+
+	/* Bus interface */
+	DEVMETHOD(bus_child_detached,	ece_child_detached),
+
+	/* MII interface */
+	DEVMETHOD(miibus_readreg,	ece_miibus_readreg),
+	DEVMETHOD(miibus_writereg,	ece_miibus_writereg),
+
+	{ 0, 0 }
+};
+
+static driver_t ece_driver = {
+	"ece",
+	ece_methods,
+	sizeof(struct ece_softc),
+};
+
+DRIVER_MODULE(ece, econaarm, ece_driver, ece_devclass, 0, 0);
+DRIVER_MODULE(miibus, ece, miibus_driver, miibus_devclass, 0, 0);
+MODULE_DEPEND(ece, miibus, 1, 1, 1);
+MODULE_DEPEND(ece, ether, 1, 1, 1);
Index: sys/arm/econa/if_ecereg.h
===================================================================
--- sys/arm/econa/if_ecereg.h	(revision 0)
+++ sys/arm/econa/if_ecereg.h	(revision 0)
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 2009, Yohanes Nugroho <yohanes@gmail.com>
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/jme/if_jmereg.h,v 1.6 2008/12/04 02:16:53 yongari Exp $
+ */
+
+#ifndef	_IF_ECEREG_H
+#define	_IF_ECEREG_H
+
+#define ETH_CFG 0x08
+#define ETH_CFG_RMII (1 << 15)
+#define PHY_CONTROL 0x00
+#define PORT_0_CONFIG 0x08
+
+#define ARL_TABLE_ACCESS_CONTROL_0 0x050
+#define ARL_TABLE_ACCESS_CONTROL_1 0x054
+#define ARL_TABLE_ACCESS_CONTROL_2 0x058
+
+
+#define PORT0               (1 << 0)    /* bit map : bit 0 */
+#define PORT1               (1 << 1)    /* bit map : bit 1 */
+#define CPU_PORT            (1 << 2)    /* bit map : bit 2 */
+
+
+#define VLAN0_GROUP_ID      (0)
+#define VLAN1_GROUP_ID      (1)
+#define VLAN2_GROUP_ID      (2)
+#define VLAN3_GROUP_ID      (3)
+#define VLAN4_GROUP_ID      (4)
+#define VLAN5_GROUP_ID      (5)
+#define VLAN6_GROUP_ID      (6)
+#define VLAN7_GROUP_ID      (7)
+
+#define PORT0_PVID          (VLAN1_GROUP_ID)
+#define PORT1_PVID          (VLAN2_GROUP_ID)
+#define CPU_PORT_PVID       (VLAN0_GROUP_ID)
+
+#define VLAN0_VID           (0x111)
+#define VLAN1_VID           (0x222)
+#define VLAN2_VID           (0x333)
+#define VLAN3_VID           (0x444)
+#define VLAN4_VID           (0x555)
+#define VLAN5_VID           (0x666)
+#define VLAN6_VID           (0x777)
+#define VLAN7_VID           (0x888)
+
+#define VLAN0_GROUP         (PORT0 | PORT1 | CPU_PORT)
+#define VLAN1_GROUP         (PORT0 | CPU_PORT)
+#define VLAN2_GROUP         (PORT1 | CPU_PORT)
+#define VLAN3_GROUP         (0)
+#define VLAN4_GROUP         (0)
+#define VLAN5_GROUP         (0)
+#define VLAN6_GROUP         (0)
+#define VLAN7_GROUP         (0)
+
+
+
+#define VLAN0_VLAN_TAG      (0)
+#define VLAN1_VLAN_TAG      (0)
+#define VLAN2_VLAN_TAG      (0)
+#define VLAN3_VLAN_TAG      (0)
+#define VLAN4_VLAN_TAG      (0)
+#define VLAN5_VLAN_TAG      (0)
+#define VLAN6_VLAN_TAG      (0)
+#define VLAN7_VLAN_TAG      (0)
+
+#define SWITCH_CONFIG 0x004
+#define MAC_PORT_0_CONFIG 0x008
+#define MAC_PORT_1_CONFIG 0x00C
+#define CPU_PORT_CONFIG 0x010
+#define BIST_RESULT_TEST_0 0x094
+
+#define FS_DMA_CONTROL                0x104
+#define TS_DMA_CONTROL                0x100
+
+#define INTERRUPT_MASK 0x08C
+#define INTERRUPT_STATUS 0x088
+
+#define TS_DESCRIPTOR_POINTER     0x108
+#define TS_DESCRIPTOR_BASE_ADDR   0x110
+#define FS_DESCRIPTOR_POINTER     0x10C
+#define FS_DESCRIPTOR_BASE_ADDR   0x114
+
+
+#define VLAN_VID_0_1      0x060
+#define VLAN_VID_2_3      0x064
+#define VLAN_VID_4_5      0x068
+#define VLAN_VID_6_7      0x06C
+
+#define VLAN_PORT_PVID       0x05C
+#define VLAN_MEMBER_PORT_MAP 0x070
+#define VLAN_TAG_PORT_MAP    0x074
+
+
+#define ASIX_GIGA_PHY   1
+#define TWO_SINGLE_PHY  2
+#define AGERE_GIGA_PHY 3
+#define VSC8601_GIGA_PHY 4
+#define IC_PLUS_PHY	5
+#define NOT_FOUND_PHY -1
+
+#define MAX_PACKET_LEN           (1536)
+
+#define INVALID_ENTRY 0
+#define NEW_ENTRY 0x1
+#define STATIC_ENTRY 0x7
+
+/*mask status except for link change*/
+#define ERROR_MASK 0xFFFFFF7F
+
+
+#endif
Index: sys/arm/econa/cfi_bus_econa.c
===================================================================
--- sys/arm/econa/cfi_bus_econa.c	(revision 0)
+++ sys/arm/econa/cfi_bus_econa.c	(revision 0)
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2009 Yohanes Nugroho
+ * 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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+
+#include <dev/cfi/cfi_var.h>
+
+#include <arm/econa/econa_reg.h>
+#include <arm/econa/econa_var.h>
+
+static int
+cfi_econa_probe(device_t dev)
+{
+	return cfi_probe(dev);
+}
+
+static device_method_t cfi_econa_methods[] = {
+	/* device interface */
+	DEVMETHOD(device_probe,		cfi_econa_probe),
+	DEVMETHOD(device_attach,	cfi_attach),
+	DEVMETHOD(device_detach,	cfi_detach),
+
+	{0, 0}
+};
+
+static driver_t cfi_econa_driver = {
+	cfi_driver_name,
+	cfi_econa_methods,
+	sizeof(struct cfi_softc),
+};
+DRIVER_MODULE(cfi, econaarm, cfi_econa_driver, cfi_devclass, 0, 0);
Index: sys/arm/econa/timer.c
===================================================================
--- sys/arm/econa/timer.c	(revision 0)
+++ sys/arm/econa/timer.c	(revision 0)
@@ -0,0 +1,432 @@
+/*-
+ * Copyright (c) 2009 Yohanes Nugroho.  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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD $");
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <machine/intr.h>
+
+#include "econa_reg.h"
+#include "econa_var.h"
+
+#define INITIAL_TIMECOUNTER	(0xffffffff)
+
+static int timers_initialized = 0;
+
+#define HZ 100
+
+unsigned int CPU_clock = 200000000;
+unsigned int AHB_clock;
+unsigned int APB_clock;
+
+unsigned int get_tclk(void);
+
+static unsigned long timer_counter = 0, sys_clock = 100000000;
+
+struct ec_timer_softc {
+	struct resource	*	timer_res[3];
+	bus_space_tag_t		timer_bst;
+	bus_space_handle_t	timer_bsh;
+	struct mtx		timer_mtx;
+};
+
+
+static struct resource_spec ec_timer_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		1,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+
+static unsigned ec_timer_get_timecount(struct timecounter *);
+
+static struct timecounter ec_timecounter = {
+	.tc_get_timecount = ec_timer_get_timecount,
+	.tc_name = "CPU Timer",
+	.tc_frequency = 0,	/* This is assigned on the fly in the init sequence */
+	.tc_counter_mask = ~0u,
+	.tc_quality = 1000,
+};
+
+
+static struct ec_timer_softc *timer_softc = NULL;
+
+static inline
+void WR4(unsigned int val, unsigned int addr)
+{
+	bus_space_write_4(timer_softc->timer_bst,
+			  timer_softc->timer_bsh, addr, val);
+
+}
+
+static inline
+unsigned int RD4(unsigned int addr)
+{
+	return bus_space_read_4(timer_softc->timer_bst,
+	    timer_softc->timer_bsh, addr);
+}
+
+
+
+#define uSECS_PER_TICK	(1000000 / APB_clock)
+#define TICKS2USECS(x)  ((x) * uSECS_PER_TICK)
+
+
+static unsigned
+read_timer_counter_noint(void)
+{
+	arm_mask_irq(0);
+	unsigned int v = RD4(TIMER_TM1_COUNTER_REG_OFFSET);
+	arm_unmask_irq(0);
+	return v;
+}
+
+void
+DELAY(int usec)
+{
+	uint32_t val, val_temp;
+	int nticks;
+
+	if (!timers_initialized) {
+		for (; usec > 0; usec--)
+			for (val = 100; val > 0; val--)
+				;
+		return;
+	}
+
+	val = read_timer_counter_noint();
+	nticks = (((APB_clock/1000) * usec) / 1000)+100;
+
+	while (nticks > 0) {
+		val_temp = read_timer_counter_noint();
+		if (val > val_temp)
+			nticks -= (val - val_temp);
+		else
+			nticks -= (val + (timer_counter - val_temp));
+
+
+		val = val_temp;
+	}
+
+}
+
+/*
+ * Setup timer
+ */
+static inline void
+setup_timer(unsigned int counter_value)
+{
+	unsigned int control_value;
+	unsigned int mask_value;
+
+	control_value = RD4(TIMER_TM_CR_REG_OFFSET);
+
+	mask_value = RD4(TIMER_TM_INTR_MASK_REG_OFFSET);
+	WR4(counter_value, TIMER_TM1_COUNTER_REG_OFFSET);
+	WR4(counter_value, TIMER_TM1_LOAD_REG_OFFSET);
+	WR4(0, TIMER_TM1_MATCH1_REG_OFFSET);
+	WR4(0,TIMER_TM1_MATCH2_REG_OFFSET);
+
+	control_value &= ~(TIMER1_CLOCK_SOURCE);
+	control_value |= TIMER1_UP_DOWN_COUNT;
+
+	WR4(0, TIMER_TM2_COUNTER_REG_OFFSET);
+	WR4(0, TIMER_TM2_LOAD_REG_OFFSET);
+	WR4(~0u, TIMER_TM2_MATCH1_REG_OFFSET);
+	WR4(~0u,TIMER_TM2_MATCH2_REG_OFFSET);
+
+	control_value &= ~(TIMER2_CLOCK_SOURCE);
+	control_value &= ~(TIMER2_UP_DOWN_COUNT);
+
+	mask_value &= ~(63);
+
+	WR4(control_value, TIMER_TM_CR_REG_OFFSET);
+	WR4(mask_value, TIMER_TM_INTR_MASK_REG_OFFSET);
+}
+
+/*
+ * Enable timer
+ */
+static inline void
+timer_enable(void)
+{
+	unsigned int control_value;
+
+	control_value = RD4(TIMER_TM_CR_REG_OFFSET);
+
+	control_value |= TIMER1_OVERFLOW_ENABLE;
+	control_value |= TIMER1_ENABLE;
+	control_value |= TIMER2_OVERFLOW_ENABLE;
+	control_value |= TIMER2_ENABLE;
+
+	WR4(control_value,  TIMER_TM_CR_REG_OFFSET);
+}
+
+
+static inline unsigned int
+read_second_timer_counter(void)
+{
+	return RD4(TIMER_TM2_COUNTER_REG_OFFSET);
+}
+
+
+/*
+ * Get timer interrupt status
+ */
+static inline unsigned int
+read_timer_interrupt_status(void)
+{
+	return RD4(TIMER_TM_INTR_STATUS_REG_OFFSET);
+}
+
+/*
+ * Clear timer interrupt status
+ */
+static inline void
+clear_timer_interrupt_status(unsigned int irq)
+{
+	unsigned int interrupt_status;
+
+	interrupt_status =   RD4(TIMER_TM_INTR_STATUS_REG_OFFSET);
+	if (irq==0) {
+		if (interrupt_status & (TIMER1_MATCH1_INTR))
+			interrupt_status &= ~(TIMER1_MATCH1_INTR);
+		if (interrupt_status & (TIMER1_MATCH2_INTR))
+			interrupt_status &= ~(TIMER1_MATCH2_INTR);
+		if (interrupt_status & (TIMER1_OVERFLOW_INTR))
+			interrupt_status &= ~(TIMER1_OVERFLOW_INTR);
+	}
+	if (irq==1) {
+
+		if (interrupt_status & (TIMER2_MATCH1_INTR))
+			interrupt_status &= ~(TIMER2_MATCH1_INTR);
+		if (interrupt_status & (TIMER2_MATCH2_INTR))
+			interrupt_status &= ~(TIMER2_MATCH2_INTR);
+		if (interrupt_status & (TIMER2_OVERFLOW_INTR))
+			interrupt_status &= ~(TIMER2_OVERFLOW_INTR);
+	}
+
+	WR4(interrupt_status, TIMER_TM_INTR_STATUS_REG_OFFSET);
+}
+
+static unsigned
+ec_timer_get_timecount(struct timecounter *a)
+{
+	unsigned int ticks1;
+	arm_mask_irq(1);
+	ticks1 = read_second_timer_counter();
+	arm_unmask_irq(1);
+	return ticks1;
+}
+
+/*
+  *  Get STR9100 System Clock
+*/
+static unsigned long
+get_system_clock(void)
+{
+	sys_clock = 100000000;
+
+	switch (((*(unsigned int *)SYSTEM_CLOCK_INFO) >> 6) & 0x3) {
+	case 0:
+		sys_clock = 87500000;
+		CPU_clock = 175000000;
+		break;
+	case 1:
+		sys_clock = 100000000;
+		CPU_clock = 200000000;
+		break;
+	case 2:
+		sys_clock = 112500000;
+		CPU_clock = 225000000;
+		break;
+	case 3:
+		sys_clock = 125000000;
+		CPU_clock = 250000000;
+		break;
+	}
+	AHB_clock = CPU_clock >> 1;
+	APB_clock = AHB_clock >> 1;
+	return sys_clock;
+}
+
+unsigned int
+get_tclk(void)
+{
+	return CPU_clock;
+}
+
+/*
+ * Setup timer
+ */
+static inline void 
+do_setup_timer(void)
+{
+	get_system_clock();
+	timer_counter = APB_clock/HZ;
+	/*
+	 * setup timer-related values
+	 */
+	setup_timer(timer_counter);
+}
+
+void
+cpu_initclocks(void)
+{
+	ec_timecounter.tc_frequency = APB_clock;
+	tc_init(&ec_timecounter);
+	timer_enable();
+	timers_initialized = 1;
+}
+
+void
+cpu_startprofclock(void)
+{
+
+}
+
+void
+cpu_stopprofclock(void)
+{
+
+}
+
+void
+cpu_reset(void)
+{
+	volatile unsigned int * control = (unsigned int * )CPU_RESET_REGISTER;
+	*control |= (1 << 0);
+	*control &= (~(1 << 0));
+	while (1);
+}
+
+static int
+ec_timer_probe(device_t dev)
+{
+	device_set_desc(dev, "Econa CPU Timer");
+	return (0);
+}
+
+static int
+ec_reset(void *arg)
+{
+	arm_mask_irq(1);
+	clear_timer_interrupt_status(1);
+	arm_unmask_irq(1);
+	return (FILTER_HANDLED);
+}
+
+static int
+ec_hardclock(void *arg)
+{
+	struct	trapframe *frame;
+	unsigned int val;
+	/*clear timer interrupt status*/
+
+	arm_mask_irq(0);
+
+	val = RD4(TIMER_INTERRUPT_STATUS_REG);
+	val &= ~(TIMER1_OVERFLOW_INTERRUPT);
+	WR4(val, TIMER_INTERRUPT_STATUS_REG);
+
+	frame = (struct trapframe *)arg;
+	  hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
+
+	arm_unmask_irq(0);
+
+	return (FILTER_HANDLED);
+}
+
+
+static int
+ec_timer_attach(device_t dev)
+{
+	int	error;
+	void	*ihl;
+	struct	ec_timer_softc *sc;
+
+	if (timer_softc != NULL)
+		return (ENXIO);
+
+	sc = (struct ec_timer_softc *)device_get_softc(dev);
+
+	timer_softc = sc;
+
+	error = bus_alloc_resources(dev, ec_timer_spec, sc->timer_res);
+	if (error) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	sc->timer_bst = rman_get_bustag(sc->timer_res[0]);
+	sc->timer_bsh = rman_get_bushandle(sc->timer_res[0]);
+
+	do_setup_timer();
+
+	if (bus_setup_intr(dev, sc->timer_res[1], INTR_TYPE_CLK,
+	    ec_hardclock, NULL, NULL, &ihl) != 0) {
+		bus_release_resources(dev, ec_timer_spec, sc->timer_res);
+		device_printf(dev, "could not setup hardclock interrupt\n");
+		return (ENXIO);
+	}
+
+	if (bus_setup_intr(dev, sc->timer_res[2], INTR_TYPE_CLK,
+	    ec_reset, NULL, NULL, &ihl) != 0) {
+		bus_release_resources(dev, ec_timer_spec, sc->timer_res);
+		device_printf(dev, "could not setup timer interrupt\n");
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+
+static device_method_t ec_timer_methods[] = {
+	DEVMETHOD(device_probe, ec_timer_probe),
+	DEVMETHOD(device_attach, ec_timer_attach),
+	{ 0, 0 }
+};
+
+static driver_t ec_timer_driver = {
+	"timer",
+	ec_timer_methods,
+	sizeof(struct ec_timer_softc),
+};
+
+
+static devclass_t ec_timer_devclass;
+
+DRIVER_MODULE(timer, econaarm, ec_timer_driver, ec_timer_devclass, 0, 0);
Index: sys/arm/econa/econa.c
===================================================================
--- sys/arm/econa/econa.c	(revision 0)
+++ sys/arm/econa/econa.c	(revision 0)
@@ -0,0 +1,656 @@
+/*-
+ * Copyright (c) 2009 Yohanes Nugroho.  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 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 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/types.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+
+#define	_ARM32_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/resource.h>
+
+#include "econa_reg.h"
+#include "econa_var.h"
+
+static struct econa_softc *econa_softc;
+
+bs_protos(generic);
+bs_protos(generic_armv4);
+
+struct bus_space econa_bs_tag = {
+	/* cookie */
+	(void *) 0,
+
+	/* mapping/unmapping */
+	generic_bs_map,
+	generic_bs_unmap,
+	generic_bs_subregion,
+
+	/* allocation/deallocation */
+	generic_bs_alloc,
+	generic_bs_free,
+
+	/* barrier */
+	generic_bs_barrier,
+
+	/* read (single) */
+	generic_bs_r_1,
+	generic_armv4_bs_r_2,
+	generic_bs_r_4,
+	NULL,
+
+	/* read multiple */
+	generic_bs_rm_1,
+	generic_armv4_bs_rm_2,
+	generic_bs_rm_4,
+	NULL,
+
+	/* read region */
+	generic_bs_rr_1,
+	generic_armv4_bs_rr_2,
+	generic_bs_rr_4,
+	NULL,
+
+	/* write (single) */
+	generic_bs_w_1,
+	generic_armv4_bs_w_2,
+	generic_bs_w_4,
+	NULL,
+
+	/* write multiple */
+	generic_bs_wm_1,
+	generic_armv4_bs_wm_2,
+	generic_bs_wm_4,
+	NULL,
+
+	/* write region */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* set multiple */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* set region */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* copy */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* read (single) stream */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* read multiple stream */
+	NULL,
+	generic_armv4_bs_rm_2,
+	NULL,
+	NULL,
+
+	/* read region stream */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* write (single) stream */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* write multiple stream */
+	NULL,
+	generic_armv4_bs_wm_2,
+	NULL,
+	NULL,
+
+	/* write region stream */
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+bus_space_tag_t obio_tag = &econa_bs_tag;
+
+
+static int
+econa_probe(device_t dev)
+{
+	device_set_desc(dev, "ECONA device bus");
+	return (0);
+}
+
+static void
+econa_identify(driver_t *drv, device_t parent)
+{
+	BUS_ADD_CHILD(parent, 0, "econaarm", 0);
+}
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+
+	return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+	return (0);
+}
+
+extern void irq_entry(void);
+
+static void
+econa_add_child(device_t dev, int prio, const char *name, int unit,
+		bus_addr_t addr, bus_size_t size, int irq0, int irq1,
+		int irq2, int irq3, int irq4)
+{
+	device_t kid;
+	struct econa_ivar *ivar;
+
+	kid = device_add_child_ordered(dev, prio, name, unit);
+	if (kid == NULL) {
+	    printf("Can't add child %s%d ordered\n", name, unit);
+	    return;
+	}
+	ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
+	if (ivar == NULL) {
+		device_delete_child(dev, kid);
+		return;
+	}
+	device_set_ivars(kid, ivar);
+	resource_list_init(&ivar->resources);
+	if (irq0 != -1)
+		bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1);
+	if (irq1 != 0)
+		bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1);
+	if (irq2 != 0)
+		bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1);
+	if (irq3 != 0)
+		bus_set_resource(kid, SYS_RES_IRQ, 3, irq3, 1);
+	if (irq4 != 0)
+		bus_set_resource(kid, SYS_RES_IRQ, 4, irq4, 1);
+
+	if (addr != 0)
+		bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size);
+}
+
+struct cpu_devs
+{
+	const char *name;
+	int unit;
+	bus_addr_t mem_base;
+	bus_size_t mem_len;
+	int irq0;
+	int irq1;
+	int irq2;
+	int irq3;
+	int irq4;
+};
+
+
+struct cpu_devs econarm_devs[] =
+{
+	// All the "system" devices
+	{
+		"econa_ic", 0,
+		ECONA_IO_BASE + ECONA_PIC_BASE, ECONA_PIC_SIZE,
+		0	// Interrupt controller has no interrupts!
+	},
+	{
+		"uart", 0,
+		ECONA_IO_BASE + ECONA_UART_BASE, ECONA_UART_SIZE,
+		ECONA_IRQ_UART
+	},
+	{
+		"timer", 0,
+		ECONA_IO_BASE + ECONA_TIMER_BASE, ECONA_TIMER_SIZE,
+		ECONA_IRQ_TIMER_1, ECONA_IRQ_TIMER_2
+	},
+	{
+		"ohci", 0,
+		ECONA_OHCI_VBASE, ECONA_OHCI_SIZE,
+		ECONA_IRQ_OHCI
+		},
+	{
+		"ehci", 0,
+		ECONA_EHCI_VBASE, ECONA_EHCI_SIZE,
+		ECONA_IRQ_EHCI
+	},
+	{
+		"cfi", 0,
+		ECONA_CFI_VBASE, ECONA_CFI_SIZE,
+		0
+	},
+	{
+		"ece", 0,
+		ECONA_NET_VBASE, ECONA_NET_SIZE,
+		ECONA_IRQ_STATUS,
+		ECONA_IRQ_TSTC, ECONA_IRQ_FSRC,
+		ECONA_IRQ_TSQE, ECONA_IRQ_FSQF,
+	},
+	{	0, 0, 0, 0, 0 }
+};
+
+static void
+econa_cpu_add_builtin_children(device_t dev, struct econa_softc *sc)
+{
+	int i;
+	struct cpu_devs *walker;
+
+	for (i = 0, walker = econarm_devs; walker->name; i++, walker++) {
+		econa_add_child(dev, i, walker->name, walker->unit,
+		    walker->mem_base, walker->mem_len, walker->irq0,
+				walker->irq1, walker->irq2, walker->irq3,
+			walker->irq4);
+	}
+
+}
+
+
+struct intc_trigger_t {
+	int mode;
+	int level;
+};
+
+
+static struct intc_trigger_t intc_trigger_table[] = {
+	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
+	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
+	{INTC_EDGE_TRIGGER, INTC_FALLING_EDGE},
+	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
+	{INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN},
+	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_LOW},
+	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_LOW},
+	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
+	{INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN},
+	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
+	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
+	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
+	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
+	{INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN},
+	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
+	{INTC_EDGE_TRIGGER, INTC_FALLING_EDGE},
+	{INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN},
+	{INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN},
+	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
+	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
+	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
+	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
+	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
+	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_LOW},
+	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_LOW},
+};
+
+static inline uint32_t
+RD4(struct econa_softc *sc, bus_size_t off)
+{
+	return bus_space_read_4(sc->sc_st, sc->sc_sys_sh, off);
+}
+
+static inline void
+WR4(struct econa_softc *sc, bus_size_t off, uint32_t val)
+{
+	return bus_space_write_4(sc->sc_st, sc->sc_sys_sh, off, val);
+}
+
+
+static inline void 
+econa_set_irq_mode(struct econa_softc * sc, unsigned int irq, unsigned int mode)
+{
+	unsigned int val;
+
+	if ((mode != INTC_LEVEL_TRIGGER) && (mode != INTC_EDGE_TRIGGER))
+		return;
+
+	val =	RD4(sc, INTC_INTERRUPT_TRIGGER_MODE_REG_OFFSET);
+
+	if (mode == INTC_LEVEL_TRIGGER) {
+		if (val & (1UL << irq)) {
+			val &= ~(1UL << irq);
+			WR4(sc,  INTC_INTERRUPT_TRIGGER_MODE_REG_OFFSET,  val);
+		}
+	} else {
+		if (!(val & (1UL << irq))) {
+			val |= (1UL << irq);
+			WR4(sc, INTC_INTERRUPT_TRIGGER_MODE_REG_OFFSET,  val);
+		}
+	}
+}
+
+
+/*
+ * Configure interrupt trigger level to be Active High/Low
+ * or Rising/Falling Edge
+ */
+static inline void 
+econa_set_irq_level(struct econa_softc * sc,
+		    unsigned int irq, unsigned int level)
+{
+	unsigned int val;
+
+
+	if ((level != INTC_ACTIVE_HIGH) &&
+	    (level != INTC_ACTIVE_LOW) &&
+	    (level != INTC_RISING_EDGE) &&
+	    (level != INTC_FALLING_EDGE)) {
+		return;
+	}
+
+	val = RD4(sc, INTC_INTERRUPT_TRIGGER_LEVEL_REG_OFFSET);
+
+	if ((level == INTC_ACTIVE_HIGH) || (level == INTC_RISING_EDGE)) {
+		if (val & (1UL << irq)) {
+			val &= ~(1UL << irq);
+			WR4(sc, INTC_INTERRUPT_TRIGGER_LEVEL_REG_OFFSET, val);
+		}
+	} else {
+		if (!(val & (1UL << irq))) {
+			val |= (1UL << irq);
+			WR4(sc,  INTC_INTERRUPT_TRIGGER_LEVEL_REG_OFFSET, val);
+		}
+	}
+}
+
+
+
+static int
+econa_attach(device_t dev)
+{
+	struct econa_softc *sc = device_get_softc(dev);
+	int i;
+
+	econa_softc = sc;
+	sc->sc_st = &econa_bs_tag;
+	sc->sc_sh = ECONA_IO_BASE;
+	sc->dev = dev;
+	if (bus_space_subregion(sc->sc_st, sc->sc_sh, ECONA_PIC_BASE,
+	    ECONA_PIC_SIZE, &sc->sc_sys_sh) != 0)
+		panic("Unable to map IRQ registers");
+	sc->sc_irq_rman.rm_type = RMAN_ARRAY;
+	sc->sc_irq_rman.rm_descr = "ECONA IRQs";
+	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
+	sc->sc_mem_rman.rm_descr = "ECONA Memory";
+	if (rman_init(&sc->sc_irq_rman) != 0 ||
+	    rman_manage_region(&sc->sc_irq_rman, 0, 31) != 0)
+		panic("econa_attach: failed to set up IRQ rman");
+	if (rman_init(&sc->sc_mem_rman) != 0 ||
+	    rman_manage_region(&sc->sc_mem_rman, 0,
+	    ~0) != 0)
+		panic("econa_attach: failed to set up memory rman");
+
+	WR4(sc,  INTC_INTERRUPT_CLEAR_EDGE_TRIGGER_REG_OFFSET,  0xffffffff);
+
+	WR4(sc,  INTC_INTERRUPT_MASK_REG_OFFSET,  0xffffffff);
+
+	WR4(sc, INTC_FIQ_MODE_SELECT_REG_OFFSET,  0);
+
+	/*initialize irq*/
+	for (i = 0; i < 32; i++) {
+		if (intc_trigger_table[i].mode != INTC_TRIGGER_UNKNOWN) {
+			econa_set_irq_mode(sc,i, intc_trigger_table[i].mode);
+			econa_set_irq_level(sc, i, intc_trigger_table[i].level);
+		}
+	}
+
+	econa_cpu_add_builtin_children(dev, sc);
+
+	bus_generic_probe(dev);
+	bus_generic_attach(dev);
+	enable_interrupts(I32_bit | F32_bit);
+
+	return (0);
+}
+
+static struct resource *
+econa_alloc_resource(device_t dev, device_t child, int type, int *rid,
+    u_long start, u_long end, u_long count, u_int flags)
+{
+	struct econa_softc *sc = device_get_softc(dev);
+	struct resource_list_entry *rle;
+	struct econa_ivar *ivar = device_get_ivars(child);
+	struct resource_list *rl = &ivar->resources;
+
+
+	if (device_get_parent(child) != dev)
+		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
+					   type, rid, start, end, count, flags));
+
+	rle = resource_list_find(rl, type, *rid);
+	if (rle == NULL) {
+		//printf("resource not found\r\n");
+		return (NULL);
+	}
+	if (rle->res)
+		panic("Resource rid %d type %d already in use", *rid, type);
+	if (start == 0UL && end == ~0UL) {
+		start = rle->start;
+		count = ulmax(count, rle->count);
+		end = ulmax(rle->end, start + count - 1);
+		/*printf("econa_alloc_resource start %08lx end %08lx, count = %08lx \r\n",
+		  start, end, count);*/
+
+	}
+	switch (type)
+	{
+	case SYS_RES_IRQ:
+		rle->res = rman_reserve_resource(&sc->sc_irq_rman,
+		    start, end, count, flags, child);
+		break;
+	case SYS_RES_MEMORY:
+		rle->res = rman_reserve_resource(&sc->sc_mem_rman,
+		    start, end, count, flags, child);
+		if (rle->res != NULL) {
+			rman_set_bustag(rle->res, &econa_bs_tag);
+			rman_set_bushandle(rle->res, start);
+		}
+		break;
+	}
+	if (rle->res) {
+		rle->start = rman_get_start(rle->res);
+		rle->end = rman_get_end(rle->res);
+		rle->count = count;
+		rman_set_rid(rle->res, *rid);
+	}
+	return (rle->res);
+}
+
+static struct resource_list *
+econa_get_resource_list(device_t dev, device_t child)
+{
+	struct econa_ivar *ivar;
+	ivar = device_get_ivars(child);
+	return (&(ivar->resources));
+}
+
+static int
+econa_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 = econa_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
+econa_setup_intr(device_t dev, device_t child,
+    struct resource *ires, int flags, driver_filter_t *filt,
+    driver_intr_t *intr, void *arg, void **cookiep)
+{
+	if (rman_get_start(ires) == ECONA_IRQ_SYSTEM && filt == NULL)
+		panic("All system interrupt ISRs must be FILTER");
+
+	BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt,
+	    intr, arg, cookiep);
+
+	arm_unmask_irq(rman_get_start(ires));
+
+	return (0);
+}
+
+static int
+econa_teardown_intr(device_t dev, device_t child, struct resource *res,
+    void *cookie)
+{
+	return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
+}
+
+static int
+econa_activate_resource(device_t bus, device_t child, int type, int rid,
+    struct resource *r)
+{
+	return (rman_activate_resource(r));
+}
+
+static int
+econa_print_child(device_t dev, device_t child)
+{
+	struct econa_ivar *ivars;
+	struct resource_list *rl;
+	int retval = 0;
+
+	ivars = device_get_ivars(child);
+	rl = &ivars->resources;
+
+	retval += bus_print_child_header(dev, child);
+
+	retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
+	retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
+	retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+	if (device_get_flags(dev))
+		retval += printf(" flags %#x", device_get_flags(dev));
+
+	retval += bus_print_child_footer(dev, child);
+
+	return (retval);
+}
+
+void
+arm_mask_irq(uintptr_t nb)
+{
+	unsigned int value;
+
+	value = RD4(econa_softc,INTC_INTERRUPT_MASK_REG_OFFSET) | 1<<nb;
+	WR4(econa_softc, INTC_INTERRUPT_MASK_REG_OFFSET, value);
+}
+
+
+void
+arm_unmask_irq(uintptr_t nb)
+{
+	unsigned int value;
+
+	value =	RD4(econa_softc,
+		    INTC_INTERRUPT_CLEAR_EDGE_TRIGGER_REG_OFFSET) | (1 << nb);
+
+	WR4(econa_softc,  
+	    INTC_INTERRUPT_CLEAR_EDGE_TRIGGER_REG_OFFSET,  value);
+
+	value =	RD4(econa_softc, INTC_INTERRUPT_MASK_REG_OFFSET)& ~(1 << nb);
+
+	WR4(econa_softc,  INTC_INTERRUPT_MASK_REG_OFFSET, value);
+
+}
+
+
+int
+arm_get_next_irq(int x)
+{
+
+	int irq;
+
+	irq = RD4(econa_softc, INTC_INTERRUPT_STATUS_REG_OFFSET) &
+		~(RD4(econa_softc,  INTC_INTERRUPT_MASK_REG_OFFSET));
+
+	if (irq!=0) {
+		return (ffs(irq) - 1);
+	}
+
+	return (-1);
+}
+
+static device_method_t econa_methods[] = {
+	DEVMETHOD(device_probe, econa_probe),
+	DEVMETHOD(device_attach, econa_attach),
+	DEVMETHOD(device_identify, econa_identify),
+	DEVMETHOD(bus_alloc_resource, econa_alloc_resource),
+	DEVMETHOD(bus_setup_intr, econa_setup_intr),
+	DEVMETHOD(bus_teardown_intr, econa_teardown_intr),
+	DEVMETHOD(bus_activate_resource, econa_activate_resource),
+	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+	DEVMETHOD(bus_get_resource_list,econa_get_resource_list),
+	DEVMETHOD(bus_set_resource,	bus_generic_rl_set_resource),
+	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
+	DEVMETHOD(bus_release_resource,	econa_release_resource),
+	DEVMETHOD(bus_print_child,	econa_print_child),
+	{0, 0},
+};
+
+static driver_t econa_driver = {
+	"econaarm",
+	econa_methods,
+	sizeof(struct econa_softc),
+};
+static devclass_t econa_devclass;
+
+DRIVER_MODULE(econaarm, nexus, econa_driver, econa_devclass, 0, 0);
Index: sys/arm/econa/ehci_ebus.c
===================================================================
--- sys/arm/econa/ehci_ebus.c	(revision 0)
+++ sys/arm/econa/ehci_ebus.c	(revision 0)
@@ -0,0 +1,313 @@
+/*-
+ * Copyright (C) 2009 Yohanes Nugroho
+ * based on ehci_mbus.c 
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_bus.h"
+
+#include <machine/resource.h>
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/linker_set.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <sys/rman.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_util.h>
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/controller/ehci.h>
+#include <dev/usb/controller/ehcireg.h>
+
+
+static device_attach_t ehci_ebus_attach;
+static device_detach_t ehci_ebus_detach;
+static device_shutdown_t ehci_ebus_shutdown;
+static device_suspend_t ehci_ebus_suspend;
+static device_resume_t ehci_ebus_resume;
+
+
+static void *ih_err;
+
+#define	USB_BRIDGE_INTR_CAUSE  0x210
+#define	USB_BRIDGE_INTR_MASK   0x214
+
+#define EHCI_HC_DEVSTR "CNS11XX USB EHCI"
+
+
+static int
+ehci_ebus_suspend(device_t self)
+{
+	ehci_softc_t *sc = device_get_softc(self);
+	int err;
+
+	err = bus_generic_suspend(self);
+	if (err)
+		return (err);
+	ehci_suspend(sc);
+	return (0);
+}
+
+static int
+ehci_ebus_resume(device_t self)
+{
+	ehci_softc_t *sc = device_get_softc(self);
+
+	ehci_resume(sc);
+
+	bus_generic_resume(self);
+
+	return (0);
+}
+
+static int
+ehci_ebus_shutdown(device_t self)
+{
+	ehci_softc_t *sc = device_get_softc(self);
+	int err;
+
+	err = bus_generic_shutdown(self);
+	if (err)
+		return (err);
+	ehci_shutdown(sc);
+
+	return (0);
+}
+
+static int
+ehci_ebus_probe(device_t self)
+{
+
+	device_set_desc(self, EHCI_HC_DEVSTR);
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+ehci_ebus_attach(device_t self)
+{
+	ehci_softc_t *sc = device_get_softc(self);
+	bus_space_handle_t bsh;
+	int err;
+	int rid;
+
+	/* initialise some bus fields */
+	sc->sc_bus.parent = self;
+	sc->sc_bus.devices = sc->sc_devices;
+	sc->sc_bus.devices_max = EHCI_MAX_DEVICES;
+
+	/* get all DMA memory */
+	if (usb_bus_mem_alloc_all(&sc->sc_bus,
+	    USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) {
+		return (ENOMEM);
+	}
+
+	sc->sc_bus.usbrev = USB_REV_2_0;
+
+	rid = 0;
+	sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+	if (!sc->sc_io_res) {
+		device_printf(self, "Could not map memory\n");
+		goto error;
+	}
+	sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
+	bsh = rman_get_bushandle(sc->sc_io_res);
+
+	bus_space_write_4(
+		(sc)->sc_io_tag, bsh,
+		0x04, 0x106);
+
+	bus_space_write_4(
+		(sc)->sc_io_tag, bsh,
+		0x40, (3 << 5)|0x2000);
+
+
+	DELAY(1000);
+	
+
+	//sc->sc_io_size = 0x4000000;
+
+	sc->sc_io_size =  4096;
+
+	if (bus_space_subregion(sc->sc_io_tag, bsh, 0x4000000,
+	    sc->sc_io_size, &sc->sc_io_hdl) != 0)
+		panic("%s: unable to subregion USB host registers",
+		    device_get_name(self));
+
+
+
+	rid = 0;
+	sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
+	    RF_SHAREABLE | RF_ACTIVE);
+	if (sc->sc_irq_res == NULL) {
+		device_printf(self, "Could not allocate irq\n");
+		ehci_ebus_detach(self);
+		return (ENXIO);
+	}
+
+
+	sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
+	if (!sc->sc_bus.bdev) {
+		device_printf(self, "Could not add USB device\n");
+		goto error;
+	}
+	device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
+	device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR);
+
+ 	sprintf(sc->sc_vendor, "Cavium");
+
+
+	err = bus_setup_intr(self,sc->sc_irq_res,  INTR_TYPE_BIO | INTR_MPSAFE,
+	    NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
+	if (err) {
+		device_printf(self, "Could not setup error irq, %d\n", err);
+		ih_err = NULL;
+		goto error;
+	}
+
+
+	err = ehci_init(sc);
+	if (!err) {
+		err = device_probe_and_attach(sc->sc_bus.bdev);
+	}
+	if (err) {
+		device_printf(self, "USB init failed err=%d\n", err);
+		goto error;
+	}
+	return (0);
+
+error:
+	ehci_ebus_detach(self);
+	return (ENXIO);
+}
+
+static int
+ehci_ebus_detach(device_t self)
+{
+	ehci_softc_t *sc = device_get_softc(self);
+	device_t bdev;
+	int err;       
+
+ 	if (sc->sc_bus.bdev) {
+		bdev = sc->sc_bus.bdev;
+		device_detach(bdev);
+		device_delete_child(self, bdev);
+	}
+	/* during module unload there are lots of children leftover */
+	device_delete_all_children(self);
+
+	/*
+	 * disable interrupts that might have been switched on in ehci_init
+	 */
+	if (sc->sc_io_res) {
+		EWRITE4(sc, EHCI_USBINTR, 0);
+		EWRITE4(sc, USB_BRIDGE_INTR_MASK, 0);
+	}
+ 	if (sc->sc_irq_res && sc->sc_intr_hdl) {
+		/*
+		 * only call ehci_detach() after ehci_init()
+		 */
+		ehci_detach(sc);
+
+		err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl);
+
+		if (err)
+			/* XXX or should we panic? */
+			device_printf(self, "Could not tear down irq, %d\n",
+			    err);
+		sc->sc_intr_hdl = NULL;
+	}
+ 	if (sc->sc_irq_res) {
+		bus_release_resource(self, SYS_RES_IRQ, 1, sc->sc_irq_res);
+		sc->sc_irq_res = NULL;
+	}
+	if (sc->sc_io_res) {
+		bus_release_resource(self, SYS_RES_MEMORY, 0,
+		    sc->sc_io_res);
+		sc->sc_io_res = NULL;
+	}
+	usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
+
+	return (0);
+}
+
+
+static device_method_t ehci_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe, ehci_ebus_probe),
+	DEVMETHOD(device_attach, ehci_ebus_attach),
+	DEVMETHOD(device_detach, ehci_ebus_detach),
+	DEVMETHOD(device_suspend, ehci_ebus_suspend),
+	DEVMETHOD(device_resume, ehci_ebus_resume),
+	DEVMETHOD(device_shutdown, ehci_ebus_shutdown),
+
+	/* Bus interface */
+	DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+	{0, 0}
+};
+
+static driver_t ehci_driver = {
+	"ehci",
+	ehci_methods,
+	sizeof(ehci_softc_t),
+};
+
+static devclass_t ehci_devclass;
+
+DRIVER_MODULE(ehci, econaarm, ehci_driver, ehci_devclass, 0, 0);
+MODULE_DEPEND(ehci, usb, 1, 1, 1);
Index: sys/arm/econa/econa_reg.h
===================================================================
--- sys/arm/econa/econa_reg.h	(revision 0)
+++ sys/arm/econa/econa_reg.h	(revision 0)
@@ -0,0 +1,172 @@
+/*-
+ * Copyright (c) 2009 Yohanes Nugroho  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 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 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 _ARM_ECONA_REG_H
+#define _ARM_ECONA_REG_H
+
+#define ECONA_SRAM_SIZE	0x10000000
+#define ECONA_DRAM_BASE	0x00000000 /* DRAM (via DDR Control Module) */
+
+#define ECONA_IO_BASE 0x70000000
+#define ECONA_PIC_BASE  0x0D000000
+#define ECONA_PIC_SIZE  0x01000000
+
+#define ECONA_UART_BASE 0x08000000
+#define ECONA_UART_SIZE 0x01000000
+#define ECONA_IRQ_UART 0xA
+
+#define ECONA_TIMER_BASE 0x09000000
+#define ECONA_TIMER_SIZE 0x01000000
+#define ECONA_IRQ_TIMER_1 0
+#define ECONA_IRQ_TIMER_2 1
+#define ECONA_IRQ_EHCI 24
+#define ECONA_IRQ_OHCI 23
+
+#define ECONA_NET_PBASE 0x70000000
+#define ECONA_NET_VBASE 0xE0000000
+#define ECONA_NET_SIZE 0x1000000
+
+
+#define ECONA_CFI_PBASE 0x10000000
+#define ECONA_CFI_VBASE 0xD0000000
+#define ECONA_CFI_SIZE 0x10000000
+
+
+#define	ECONA_IRQ_STATUS 18
+#define	ECONA_IRQ_TSTC 19
+#define ECONA_IRQ_FSRC 20
+#define ECONA_IRQ_TSQE 21
+#define ECONA_IRQ_FSQF 22
+
+
+#define ECONA_IRQ_SYSTEM 0
+
+#define ECONA_EHCI_PBASE 0xC8000000
+#define ECONA_EHCI_VBASE 0xF8000000
+#define ECONA_EHCI_SIZE 0x8000000
+
+#define ECONA_OHCI_PBASE 0xC0000000
+#define ECONA_OHCI_VBASE 0xF0000000
+#define ECONA_OHCI_SIZE 0x8000000
+
+#define ECONA_USB_SIZE 0xf000000
+
+/*IC*/
+
+#define INTC_LEVEL_TRIGGER                  0
+#define INTC_EDGE_TRIGGER                   1
+#define INTC_ACTIVE_HIGH                    0
+#define INTC_ACTIVE_LOW                     1
+/*
+ * define rising/falling edge for edge trigger mode
+ */
+#define INTC_RISING_EDGE                    0
+#define INTC_FALLING_EDGE                   1
+
+#define INTC_INTERRUPT_SOURCE_REG_OFFSET             0x00
+#define INTC_INTERRUPT_MASK_REG_OFFSET               0x04
+#define INTC_INTERRUPT_CLEAR_EDGE_TRIGGER_REG_OFFSET 0x08
+#define INTC_INTERRUPT_TRIGGER_MODE_REG_OFFSET       0x0C
+#define INTC_INTERRUPT_TRIGGER_LEVEL_REG_OFFSET      0x10
+#define INTC_INTERRUPT_STATUS_REG_OFFSET             0x14
+#define INTC_FIQ_MODE_SELECT_REG_OFFSET              0x18
+#define INTC_SOFTWARE_INTERRUPT_REG_OFFSET           0x1C
+
+
+/*
+ * define rising/falling edge for edge trigger mode
+ */
+#define INTC_RISING_EDGE                    0
+#define INTC_FALLING_EDGE                   1
+
+
+#define TIMER_TM1_COUNTER_REG_OFFSET    0x00
+#define TIMER_TM1_LOAD_REG_OFFSET       0x04
+#define TIMER_TM1_MATCH1_REG_OFFSET     0x08
+#define TIMER_TM1_MATCH2_REG_OFFSET     0x0C
+
+#define TIMER_TM2_COUNTER_REG_OFFSET    0x10
+#define TIMER_TM2_LOAD_REG_OFFSET       0x14
+#define TIMER_TM2_MATCH1_REG_OFFSET     0x18
+#define TIMER_TM2_MATCH2_REG_OFFSET     0x1C
+
+#define TIMER_TM_CR_REG_OFFSET          0x30
+#define TIMER_TM_INTR_STATUS_REG_OFFSET 0x34
+#define TIMER_TM_INTR_MASK_REG_OFFSET   0x38
+
+#define TIMER_TM_REVISION_REG_OFFSET    0x3C
+
+
+#define INTC_TIMER1_BIT_INDEX               0
+
+#define TIMER1_UP_DOWN_COUNT      (1<<9)
+#define TIMER2_UP_DOWN_COUNT      (1<<10)
+
+#define TIMER1_MATCH1_INTR        (1<<0)
+#define TIMER1_MATCH2_INTR        (1<<1)
+#define TIMER1_OVERFLOW_INTR      (1<<2)
+
+
+#define TIMER2_MATCH1_INTR        (1<<3)
+#define TIMER2_MATCH2_INTR        (1<<4)
+#define TIMER2_OVERFLOW_INTR      (1<<5)
+
+
+#define TIMER_CLOCK_SOURCE_PCLK             0
+#define TIMER_CLOCK_SOURCE_EXT_CLK          1
+
+/*
+ * define interrupt trigger mode
+ */
+#define INTC_LEVEL_TRIGGER                  0
+#define INTC_EDGE_TRIGGER                   1
+
+
+#define INTC_TRIGGER_UNKNOWN -1
+
+#define	TIMER1_OVERFLOW_INTERRUPT	(1<<2)
+#define	TIMER2_OVERFLOW_INTERRUPT	(1<<5)
+#define	TIMER_INTERRUPT_STATUS_REG		0x34
+
+
+#define TIMER1_ENABLE   (1<<0)
+#define TIMER1_CLOCK_SOURCE       (1<<1)
+#define TIMER1_OVERFLOW_ENABLE    (1<<2)
+
+
+#define TIMER2_ENABLE             (1<<3)
+#define TIMER2_CLOCK_SOURCE       (1<<4)
+#define TIMER2_OVERFLOW_ENABLE    (1<<5)
+
+
+#define TIMER_1                             1
+
+#define EC_UART_CLOCK 14769200
+#define EC_UART_REGSHIFT 2
+
+#define SYSTEM_CLOCK_INFO (0x77000014)
+#define CPU_RESET_REGISTER (0x77000014)
+
+
+#endif
Index: sys/arm/econa/if_ecevar.h
===================================================================
--- sys/arm/econa/if_ecevar.h	(revision 0)
+++ sys/arm/econa/if_ecevar.h	(revision 0)
@@ -0,0 +1,196 @@
+/*-
+ * Copyright (c) 2009 Yohanes Nugroho  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 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 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 _IFECEVAR_H
+#define _IFECEVAR_H
+
+#define ECE_MAX_TX_BUFFERS 128
+#define ECE_MAX_RX_BUFFERS 128
+#define MAX_FRAGMENT 32
+
+typedef struct {
+	/* 1st 32Bits */
+	uint32_t		data_ptr;
+	/* 2nd	32Bits*/
+	uint32_t		length:16;
+
+	uint32_t		tco:1; /*tcp checksum offload*/
+	uint32_t		uco:1; /*udp checksum offload*/
+	uint32_t		ico:1; /*ip checksum offload*/
+	/* force_route_port_map*/
+	uint32_t		pmap:3;
+	/* force_route */
+	uint32_t		fr:1;
+	/* force_priority_value */
+	uint32_t		pri:3;
+	/* force_priority */
+	uint32_t		fp:1;
+	/*interrupt_bit*/
+	uint32_t		interrupt:1;
+	/*last_seg*/
+	uint32_t		ls:1;
+	/*first_seg*/
+	uint32_t		fs:1;
+	/* end_bit */
+	uint32_t		eor:1;
+	/* c_bit */
+	uint32_t		cown:1;
+	/* 3rd 32Bits*/
+	/*vid_index*/
+	uint32_t		vid:3;
+	/*insert_vid_tag*/
+	uint32_t		insv:1;
+	/*pppoe_section_index*/
+	uint32_t		sid:3;
+	/*insert_pppoe_section*/
+	uint32_t		inss:1;
+	uint32_t		unused:24;
+	/* 4th 32Bits*/
+	uint32_t		unused2;
+
+} eth_tx_desc_t;
+
+typedef struct{
+	uint32_t		data_ptr;
+	uint32_t		length:16;
+	uint32_t		l4f:1;
+	uint32_t		ipf:1;
+	uint32_t		prot:2;
+	uint32_t		hr:6;
+	uint32_t		sp:2;
+	uint32_t		ls:1;
+	uint32_t		fs:1;
+	uint32_t		eor:1;
+	uint32_t		cown:1;
+	uint32_t		unused;
+	uint32_t		unused2;
+} eth_rx_desc_t;
+
+
+struct rx_desc_info {
+	struct mbuf*buff;
+	bus_dmamap_t dmamap;
+	eth_rx_desc_t *desc;
+};
+
+struct tx_desc_info {
+	struct mbuf*buff;
+	bus_dmamap_t dmamap;
+	eth_tx_desc_t *desc;
+};
+
+
+struct ece_softc
+{
+	struct ifnet *ifp;		/* ifnet pointer */
+	struct mtx sc_mtx;		/* global mutex */
+	struct mtx sc_mtx_tx;		/* tx mutex */
+	struct mtx sc_mtx_rx;		/* rx mutex */
+	struct mtx sc_mtx_cleanup;	/* rx mutex */
+
+	bus_dma_tag_t	sc_parent_tag;	/* parent bus DMA tag */
+
+	device_t dev;			/* Myself */
+	device_t miibus;		/* My child miibus */
+	void *intrhand;			/* Interrupt handle */
+	void *intrhand_qf;			/* Interrupt handle: queue full */
+	void *intrhand_tx;			/* Interrupt handle: queue full */
+	void *intrhand_status;			/* Interrupt handle */
+
+	struct resource *irq_res_tx;	/* transmit */
+	struct resource *irq_res_rec;	/* receive */
+	struct resource *irq_res_qf;	/* queue full */
+	struct resource *irq_res_status;	/* status */
+
+	struct resource	*mem_res;	/* Memory resource */
+
+	struct callout tick_ch;		/* Tick callout */
+
+	int use_rmii;
+
+	struct taskqueue *sc_tq;
+	struct task	sc_intr_task;
+	struct task	sc_cleanup_task;
+	struct task	sc_tx_task;
+
+
+	bus_dmamap_t	dmamap_ring_tx;
+	bus_dmamap_t	dmamap_ring_rx;
+	bus_dmamap_t	rx_sparemap;
+
+	/*dma tag for ring*/
+	bus_dma_tag_t	dmatag_ring_tx;
+	bus_dma_tag_t	dmatag_ring_rx;
+
+	/*dma tag for data*/
+	bus_dma_tag_t	dmatag_data_tx;
+	bus_dma_tag_t	dmatag_data_rx;
+
+	/*the ring*/
+	eth_tx_desc_t*	desc_tx;
+	eth_rx_desc_t*	desc_rx;
+
+	/*ring physical address*/
+	bus_addr_t	ring_paddr_tx;
+	bus_addr_t	ring_paddr_rx;
+
+	/*index of last received descritor*/
+	uint32_t last_rx;
+	struct rx_desc_info rx_desc[ECE_MAX_RX_BUFFERS];
+
+
+	/* tx producer index */
+	uint32_t tx_prod;
+	/* tx consumer index */
+	uint32_t tx_cons;
+	/* tx ring index*/
+	uint32_t desc_curr_tx;
+
+	struct tx_desc_info tx_desc[ECE_MAX_TX_BUFFERS];
+
+};
+
+
+struct arl_table_entry_t {
+	uint32_t cmd_complete: 1;
+	uint32_t table_end: 1;
+	uint32_t search_match: 1;
+	uint32_t filter:1; /*if set, packet will be dropped */
+	uint32_t vlan_mac:1; /*indicates that this is the gateway mac address*/
+	uint32_t vlan_gid:3; /*vlan id*/
+	uint32_t age_field:3;
+	uint32_t port_map:3;
+	 /*48 bit mac address*/
+	uint8_t mac_addr[6];
+	uint8_t pad[2];
+};
+
+struct mac_list{
+	char mac_addr[6];
+	struct mac_list *next;
+};
+
+
+#endif
Index: sys/arm/econa/ohci_ec.c
===================================================================
--- sys/arm/econa/ohci_ec.c	(revision 0)
+++ sys/arm/econa/ohci_ec.c	(revision 0)
@@ -0,0 +1,242 @@
+/*-
+ * Copyright (c) 2009 Yohanes Nugroho
+ *
+ * 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 <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/linker_set.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_util.h>
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/controller/ohci.h>
+#include <dev/usb/controller/ohcireg.h>
+
+#include <sys/rman.h>
+
+#include <arm/econa/econa_reg.h>
+
+#define	MEM_RID	0
+
+static device_probe_t ohci_ec_probe;
+static device_attach_t ohci_ec_attach;
+static device_detach_t ohci_ec_detach;
+
+struct ec_ohci_softc {
+	struct ohci_softc sc_ohci;	/* must be first */
+};
+
+static int
+ohci_ec_probe(device_t dev)
+{
+	device_set_desc(dev, "Econa integrated OHCI controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+ohci_ec_attach(device_t dev)
+{
+	struct ec_ohci_softc *sc = device_get_softc(dev);
+	bus_space_handle_t bsh;
+	int err;
+	int rid;
+
+	/* initialise some bus fields */
+	sc->sc_ohci.sc_bus.parent = dev;
+	sc->sc_ohci.sc_bus.devices = sc->sc_ohci.sc_devices;
+	sc->sc_ohci.sc_bus.devices_max = OHCI_MAX_DEVICES;
+
+	/* get all DMA memory */
+	if (usb_bus_mem_alloc_all(&sc->sc_ohci.sc_bus,
+	    USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) {
+		return (ENOMEM);
+	}
+	sc->sc_ohci.sc_dev = dev;
+
+	rid = MEM_RID;
+
+	sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+	    &rid, RF_ACTIVE);
+
+	if (!(sc->sc_ohci.sc_io_res)) {
+		err = ENOMEM;
+		goto error;
+	}
+	sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res);
+	bsh = rman_get_bushandle(sc->sc_ohci.sc_io_res);
+
+
+
+	bus_space_write_4(
+		(sc)->sc_ohci.sc_io_tag, bsh,
+		0x04, 0x146);
+
+	bus_space_write_4(
+		(sc)->sc_ohci.sc_io_tag, bsh,
+		0x44, 0x0200);
+
+	DELAY(1000);
+
+
+	sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res);
+
+
+	if (bus_space_subregion(sc->sc_ohci.sc_io_tag, bsh, 0x4000000,
+	    sc->sc_ohci.sc_io_size, &sc->sc_ohci.sc_io_hdl) != 0)
+		panic("%s: unable to subregion USB host registers",
+		    device_get_name(dev));
+
+
+	rid = 0;
+	sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (!(sc->sc_ohci.sc_irq_res)) {
+		goto error;
+	}
+	sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1);
+	if (!(sc->sc_ohci.sc_bus.bdev)) {
+		goto error;
+	}
+	device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus);
+
+	strlcpy(sc->sc_ohci.sc_vendor, "Cavium", sizeof(sc->sc_ohci.sc_vendor));
+
+#if (__FreeBSD_version >= 700031)
+	err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
+	    NULL, (driver_intr_t *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl);
+#else
+	err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
+	    (driver_intr_t *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl);
+#endif
+	if (err) {
+		sc->sc_ohci.sc_intr_hdl = NULL;
+		goto error;
+	}
+
+	bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl,
+	    OHCI_CONTROL, 0);
+
+	err = ohci_init(&sc->sc_ohci);
+	if (!err) {
+		err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev);
+	}
+	if (err) {
+		goto error;
+	}
+	return (0);
+
+error:
+	ohci_ec_detach(dev);
+	return (ENXIO);
+}
+
+static int
+ohci_ec_detach(device_t dev)
+{
+	struct ec_ohci_softc *sc = device_get_softc(dev);
+	device_t bdev;
+	int err;
+
+	if (sc->sc_ohci.sc_bus.bdev) {
+		bdev = sc->sc_ohci.sc_bus.bdev;
+		device_detach(bdev);
+		device_delete_child(dev, bdev);
+	}
+	/* during module unload there are lots of children leftover */
+	device_delete_all_children(dev);
+
+	bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl,
+	    OHCI_CONTROL, 0);
+
+	if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) {
+		/*
+		 * only call ohci_detach() after ohci_init()
+		 */
+		ohci_detach(&sc->sc_ohci);
+
+		err = bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl);
+		sc->sc_ohci.sc_intr_hdl = NULL;
+	}
+	if (sc->sc_ohci.sc_irq_res) {
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res);
+		sc->sc_ohci.sc_irq_res = NULL;
+	}
+	if (sc->sc_ohci.sc_io_res) {
+		bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID,
+		    sc->sc_ohci.sc_io_res);
+		sc->sc_ohci.sc_io_res = NULL;
+	}
+	usb_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc);
+
+	return (0);
+}
+
+static device_method_t ohci_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe, ohci_ec_probe),
+	DEVMETHOD(device_attach, ohci_ec_attach),
+	DEVMETHOD(device_detach, ohci_ec_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 ec_ohci_softc),
+};
+
+static devclass_t ohci_devclass;
+
+DRIVER_MODULE(ohci, econaarm, ohci_driver, ohci_devclass, 0, 0);
+MODULE_DEPEND(ohci, usb, 1, 1, 1);
Index: sys/arm/econa/uart_cpu_ec.c
===================================================================
--- sys/arm/econa/uart_cpu_ec.c	(revision 0)
+++ sys/arm/econa/uart_cpu_ec.c	(revision 0)
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (C) 2009 Yohanes Nugroho
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * 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. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY 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 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 <sys/cons.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <sys/rman.h>
+
+#include <arm/econa/econa_reg.h>
+#include <arm/econa/econa_var.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)
+{
+	struct uart_class *class = &uart_ns8250_class;
+
+	di->ops = uart_getops(class);
+	di->bas.chan = 0;
+	di->bas.bst = obio_tag;
+
+	if (bus_space_map(di->bas.bst, ECONA_IO_BASE + ECONA_UART_BASE,
+			  ECONA_UART_SIZE,
+			  0, &di->bas.bsh) != 0) {
+		return (ENXIO);
+	}
+
+	di->baudrate = 0;
+	di->bas.regshft = EC_UART_REGSHIFT;
+	di->bas.rclk = EC_UART_CLOCK ;
+	di->databits = 8;
+	di->stopbits = 1;
+	di->parity = UART_PARITY_NONE;
+	uart_bus_space_mem = obio_tag;
+	uart_bus_space_io = NULL;
+
+	return (0);
+}
Index: sys/arm/econa/uart_bus_ec.c
===================================================================
--- sys/arm/econa/uart_bus_ec.c	(revision 0)
+++ sys/arm/econa/uart_bus_ec.c	(revision 0)
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (C) 2009 Yohanes Nugroho
+ * All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY 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 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/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <arm/econa/econa_reg.h>
+
+static int uart_ec_probe(device_t dev);
+
+static device_method_t uart_ec_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		uart_ec_probe),
+	DEVMETHOD(device_attach,	uart_bus_attach),
+	DEVMETHOD(device_detach,	uart_bus_detach),
+	{ 0, 0 }
+};
+
+static driver_t uart_ec_driver = {
+	uart_driver_name,
+	uart_ec_methods,
+	sizeof(struct uart_softc),
+};
+
+static int
+uart_ec_probe(device_t dev)
+{
+	struct	uart_softc *sc;
+	int 	status;
+
+	sc = device_get_softc(dev);
+	sc->sc_class = &uart_ns8250_class;
+	status = uart_bus_probe(dev, EC_UART_REGSHIFT, EC_UART_CLOCK , 0, 0);
+
+	return(status);
+}
+
+DRIVER_MODULE(uart, econaarm, uart_ec_driver, uart_devclass, 0, 0);
Index: sys/arm/econa/std.econa
===================================================================
--- sys/arm/econa/std.econa	(revision 0)
+++ sys/arm/econa/std.econa	(revision 0)
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+files	"../econa/files.econa"
+cpu		CPU_FA526
+makeoptions	CONF_CFLAGS=-march=armv4
+options 	PHYSADDR=0x00000000
+makeoptions	KERNPHYSADDR=0x01000000
+makeoptions	KERNVIRTADDR=0xc1000000
+
+options 	KERNPHYSADDR=0x01000000
+options 	KERNVIRTADDR=0xc1000000		# Used in ldscript.arm
+options 	FLASHADDR=0xD0000000
+options 	LOADERRAMADDR=0x00000000
+options 	STARTUP_PAGETABLE_ADDR=0x00100000
Index: sys/conf/Makefile.arm
===================================================================
--- sys/conf/Makefile.arm	(revision 200988)
+++ sys/conf/Makefile.arm	(working copy)
@@ -73,7 +73,7 @@
 	$S/$M/$M/cpufunc_asm_sa1.S $S/$M/$M/cpufunc_asm_arm10.S \
 	$S/$M/$M/cpufunc_asm_xscale.S $S/$M/$M/cpufunc_asm.S \
 	$S/$M/$M/cpufunc_asm_xscale_c3.S $S/$M/$M/cpufunc_asm_armv5_ec.S \
-	$S/$M/$M/cpufunc_asm_sheeva.S
+	$S/$M/$M/cpufunc_asm_sheeva.S $S/$M/$M/cpufunc_asm_fa526.S
 KERNEL_EXTRA=trampoline
 KERNEL_EXTRA_INSTALL=kernel.gz.tramp
 trampoline: ${KERNEL_KO}.tramp
Index: sys/conf/options.arm
===================================================================
--- sys/conf/options.arm	(revision 200988)
+++ sys/conf/options.arm	(working copy)
@@ -36,3 +36,4 @@
 AT91_BWCT		opt_at91.h
 AT91_TSC		opt_at91.h
 AT91_KWIKBYTE		opt_at91.h
+CPU_FA526		opt_global.h
Index: sys/kern/vfs_mount.c
===================================================================
--- sys/kern/vfs_mount.c	(revision 200988)
+++ sys/kern/vfs_mount.c	(working copy)
@@ -1403,6 +1403,11 @@
 	struct timeval lastfail;
 	int curfail = 0;
 
+	/* temporary solution for timeout waiting for USB disk root
+	 * filesystem
+	 */
+	pause("WAIT", hz * 10);
+
 	for (;;) {
 		DROP_GIANT();
 		g_waitidle();

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?260bb65e0912250948w6f714367w672a1ebf037fb7f7>