Community discussions

MikroTik App
 
itsmorefun
just joined
Topic Author
Posts: 7
Joined: Mon Jul 29, 2013 11:46 pm

A attempt to update openwrt patch to support kernel 3.10.4

Sat Aug 03, 2013 9:25 am

Hello,

Because Mikrotik don't want to update the openwrt patch for compiling latest trunk with kernel 3.x i have try to update the path myself (MIPS only, config file not set)
Index: target/linux/mr-mips/config-3.10.4
===================================================================
--- target/linux/mr-mips/config-3.10.4	(revision 0)
+++ target/linux/mr-mips/config-3.10.4	(revision 0)
@@ -0,0 +1,236 @@
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_ATH79 is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
+# CONFIG_LANTIQ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MACH_LOONGSON is not set
+# CONFIG_MACH_LOONGSON1 is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_POWERTV is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+CONFIG_METAROUTER=y
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_NLM_XLR_BOARD is not set
+# CONFIG_NLM_XLP_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+# CONFIG_WR_PPMC is not set
+CONFIG_MAPPED_KERNEL=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_CEVT_R4K=y
+CONFIG_CSRC_R4K=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_128 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+# CONFIG_PCSPKR_PLATFORM is not set
+# CONFIG_PROBE_INITRD_HEADER is not set
+# CONFIG_MTD is not set
+
+
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_AX88796 is not set
+CONFIG_MT_VETH=y
+# CONFIG_DM9000 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_IRQ=y
+CONFIG_HVC_META=y
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+CONFIG_META_FS=y
+CONFIG_CMDLINE="init=/etc/preinit"
Index: target/linux/mr-mips/patches-3.10/000-linux-metarouter.patch
===================================================================
--- target/linux/mr-mips/patches-3.10/000-linux-metarouter.patch	(revision 0)
+++ target/linux/mr-mips/patches-3.10/000-linux-metarouter.patch	(revision 0)
@@ -0,0 +1,1974 @@
+diff -uNr linux-3.10.4/arch/mips/include/asm/fixmap.h linux-3.10.4.new/arch/mips/include/asm/fixmap.h
+--- linux-3.10.4/arch/mips/include/asm/fixmap.h	2010-01-07 00:27:24.000000000 +0200
++++ linux-3.10.4.new/arch/mips/include/asm/fixmap.h	2013-02-08 15:54:46.000000000 +0300
+@@ -68,6 +68,9 @@
+  * the start of the fixmap, and leave one page empty
+  * at the top of mem..
+  */
++#ifdef CONFIG_MAPPED_KERNEL
++#define FIXADDR_TOP   ((unsigned long)(long)(int)0xdffe0000)
++#endif
+ #define FIXADDR_SIZE	(__end_of_fixed_addresses << PAGE_SHIFT)
+ #define FIXADDR_START	(FIXADDR_TOP - FIXADDR_SIZE)
+ 
+diff -uNr linux-3.10.4/arch/mips/include/asm/io.h linux-3.10.4.new/arch/mips/include/asm/io.h
+--- linux-3.10.4/arch/mips/include/asm/io.h	2010-01-07 00:27:24.000000000 +0200
++++ linux-3.10.4.new/arch/mips/include/asm/io.h	2013-02-08 15:54:46.000000000 +0300
+@@ -201,6 +201,7 @@
+ 		if (!size || last_addr < phys_addr)
+ 			return NULL;
+ 
++#ifndef CONFIG_MAPPED_KERNEL
+ 		/*
+ 		 * Map uncached objects in the low 512MB of address
+ 		 * space using KSEG1.
+@@ -209,6 +210,7 @@
+ 		    flags == _CACHE_UNCACHED)
+ 			return (void __iomem *)
+ 				(unsigned long)CKSEG1ADDR(phys_addr);
++#endif
+ 	}
+ 
+ 	return __ioremap(offset, size, flags);
+diff -uNr linux-3.10.4/arch/mips/include/asm/mach-metarouter/kernel-entry-init.h linux-3.10.4.new/arch/mips/include/asm/mach-metarouter/kernel-entry-init.h
+--- linux-3.10.4/arch/mips/include/asm/mach-metarouter/kernel-entry-init.h	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/arch/mips/include/asm/mach-metarouter/kernel-entry-init.h	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1,44 @@
++#ifndef __ASM_MACH_METAROUTER_KERNEL_ENTRY_H
++#define __ASM_MACH_METAROUTER_KERNEL_ENTRY_H
++
++.macro	kernel_entry_setup
++#ifdef CONFIG_MAPPED_KERNEL
++	.set	push
++	.set	mips32r2
++	/* check whether we are running under 0xc0000000 address space */
++	lui	t0, 0xf000
++	bal	1f
++1:	and	t1, ra, t0
++	li	t0, 0xc0000000
++	beq	t0, t1, 2f
++	/* set up 0xc0000000 address space */
++	mtc0	t0, CP0_ENTRYHI
++	li	t0, 0x1f
++	mtc0	t0, CP0_ENTRYLO0
++	li	t0, 0x0010001f
++	mtc0	t0, CP0_ENTRYLO1
++	li	t0, PM_64M
++	mtc0	t0, CP0_PAGEMASK
++	li	t0, 0
++	mtc0	t0, CP0_INDEX
++	li	t0, 2
++	mtc0	t0, CP0_WIRED
++	ehb
++	tlbwi
++
++	li	t0, 0xc8000000
++	mtc0	t0, CP0_ENTRYHI
++	li	t0, 0x0020001f
++	mtc0	t0, CP0_ENTRYLO0
++	li	t0, 0x0030001f
++	mtc0	t0, CP0_ENTRYLO1
++	li	t0, 1
++	mtc0	t0, CP0_INDEX
++	ehb
++	tlbwi
++2:
++	.set	pop
++#endif
++.endm
++
++#endif
+diff -uNr linux-3.10.4/arch/mips/include/asm/mach-metarouter/spaces.h linux-3.10.4.new/arch/mips/include/asm/mach-metarouter/spaces.h
+--- linux-3.10.4/arch/mips/include/asm/mach-metarouter/spaces.h	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/arch/mips/include/asm/mach-metarouter/spaces.h	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1,24 @@
++#ifndef _ASM_MACH_METAROUTER_SPACES_H
++#define _ASM_MACH_METAROUTER_SPACES_H
++
++#include <linux/const.h>
++
++#define PHYS_OFFSET		_AC(0, UL)
++
++#ifdef CONFIG_MAPPED_KERNEL
++#define CAC_BASE		_AC(0xc0000000, UL)
++#else
++#define CAC_BASE		_AC(0x80000000, UL)
++#endif
++#define IO_BASE			_AC(0xa0000000, UL)
++#define UNCAC_BASE		_AC(0xa0000000, UL)
++
++#ifndef MAP_BASE
++#define MAP_BASE		_AC(0xd0000000, UL)
++#endif
++
++#define HIGHMEM_START		_AC(0x20000000, UL)
++
++#define PAGE_OFFSET		(CAC_BASE + PHYS_OFFSET)
++
++#endif
+diff -uNr linux-3.10.4/arch/mips/include/asm/mach-metarouter/war.h linux-3.10.4.new/arch/mips/include/asm/mach-metarouter/war.h
+--- linux-3.10.4/arch/mips/include/asm/mach-metarouter/war.h	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/arch/mips/include/asm/mach-metarouter/war.h	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1,18 @@
++#ifndef __ASM_MIPS_MACH_METAROUTER_WAR_H
++#define __ASM_MIPS_MACH_METAROUTER_WAR_H
++
++#define R4600_V1_INDEX_ICACHEOP_WAR	0
++#define R4600_V1_HIT_CACHEOP_WAR	0
++#define R4600_V2_HIT_CACHEOP_WAR	0
++#define R5432_CP0_INTERRUPT_WAR		0
++#define BCM1250_M3_WAR			0
++#define SIBYTE_1956_WAR			0
++#define MIPS4K_ICACHE_REFILL_WAR	0
++#define MIPS_CACHE_SYNC_WAR		0
++#define TX49XX_ICACHE_INDEX_INV_WAR	0
++#define RM9000_CDEX_SMP_WAR		0
++#define ICACHE_REFILLS_WORKAROUND_WAR   0
++#define R10000_LLSC_WAR			0
++#define MIPS34K_MISSED_ITLB_WAR		0
++
++#endif
+diff -uNr linux-3.10.4/arch/mips/include/asm/vm.h linux-3.10.4.new/arch/mips/include/asm/vm.h
+--- linux-3.10.4/arch/mips/include/asm/vm.h	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/arch/mips/include/asm/vm.h	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1,45 @@
++#ifndef MT_VM_H
++#define MT_VM_H
++
++#define GFP_HYPERVISOR	GFP_KERNEL
++
++#define VIRQ_BASE	64
++
++#define hypercall(name, nr, ...)		\
++	asm(					\
++		".global " #name ";"		\
++		".align 2;"			\
++		".set	push;"			\
++		".set	noreorder;"		\
++		".type " #name ",@function;"	\
++		".ent " #name ",0;"		\
++		#name ": .frame $sp,0,$ra;"	\
++		"li $3, " #nr ";"		\
++		"li $2, -22;"			\
++		"mtc0 $0, $1;"			\
++		"jr $ra;"			\
++		"nop;"				\
++		".end " #name ";"		\
++		".size " #name ",.-" #name ";"	\
++		".set	pop"			\
++        );					\
++	asmlinkage extern int name(__VA_ARGS__);
++
++/* NOTE: do not allow vdma_descr to span multiple pages, so align it */
++struct vdma_descr {
++	unsigned addr;
++	unsigned size;
++	unsigned next;
++} __attribute__((aligned(16)));
++
++#define DONE		0x80000000
++
++static inline unsigned get_virq_nr(unsigned hwirq)
++{
++	return VIRQ_BASE + hwirq;
++}
++
++extern int vm_running(void);
++#define hc_yield() asm volatile ("wait")
++
++#endif
+diff -uNr linux-3.10.4/arch/mips/Kconfig linux-3.10.4.new/arch/mips/Kconfig
+--- linux-3.10.4/arch/mips/Kconfig	2010-01-07 00:27:24.000000000 +0200
++++ linux-3.10.4.new/arch/mips/Kconfig	2013-02-08 15:54:46.000000000 +0300
+@@ -712,6 +712,19 @@
+ 	  Support the Mikrotik(tm) RouterBoard 532 series,
+ 	  based on the IDT RC32434 SoC.
+ 
++config METAROUTER
++	bool "Mikrotik MetaROUTER"
++	select CEVT_R4K
++	select CSRC_R4K
++	select IRQ_CPU
++	select DMA_NONCOHERENT
++	select SYS_HAS_CPU_MIPS32_R1
++	select SYS_SUPPORTS_BIG_ENDIAN
++	select SYS_SUPPORTS_32BIT_KERNEL
++	select MAPPED_KERNEL
++	help
++	  Support the Mikrotik(tm) MetaROUTER.
++
+ config WR_PPMC
+ 	bool "Wind River PPMC board"
+ 	select CEVT_R4K
+diff -uNr linux-3.10.4/arch/mips/metarouter/Platform linux-3.10.4/arch/mips/metarouter/Platform
+--- linux-3.10.4/arch/mips/metarouter/Platform	  1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4/arch/mips/metarouter/Platform   2013-08-02 19:01:32.000000000 +0200
+@@ -0,0 +1,8 @@
++# Mikrotik MetaROUTER
++#
++core-$(CONFIG_METAROUTER) += arch/mips/metarouter/
++cflags-$(CONFIG_METAROUTER) += -I$(srctree)/arch/mips/include/asm/mach-metarouter
++load-$(CONFIG_METAROUTER) += 0xffffffffc0101000
++ifdef CONFIG_METAROUTER
++OBJCOPYFLAGS += --change-addresses=0xc0000000
++endif
+diff -uNr linux-3.10.4/arch/mips/Makefile linux-3.10.4.new/arch/mips/Kbuild.platforms
+--- linux-3.10.4/arch/mips/Kbuild.platforms	2010-04-10 15:51:55.000000000 +0300
++++ linux-3.10.4.new/arch/mips/Kbuild.platforms	2013-02-08 15:54:46.000000000 +0300
+@@ -15,6 +15,7 @@
+ platforms += lasat
+ platforms += loongson
+ platforms += loongson1
++platforms += metarouter
+ platforms += mti-malta
+ platforms += mti-sead3
+ platforms += netlogic
+diff -uNr linux-3.10.4/arch/mips/metarouter/irq.c linux-3.10.4.new/arch/mips/metarouter/irq.c
+--- linux-3.10.4/arch/mips/metarouter/irq.c	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/arch/mips/metarouter/irq.c	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1,97 @@
++#include <linux/init.h>
++#include <linux/linkage.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/bitops.h>
++#include <linux/module.h>
++#include <asm/signal.h>
++#include <asm/mipsregs.h>
++#include <asm/irq_cpu.h>
++#include <asm/bootinfo.h>
++#include <asm/vm.h>
++
++asmlinkage void plat_irq_dispatch(void) {
++	unsigned pending = read_c0_status() & read_c0_cause() & 0xfe00;
++
++	if (pending)
++		do_IRQ(fls(pending) - 9);
++}
++
++volatile unsigned long virqs;
++EXPORT_SYMBOL(virqs);
++
++static void ack_virq(unsigned int irq)
++{
++	clear_bit(irq - VIRQ_BASE, &virqs);
++}
++
++static inline void unmask_virq(unsigned int irq)
++{
++}
++
++static inline void mask_virq(unsigned int irq)
++{
++}
++
++static struct irq_chip virq_controller = {
++	.name	= "virq",
++	.ack	= ack_virq,
++	.unmask = unmask_virq,
++	.mask	= mask_virq,
++};
++
++static irqreturn_t virq_cascade_irq(int irq, void *dev_id)
++{
++	unsigned i;
++	unsigned irqs = virqs;
++
++	for (i = 0; irqs; ++i) {
++		if (irqs & (1 << i)) {
++			do_IRQ(i + VIRQ_BASE);
++			irqs ^= (1 << i);
++		}
++	}
++	return IRQ_HANDLED;
++}
++
++static struct irqaction virq_cascade  = {
++	.handler = virq_cascade_irq,
++	.name = "virq-cascade",
++};
++
++static void soft_irq_ack(unsigned int irq)
++{
++	clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE));
++}
++
++static inline void unmask_soft_irq(unsigned int irq)
++ {
++	set_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE));
++	irq_enable_hazard();
++ }
++ 
++static inline void mask_soft_irq(unsigned int irq)
++{
++	clear_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE));
++	irq_disable_hazard();
++}
++
++static struct irq_chip soft_irq_controller = {
++	.name	= "SoftIRQ",
++	.ack	= soft_irq_ack,
++	.unmask = unmask_soft_irq,
++	.mask	= mask_soft_irq,
++};
++
++void __init arch_init_irq(void)
++{
++	unsigned i;
++
++	mips_cpu_irq_init();
++
++	set_irq_chip_and_handler(1, &soft_irq_controller, handle_percpu_irq);
++	setup_irq(1, &virq_cascade);
++
++	for (i = VIRQ_BASE;  i < VIRQ_BASE + 32; ++i)
++		set_irq_chip_and_handler(i, &virq_controller, handle_edge_irq);
++}
+diff -uNr linux-3.10.4/arch/mips/metarouter/Makefile linux-3.10.4.new/arch/mips/metarouter/Makefile
+--- linux-3.10.4/arch/mips/metarouter/Makefile	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/arch/mips/metarouter/Makefile	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1 @@
++obj-y += prom.o irq.o setup.o
+diff -uNr linux-3.10.4/arch/mips/metarouter/prom.c linux-3.10.4.new/arch/mips/metarouter/prom.c
+--- linux-3.10.4/arch/mips/metarouter/prom.c	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/arch/mips/metarouter/prom.c	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1,66 @@
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/console.h>
++#include <asm/bootinfo.h>
++#include <linux/bootmem.h>
++#include <linux/ioport.h>
++#include <linux/ctype.h>
++#include <linux/irq.h>
++
++extern char arcs_cmdline[COMMAND_LINE_SIZE];
++
++extern unsigned long totalram_pages;
++extern unsigned long mips_hpt_frequency;
++
++void __init prom_init(void)
++{
++	int argc = fw_arg0;
++	char **argv = (char **) fw_arg1;
++	unsigned i;
++	unsigned offset = strlen(arcs_cmdline);
++	if (offset > 0)
++		offset += snprintf(arcs_cmdline + offset,
++				   sizeof(arcs_cmdline) - offset,
++				   " ");
++
++	/* HZ must be parsed here because otherwise it's too late */
++	for (i = 0; (i < argc && argv[i] != NULL); i++) {
++		if (strncmp(argv[i], "HZ=", 3) == 0) {
++			mips_hpt_frequency = 
++			    simple_strtoul(argv[i] + 3, 0, 10);
++			continue;
++		}
++		offset += snprintf(arcs_cmdline + offset,
++				   sizeof(arcs_cmdline) - offset,
++				   "%s ", argv[i]);
++	}
++}
++
++void __init prom_free_prom_memory(void)
++{
++	unsigned long addr, end;
++	extern char _text;
++
++	/*
++	 * Free everything below the kernel itself but leave
++	 * the first page reserved for the exception handlers.
++	 */
++
++	end = __pa(&_text);
++	addr = PAGE_SIZE;
++
++	while (addr < end) {
++		ClearPageReserved(virt_to_page(__va(addr)));
++		init_page_count(virt_to_page(__va(addr)));
++		free_page((unsigned long)__va(addr));
++		addr += PAGE_SIZE;
++		++totalram_pages;
++	}
++}
++
++unsigned long long sched_clock(void)
++{
++	return read_c0_count() * 1000000000 / mips_hpt_frequency;
++}
+diff -uNr linux-3.10.4/arch/mips/metarouter/setup.c linux-3.10.4.new/arch/mips/metarouter/setup.c
+--- linux-3.10.4/arch/mips/metarouter/setup.c	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/arch/mips/metarouter/setup.c	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1,147 @@
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <asm/reboot.h>
++#include <asm/vm.h>
++
++#define BUF_SIZE	256
++#define BUF_COUNT	4
++
++hypercall(vm_create_queue, 4, unsigned id, unsigned irq,
++		 unsigned tx, unsigned rx);
++hypercall(vm_release_queue, 5, unsigned id);
++hypercall(vm_running, 6, void);
++hypercall(vm_setup_irqs, 14, unsigned *irqs, unsigned count);
++
++static volatile struct vdma_descr tx_chain[BUF_COUNT];
++static volatile struct vdma_descr rx_chain[BUF_COUNT];
++static unsigned char tx_buffers[BUF_COUNT][BUF_SIZE];
++static unsigned char rx_buffers[BUF_COUNT][BUF_SIZE];
++
++static unsigned cur_tx;
++static unsigned cur_rx;
++
++static int send_message(const unsigned char *buf, int len)
++{
++	unsigned long flags;
++
++	local_irq_save(flags);
++
++	/* drop some data if full buffer */
++	while (tx_chain[cur_tx].size & DONE)
++		asm volatile ("wait");
++
++	len = min_t(int, len, BUF_SIZE);
++	memcpy(tx_buffers[cur_tx], buf, len);
++	tx_chain[cur_tx].size = len | DONE;
++
++	cur_tx = (cur_tx + 1) % BUF_COUNT;
++
++	local_irq_restore(flags);
++
++	return len;
++}
++
++static int recv_message(char *buf, int len)
++{
++	unsigned long flags;
++
++	local_irq_save(flags);
++
++	if (!(rx_chain[cur_rx].size & DONE)) {
++		local_irq_restore(flags);
++		return 0;
++	}
++	
++	len = min_t(int, len, rx_chain[cur_rx].size & ~DONE);
++	memcpy(buf, rx_buffers[cur_rx], len);
++
++	rx_chain[cur_rx].size = BUF_SIZE;
++	cur_rx = (cur_rx + 1) % BUF_COUNT;
++
++	local_irq_restore(flags);
++
++	return len;
++}
++
++static irqreturn_t ctrl_interrupt(int irq, void *dev_id)
++{
++	struct task_struct *init;
++	char buf[256];
++	int len;
++
++	len = recv_message(buf, sizeof(buf));
++	if (len <= 0)
++		return IRQ_HANDLED;
++
++	if (strncmp(buf, "restart", len) == 0) {
++		printk("RESTART\n");
++		init = find_task_by_pid_ns(1, &init_pid_ns);
++		if (init)
++			send_sig(SIGINT, init, 1);
++	} else if (strncmp(buf, "halt", len) == 0) {
++	    printk("HALT\n");
++		init = find_task_by_pid_ns(1, &init_pid_ns);
++		if (init)
++			send_sig(SIGWINCH, init, 1);
++	}
++
++	return IRQ_HANDLED;
++}
++
++static void rbvm_machine_restart(char *command)
++{
++	char msg[] = "restart";
++
++	send_message(msg, sizeof(msg));
++}
++
++static void rbvm_machine_halt(void)
++{
++	char msg[] = "halt";
++
++	send_message(msg, sizeof(msg));
++}
++
++const char *get_system_type(void)
++{
++	return "Mikrotik MetaROUTER";
++}
++
++void __init plat_mem_setup(void)
++{
++	extern unsigned long virqs;
++	int i;
++
++	vm_setup_irqs((unsigned *) &virqs, 32);
++
++	for (i = 0; i < BUF_COUNT; ++i) {
++		rx_chain[i].addr = (unsigned) rx_buffers[i];
++		rx_chain[i].size = BUF_SIZE;
++		rx_chain[i].next = (unsigned) &rx_chain[i + 1];
++		
++		tx_chain[i].addr = (unsigned) tx_buffers[i];
++		tx_chain[i].size = 0;
++		tx_chain[i].next = (unsigned) &tx_chain[i + 1];
++	}
++	rx_chain[BUF_COUNT - 1].next = (unsigned) &rx_chain[0];
++	tx_chain[BUF_COUNT - 1].next = (unsigned) &tx_chain[0];
++
++	vm_create_queue(0, 0, (unsigned) &tx_chain[0],
++			(unsigned) &rx_chain[0]);
++
++	_machine_restart = rbvm_machine_restart;
++	_machine_halt = rbvm_machine_halt;
++}
++
++void __init plat_time_init(void)
++{
++}
++
++int __init init_ctrl_interrupt(void)
++{
++	if (request_irq(VIRQ_BASE + 0, ctrl_interrupt, 0, "ctrl", (void *) 1))
++		return -EBUSY;
++	return 0;
++
++}
++arch_initcall(init_ctrl_interrupt);
+diff -uNr linux-3.10.4/drivers/char/hvc_meta.c linux-3.10.4.new/drivers/char/hvc_meta.c
+--- linux-3.10.4/drivers/char/hvc_meta.c	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/drivers/char/hvc_meta.c	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1,134 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/bootmem.h>
++#include <asm/vm.h>
++#include <asm/irq.h>
++#include "hvc_console.h"
++
++extern int vm_create_queue(unsigned id, unsigned irq,
++			   unsigned tx, unsigned rx);
++extern int vm_release_queue(unsigned id);
++
++#define BUF_SIZE	4096
++
++static volatile struct vdma_descr tx_descr;
++static volatile struct vdma_descr rx_descr;
++
++static unsigned rx_offset;
++static DEFINE_SPINLOCK(lock);
++
++static int put_chars(u32 vtermno, const char *buf, int count)
++{
++	unsigned long flags;
++	int i;
++
++	spin_lock_irqsave(&lock, flags);
++
++#ifdef __powerpc__
++	for (i = 0; i < 2000000; ++i) {
++#else
++	for (i = 0; i < 2; ++i) {
++#endif
++		unsigned size = xchg(&tx_descr.size, 0);
++
++		if (!(size & DONE)) {
++			count = min(count, BUF_SIZE);
++			memcpy((char *) tx_descr.addr, buf, count);
++			tx_descr.size = count | DONE;
++
++			spin_unlock_irqrestore(&lock, flags);
++			return count;
++		}
++
++		if (size == (BUF_SIZE | DONE)) {
++			if (i == 0) {
++				tx_descr.size = size;
++				hc_yield();
++				continue;
++			} else {
++				unsigned drop = BUF_SIZE / 4;
++				size = BUF_SIZE - drop;
++				memcpy((char *) tx_descr.addr,
++				       (char *) tx_descr.addr + drop,
++				       size);
++			}
++		}
++
++		size &= ~DONE;
++		count = min(BUF_SIZE - (int) size, count);
++		memcpy((char *) tx_descr.addr + size, buf, count);
++		tx_descr.size = (size + count) | DONE;
++
++		spin_unlock_irqrestore(&lock, flags);
++		return count;
++	}
++
++	spin_unlock_irqrestore(&lock, flags);
++	return 0;
++}
++
++static int get_chars(u32 vtermno, char *buf, int count)
++{
++	unsigned long flags;
++	unsigned size;
++
++	spin_lock_irqsave(&lock, flags);
++
++	if (!(rx_descr.size & DONE)) {
++		spin_unlock_irqrestore(&lock, flags);
++		return -EAGAIN;
++	}
++	
++	size = (rx_descr.size & ~DONE) - rx_offset;
++	count = min(count, (int) size);
++
++	memcpy(buf, (char *) rx_descr.addr + rx_offset, count);
++
++	if (count == size) {
++		rx_descr.size = BUF_SIZE;
++		rx_offset = 0;
++	} else {
++		rx_offset += count;
++	}
++
++	spin_unlock_irqrestore(&lock, flags);
++	return count;
++}
++
++static struct hv_ops cons = {
++	.put_chars = put_chars,
++	.get_chars = get_chars,
++	.notifier_add = notifier_add_irq,
++	.notifier_del = notifier_del_irq,
++};
++
++static int __init cons_init(void)
++{
++	if (vm_running() != 0)
++		return 0;
++
++	rx_descr.addr = (unsigned) kmalloc(BUF_SIZE, GFP_KERNEL);
++	rx_descr.size = BUF_SIZE;
++	rx_descr.next = (unsigned) &rx_descr;
++	
++	tx_descr.addr = (unsigned) kmalloc(BUF_SIZE, GFP_KERNEL);
++	tx_descr.size = 0;
++	tx_descr.next = (unsigned) &tx_descr;
++
++	vm_create_queue(1, 1,
++			(unsigned) &tx_descr, (unsigned) &rx_descr);
++
++	return hvc_instantiate(0, 0, &cons);
++}
++console_initcall(cons_init);
++
++int vm_init(void)
++{
++	if (vm_running() == 0) 
++		hvc_alloc(0, get_virq_nr(1), &cons, 256);
++	return 0;
++}
++module_init(vm_init);
+diff -uNr linux-2.6.31.10/drivers/char/Kconfig linux-2.6.31.10.new/drivers/char/Kconfig
+--- linux-2.6.31.10/drivers/char/Kconfig	2010-01-07 00:27:24.000000000 +0200
++++ linux-2.6.31.10.new/drivers/char/Kconfig	2013-02-08 15:54:46.000000000 +0300
+@@ -157,6 +157,13 @@
+ 
+ source "drivers/tty/hvc/Kconfig"
+ 
++config HVC_META
++	bool "MetaROUTER Hypervisor Console support"
++	depends on METAROUTER
++	select HVC_DRIVER
++	select HVC_IRQ
++	default y
++ 
+ config VIRTIO_CONSOLE
+ 	tristate "Virtio console"
+ 	depends on VIRTIO && TTY
+diff -uNr linux-2.6.31.10/drivers/char/Makefile linux-2.6.31.10.new/drivers/char/Makefile
+--- linux-2.6.31.10/drivers/char/Makefile	2010-01-07 00:27:24.000000000 +0200
++++ linux-2.6.31.10.new/drivers/char/Makefile	2013-02-08 15:54:46.000000000 +0300
+@@ -7,6 +7,7 @@
+ obj-y				+= misc.o
+ obj-$(CONFIG_ATARI_DSP56K)	+= dsp56k.o
+ obj-$(CONFIG_VIRTIO_CONSOLE)	+= virtio_console.o
++obj-$(CONFIG_HVC_META)          += hvc_meta.o
+ obj-$(CONFIG_RAW_DRIVER)	+= raw.o
+ obj-$(CONFIG_SGI_SNSC)		+= snsc.o snsc_event.o
+ obj-$(CONFIG_MSM_SMD_PKT)	+= msm_smd_pkt.o
+diff -uNr linux-3.10.4/drivers/net/Kconfig linux-3.10.4.new/drivers/net/Kconfig
+--- linux-3.10.4/drivers/net/Kconfig	2010-01-07 00:27:24.000000000 +0200
++++ linux-3.10.4.new/drivers/net/Kconfig	2013-02-08 15:54:46.000000000 +0300
+@@ -287,6 +287,11 @@
+ 
+ 	  If you don't have this card, of course say N.
+ 
++config MT_VETH
++       bool "MetaROUTER Virtual Ethernet support"
++       depends on METAROUTER
++       default y
++
+ source "drivers/net/phy/Kconfig"
+ 
+ source "drivers/net/plip/Kconfig"
+diff -uNr linux-3.10.4/drivers/net/Makefile linux-3.10.4.new/drivers/net/Makefile
+--- linux-3.10.4/drivers/net/Makefile	2010-01-07 00:27:24.000000000 +0200
++++ linux-3.10.4.new/drivers/net/Makefile	2013-02-08 15:54:46.000000000 +0300
+@@ -59,6 +59,7 @@
+ obj-$(CONFIG_VMXNET3) += vmxnet3/
+ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
+ obj-$(CONFIG_XEN_NETDEV_BACKEND) += xen-netback/
++obj-$(CONFIG_MT_VETH) += mtveth.o
+
+ obj-$(CONFIG_USB_CATC)          += usb/
+ obj-$(CONFIG_USB_KAWETH)        += usb/
+diff -uNr linux-3.10.4/drivers/net/mtveth.c linux-3.10.4.new/drivers/net/mtveth.c
+--- linux-3.10.4/drivers/net/mtveth.c	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/drivers/net/mtveth.c	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1,284 @@
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/interrupt.h>
++#include <asm/vm.h>
++
++#define MAX_IFACES	8
++
++#define TXBUF_COUNT	1024
++#define RXBUF_COUNT	128
++
++#define RXBUF_SIZE	1600
++
++extern int vm_create_queue(unsigned id, unsigned irq,
++			   unsigned tx, unsigned rx);
++extern int vm_release_queue(unsigned id);
++
++#define CMD_NEWIFACE	0
++#define CMD_DELIFACE	1
++
++struct ctrl_msg {
++	unsigned cmd;
++	unsigned short id;
++	unsigned char hwaddr[6];
++} __attribute__((packed));
++
++static volatile struct vdma_descr rx_descr[RXBUF_COUNT];
++static volatile struct vdma_descr tx_descr[TXBUF_COUNT];
++static struct sk_buff *rx_skbs[RXBUF_COUNT];
++static struct sk_buff *tx_skbs[TXBUF_COUNT];
++
++static unsigned last_tx;
++static atomic_t cur_tx;
++static unsigned cur_rx;
++static unsigned max_tx;
++
++static struct net_device *devs[MAX_IFACES];
++
++struct veth_private {
++	unsigned id;
++	atomic_t pending_tx;
++};
++
++static void ctrl_receiver(struct work_struct *work);
++
++static struct sk_buff_head ctrl_queue;
++static DECLARE_WORK(ctrl_work, ctrl_receiver);
++
++static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	struct veth_private *veth = netdev_priv(dev);
++	unsigned cur = atomic_read(&cur_tx) % TXBUF_COUNT;
++    
++	if (skb_padto(skb, ETH_ZLEN))
++		return NETDEV_TX_OK;
++
++	if (tx_descr[cur].size & DONE) {
++		dev->stats.tx_dropped++;
++		dev_kfree_skb_any(skb);
++		return NETDEV_TX_OK;
++	}
++
++	if (skb_headroom(skb) < 2) {
++		struct sk_buff *s = skb;
++		skb = skb_realloc_headroom(s, 2);
++		dev_kfree_skb_any(s);
++	} else {
++		skb = skb_unshare(skb, GFP_ATOMIC);
++	}
++	if (!skb) {
++		dev->stats.tx_dropped++;
++		return NETDEV_TX_OK;
++	}
++	*(u16 *) skb_push(skb, 2) = veth->id;
++
++	dev->stats.tx_packets++;
++	dev->stats.tx_bytes += skb->len;
++
++	tx_descr[cur].addr = (unsigned) skb->data;
++	tx_descr[cur].size = skb->len | DONE;
++
++	if (tx_skbs[cur]) {
++		/* should not happen */
++		dev->stats.tx_dropped++;
++		dev_kfree_skb_any(skb);
++		return NETDEV_TX_BUSY;
++	}
++
++	tx_skbs[cur] = skb;
++	atomic_add(1, &cur_tx);
++
++	if (atomic_add_return(1, &veth->pending_tx) >= max_tx) {
++		netif_stop_queue(dev);
++
++		/* in case we got rewaken right before stop */
++		if (atomic_read(&veth->pending_tx) < max_tx)
++			netif_wake_queue(dev);
++	}
++
++	return 0;
++}
++
++static irqreturn_t veth_interrupt(int irq, void *dev_id)
++{
++	unsigned cur;
++
++	while (last_tx != atomic_read(&cur_tx)) {
++		unsigned last = last_tx % TXBUF_COUNT;
++		struct net_device *dev;
++		struct veth_private *veth;
++
++		if (tx_descr[last].size & DONE)
++			break;
++
++		dev = tx_skbs[last]->dev;
++		veth = netdev_priv(dev);
++		dev_kfree_skb_irq(tx_skbs[last]);
++		tx_skbs[last] = NULL;
++
++		++last_tx;
++
++		if (atomic_sub_return(1, &veth->pending_tx) < max_tx)
++			netif_wake_queue(dev);
++	}
++
++	cur = cur_rx % RXBUF_COUNT;
++	while ((rx_descr[cur].size & DONE)) {
++		struct sk_buff *skb = rx_skbs[cur];
++		struct net_device *dev;
++		unsigned id;
++
++		skb_put(skb, rx_descr[cur].size & ~DONE);
++		if (skb->len < 2) {
++			dev_kfree_skb_irq(skb);
++			goto next;
++		}
++
++		id = *(u16 *) skb->data;
++		skb_pull(skb, 2);
++
++		if (id == 0) {
++			__skb_queue_tail(&ctrl_queue, skb);
++			schedule_work(&ctrl_work);
++			goto next;
++		}
++		if (id >= MAX_IFACES || !devs[id]) {
++			dev_kfree_skb_irq(skb);
++			goto next;
++		}
++		dev = devs[id];
++
++		skb->dev = dev;
++		skb->protocol = eth_type_trans(skb, dev);
++
++		dev->last_rx = jiffies;
++		++dev->stats.rx_packets;
++		dev->stats.rx_bytes += skb->len;
++
++		netif_rx(skb);
++
++	  next:
++		skb = dev_alloc_skb(RXBUF_SIZE);
++		rx_skbs[cur] = skb;
++		if (skb) {
++			rx_descr[cur].addr = (unsigned) skb->data;
++			rx_descr[cur].size = RXBUF_SIZE;
++		} else {
++			rx_descr[cur].size = 0;
++		}
++
++		++cur_rx;
++		cur = cur_rx % RXBUF_COUNT;
++	}
++
++	return IRQ_HANDLED;
++}
++
++static const struct net_device_ops veth_netdev_ops = {
++	.ndo_start_xmit		= veth_xmit,
++};
++
++static int veth_alloc_dev(unsigned id, const unsigned char *hwaddr)
++{
++	struct veth_private *veth;
++	struct net_device *dev;
++	int err;
++
++	//SET_NETDEV_DEV(dev, &pdev->dev);
++	//platform_set_drvdata(pdev, dev);
++
++	dev = alloc_etherdev(sizeof(struct veth_private));
++	if (!dev)
++		return -ENOMEM;
++
++	veth = netdev_priv(dev);
++	veth->id = id;
++	atomic_set(&veth->pending_tx, 1);
++	memcpy(dev->dev_addr, hwaddr, 6);
++	dev->netdev_ops = &veth_netdev_ops;
++
++	err = register_netdev(dev);
++	if (err < 0) {
++		printk("cannot register net device %u\n", err);
++		goto netdev_err;
++	}
++
++	devs[id] = dev;
++	return 0;
++
++  netdev_err:
++	free_netdev(dev);
++	return err;
++}
++
++static int recv_ctrl_msg(struct sk_buff *skb)
++{
++	struct ctrl_msg *msg = (struct ctrl_msg *) skb->data;
++
++	if (skb->len < sizeof(struct ctrl_msg))
++		return -EINVAL;
++
++	if (msg->cmd == CMD_NEWIFACE) {
++		if (msg->id >= MAX_IFACES || devs[msg->id])
++			return -EBUSY;
++
++		veth_alloc_dev(msg->id, msg->hwaddr);
++		return 0;
++	} else if (msg->cmd == CMD_DELIFACE) {
++		struct net_device *dev;
++
++		if (msg->id >= MAX_IFACES || !devs[msg->id])
++			return -EINVAL;
++		
++		dev = devs[msg->id];
++		devs[msg->id] = NULL;
++
++		unregister_netdev(dev);
++	}
++	return -EINVAL;
++}
++
++static void ctrl_receiver(struct work_struct *work)
++{
++	struct sk_buff *skb;
++
++	while ((skb = skb_dequeue(&ctrl_queue)))
++		recv_ctrl_msg(skb);
++}
++
++int veth_init(void)
++{
++	unsigned i;
++
++	if (vm_running() != 0)
++		return 0;
++
++	skb_queue_head_init(&ctrl_queue);
++
++	if (request_irq(get_virq_nr(3), veth_interrupt, IRQF_SHARED,
++			"veth", (void *) 1))
++		return -EBUSY;
++
++	for (i = 0; i < TXBUF_COUNT; ++i) {
++		tx_descr[i].addr = 0;
++		tx_descr[i].size = 0;
++		tx_descr[i].next = (unsigned) &tx_descr[i + 1];
++	}
++	for (i = 0; i < RXBUF_COUNT; ++i) {
++		rx_skbs[i] = dev_alloc_skb(RXBUF_SIZE);
++		rx_descr[i].addr = (unsigned) rx_skbs[i]->data;
++		rx_descr[i].size = RXBUF_SIZE;
++		rx_descr[i].next = (unsigned) &rx_descr[i + 1];
++	}
++	tx_descr[TXBUF_COUNT - 1].next = (unsigned) &tx_descr[0];
++	rx_descr[RXBUF_COUNT - 1].next = (unsigned) &rx_descr[0];
++	
++	vm_create_queue(3, 3,
++			(unsigned) &tx_descr[0], (unsigned) &rx_descr[0]);
++
++	max_tx = TXBUF_COUNT / MAX_IFACES;
++
++	return 0;
++}
++module_init(veth_init);
+diff -uNr linux-3.10.4/fs/Kconfig linux-3.10.4.new/fs/Kconfig
+--- linux-3.10.4/fs/Kconfig	2010-01-07 00:27:24.000000000 +0200
++++ linux-3.10.4.new/fs/Kconfig	2013-02-08 15:54:46.000000000 +0300
+@@ -201,6 +201,7 @@
+ source "fs/bfs/Kconfig"
+ source "fs/efs/Kconfig"
+ source "fs/jffs2/Kconfig"
++source "fs/metafs/Kconfig"
+ # UBIFS File system configuration
+ source "fs/ubifs/Kconfig"
+ source "fs/logfs/Kconfig"
+diff -uNr linux-3.10.4/fs/Makefile linux-3.10.4.new/fs/Makefile
+--- linux-3.10.4/fs/Makefile	2010-01-07 00:27:24.000000000 +0200
++++ linux-3.10.4.new/fs/Makefile	2013-02-08 15:54:46.000000000 +0300
+@@ -72,6 +72,7 @@
+ obj-$(CONFIG_JBD)		+= jbd/
+ obj-$(CONFIG_JBD2)		+= jbd2/
+ obj-$(CONFIG_CRAMFS)		+= cramfs/
++obj-$(CONFIG_META_FS)           += metafs/
+ obj-$(CONFIG_SQUASHFS)		+= squashfs/
+ obj-y				+= ramfs/
+ obj-$(CONFIG_HUGETLBFS)		+= hugetlbfs/
+diff -uNr linux-3.10.4/fs/metafs/inode.c linux-3.10.4.new/fs/metafs/inode.c
+--- linux-3.10.4/fs/metafs/inode.c	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/fs/metafs/inode.c	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1,902 @@
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/statfs.h>
++#include <linux/pagemap.h>
++#include <linux/namei.h>
++#include <asm/vm.h>
++
++#define CMD_GETINODE		0
++#define CMD_RELEASE_INODE	1
++#define CMD_LOOKUP		2
++#define CMD_READPAGE		3
++#define CMD_READLINK		4
++#define CMD_READDIR		5
++#define CMD_WRITEPAGE		6
++#define CMD_CREATE		7
++#define CMD_UNLINK		8
++#define CMD_SYMLINK		9
++#define CMD_RENAME		10
++#define CMD_SETINODE		11
++#define CMD_STATFS		12
++#define CMD_HLINK		13
++#define CMD_FSYNC		14
++
++struct hptime {
++	unsigned sec;
++	unsigned nsec;
++};
++
++struct getinode_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long ino;
++} __attribute__((packed));
++
++struct inode_rep {
++	int status;
++	unsigned long long ino;
++	unsigned long long size;
++	unsigned mode;
++	unsigned nlink;
++	unsigned uid;
++	unsigned gid;
++	unsigned rdev;
++	struct hptime atime;
++	struct hptime mtime;
++	struct hptime ctime;
++	unsigned long blksize;
++	unsigned long long blocks;
++} __attribute__((packed));
++
++struct setinode_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long ino;
++	unsigned long long size;
++	unsigned mode;
++	unsigned uid;
++	unsigned gid;
++	unsigned rdev;
++} __attribute__((packed));
++
++struct lookup_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long parent_ino;
++	char name[0];
++} __attribute__((packed));
++
++struct create_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long parent_ino;
++	unsigned mode;
++	unsigned dev;
++	char name[0];
++} __attribute__((packed));
++
++struct unlink_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long parent_ino;
++	char name[0];
++} __attribute__((packed));
++
++struct symlink_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long parent_ino;
++	unsigned namelen;
++	char names[0];
++} __attribute__((packed));
++
++struct hlink_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long parent_ino;
++	unsigned long long ino;
++	char name[0];
++} __attribute__((packed));
++
++struct rename_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long old_parent_ino;
++	unsigned long long new_parent_ino;
++	unsigned old_namelen;
++	char names[0];
++} __attribute__((packed));
++
++struct readpage_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long ino;
++	unsigned long long offset;
++	unsigned size;
++} __attribute__((packed));
++
++struct writepage_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long ino;
++	unsigned long long offset;
++	unsigned size;
++} __attribute__((packed));
++
++struct fsync_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long ino;
++} __attribute__((packed));
++
++struct readlink_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long ino;
++} __attribute__((packed));
++
++struct readlink_rep {
++	int status;
++	char target[0];
++} __attribute__((packed));
++
++struct readdir_req {
++	unsigned short id;
++	unsigned short cmd;
++	unsigned long long ino;
++	unsigned long long offset;
++	unsigned size;
++} __attribute__((packed));
++
++struct dirnode {
++	unsigned long long ino;
++	unsigned long long offset;
++	unsigned char type;
++	unsigned short len;
++	char name[0];
++} __attribute__((packed));
++
++struct readdir_rep {
++	int status;
++	unsigned long long offset;
++	struct dirnode entries[0];
++} __attribute__((packed));
++
++struct statfs_req {
++	unsigned short id;
++	unsigned short cmd;
++} __attribute__((packed));
++
++struct statfs_rep {
++	int status;
++	unsigned blocks;
++	unsigned bfree;
++} __attribute__((packed));
++
++#define BUF_COUNT	16
++
++extern int vm_create_queue(unsigned id, unsigned irq,
++			   unsigned tx, unsigned rx);
++extern int vm_release_queue(unsigned id);
++
++static volatile struct vdma_descr rx_descr[BUF_COUNT];
++static volatile struct vdma_descr tx_descr[BUF_COUNT];
++
++#define MFS_ID(sb) ((unsigned) sb->s_fs_info)
++
++
++static void mfs_update_inode(struct inode *i, struct inode_rep *rep);
++static struct inode *mfs_new_inode(struct super_block *sb,
++				   struct inode_rep *rep);
++
++static void start_new_request(unsigned *tx_idx, unsigned tx_slots,
++			      unsigned *rx_idx, unsigned rx_slots)
++{
++	static DEFINE_MUTEX(mfs_lock);
++	static unsigned cur_tx;
++	static unsigned cur_rx;
++
++	mutex_lock(&mfs_lock);
++
++	*tx_idx = cur_tx;
++	cur_tx += tx_slots;
++
++	*rx_idx = cur_rx;
++	cur_rx += rx_slots;
++
++	mutex_unlock(&mfs_lock);
++}
++
++static void prepare_receive(unsigned idx, void *resp, unsigned rp_size)
++{
++	idx = idx & (BUF_COUNT - 1);
++
++	rx_descr[idx].addr = (unsigned) resp;
++	rx_descr[idx].size = rp_size;
++}
++
++static void post_request(unsigned idx, const void *req, unsigned rq_size)
++{
++	idx = idx & (BUF_COUNT - 1);
++
++	while (tx_descr[idx].size & DONE) {
++		hc_yield();
++	}
++
++	tx_descr[idx].addr = (unsigned) req;
++	tx_descr[idx].size = rq_size | DONE;
++}
++
++static unsigned wait_for_reply(unsigned idx)
++{
++	idx = idx & (BUF_COUNT - 1);
++
++	while (!(rx_descr[idx].size & DONE)) {
++		hc_yield();
++	}
++	return rx_descr[idx].size & ~(PAGE_MASK<<1);
++}
++
++static unsigned send_request(const void *req, unsigned rq_size,
++			     void *resp, unsigned rp_size)
++{
++	unsigned tx;
++	unsigned rx;
++
++	start_new_request(&tx, 1, &rx, 1);
++	prepare_receive(rx, resp, rp_size);
++	post_request(tx, req, rq_size);
++	return wait_for_reply(rx);
++}
++
++static struct kmem_cache *mfs_inode_cachep;
++
++static struct inode *mfs_alloc_inode(struct super_block *sb)
++{
++	return kmem_cache_alloc(mfs_inode_cachep, GFP_KERNEL);
++}
++
++static void mfs_destroy_inode(struct inode *inode)
++{
++	kmem_cache_free(mfs_inode_cachep, inode);
++}
++
++static struct dentry *mfs_lookup(struct inode *dir,
++				 struct dentry *dentry, struct nameidata *nd)
++{
++	unsigned size = sizeof(struct lookup_req) + dentry->d_name.len;
++	unsigned char buf[size];
++	struct lookup_req *req = (struct lookup_req *) buf;
++	struct inode_rep rep;
++	struct inode *inode = NULL;
++	struct dentry *res = NULL;
++	unsigned ret;
++
++	req->id = MFS_ID(dir->i_sb);
++	req->cmd = CMD_LOOKUP;
++	req->parent_ino = dir->i_ino;
++	memcpy(req->name, dentry->d_name.name, dentry->d_name.len);
++
++	rep.status = -EINVAL;
++	ret = send_request(req, size, &rep, sizeof(rep));
++	if (ret == sizeof(rep) && rep.status == 0)
++		inode = mfs_new_inode(dir->i_sb, &rep);
++	d_add(dentry, inode);
++	return res;
++}
++
++static int mfs_create_file(struct inode *dir, struct dentry *dentry,
++			   int mode, dev_t dev)
++{
++	unsigned size = sizeof(struct create_req) + dentry->d_name.len;
++	unsigned char buf[size];
++	struct create_req *req = (struct create_req *) buf;
++	struct inode_rep rep;
++	struct inode *inode = NULL;
++	unsigned ret;
++
++	req->id = MFS_ID(dir->i_sb);
++	req->cmd = CMD_CREATE;
++	req->parent_ino = dir->i_ino;
++	req->mode = mode;
++	req->dev = (unsigned) dev;
++	memcpy(req->name, dentry->d_name.name, dentry->d_name.len);
++
++	rep.status = -EINVAL;
++	ret = send_request(req, size, &rep, sizeof(rep));
++	if (ret < sizeof(rep))
++		return rep.status;
++
++	inode = mfs_new_inode(dir->i_sb, &rep);
++	d_instantiate(dentry, inode);
++	return 0;
++}
++
++static int mfs_create(struct inode *dir, struct dentry *dentry, int mode,
++		      struct nameidata *nd)
++{
++	return mfs_create_file(dir, dentry, mode, MKDEV(0, 0));
++}
++
++static int mfs_unlink(struct inode *dir, struct dentry *dentry)
++{
++	unsigned size = sizeof(struct unlink_req) + dentry->d_name.len;
++	unsigned char buf[size];
++	struct unlink_req *req = (struct unlink_req *) buf;
++	int err = -EINVAL;
++    
++	req->id = MFS_ID(dir->i_sb);
++	req->cmd = CMD_UNLINK;
++	req->parent_ino = dir->i_ino;
++	memcpy(req->name, dentry->d_name.name, dentry->d_name.len);
++
++	send_request(req, size, &err, sizeof(err));
++	return err;
++}
++
++static int mfs_symlink(struct inode *dir, struct dentry *dentry,
++		       const char *target)
++{
++	unsigned tlen = strlen(target);
++	unsigned size = sizeof(struct symlink_req) + dentry->d_name.len + tlen;
++	unsigned char buf[size];
++	struct symlink_req *req = (struct symlink_req *) buf;
++	struct inode_rep rep;
++	struct inode *inode = NULL;
++	unsigned ret;
++    
++	req->id = MFS_ID(dir->i_sb);
++	req->cmd = CMD_SYMLINK;
++	req->parent_ino = dir->i_ino;
++	req->namelen = dentry->d_name.len;
++	memcpy(req->names, dentry->d_name.name, dentry->d_name.len);
++	memcpy(req->names + req->namelen, target, tlen);
++
++	rep.status = -EINVAL;
++	ret = send_request(req, size, &rep, sizeof(rep));
++	if (ret < sizeof(rep))
++		return rep.status;
++
++	inode = mfs_new_inode(dir->i_sb, &rep);
++	d_instantiate(dentry, inode);
++	return 0;
++}
++
++static int mfs_link(struct dentry *old_dentry, struct inode *dir,
++		    struct dentry *dentry)
++{
++	unsigned size = sizeof(struct hlink_req) + dentry->d_name.len;
++	unsigned char buf[size];
++	struct hlink_req *req = (struct hlink_req *) buf;
++	struct inode_rep rep;
++	unsigned ret;
++    
++	req->id = MFS_ID(dir->i_sb);
++	req->cmd = CMD_HLINK;
++	req->parent_ino = dir->i_ino;
++	req->ino = old_dentry->d_inode->i_ino;
++	memcpy(req->name, dentry->d_name.name, dentry->d_name.len);
++
++	rep.status = -EINVAL;
++	ret = send_request(req, size, &rep, sizeof(rep));
++	if (ret < sizeof(rep))
++		return rep.status;
++
++	mfs_update_inode(old_dentry->d_inode, &rep);
++
++	atomic_inc(&old_dentry->d_inode->i_count);
++	d_instantiate(dentry, old_dentry->d_inode);
++	return 0;
++}
++
++static int mfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++	return mfs_create_file(dir, dentry, mode | S_IFDIR, MKDEV(0, 0));
++}
++
++static int mfs_rmdir(struct inode *dir, struct dentry *dentry)
++{
++	return mfs_unlink(dir, dentry);
++}
++
++static int mfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++		     dev_t rdev) {
++	return mfs_create_file(dir, dentry, mode, rdev);
++}
++
++static int mfs_rename(struct inode *old_dir, struct dentry *old_dentry,
++		      struct inode *new_dir, struct dentry *new_dentry)
++{
++	unsigned size = sizeof(struct rename_req) +
++	    old_dentry->d_name.len + new_dentry->d_name.len;
++	unsigned char buf[size];
++	struct rename_req *req = (struct rename_req *) buf;
++	int err = -EINVAL;
++    
++	req->id = MFS_ID(old_dir->i_sb);
++	req->cmd = CMD_RENAME;
++	req->old_parent_ino = old_dir->i_ino;
++	req->new_parent_ino = new_dir->i_ino;
++	req->old_namelen = old_dentry->d_name.len;
++	memcpy(req->names, old_dentry->d_name.name, old_dentry->d_name.len);
++	memcpy(req->names + req->old_namelen,
++	       new_dentry->d_name.name, new_dentry->d_name.len);
++
++	send_request(req, size, &err, sizeof(err));
++	return err;
++}
++
++static int mfs_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++	struct readdir_req req;
++	struct readdir_rep *rep;
++	struct dirnode *dn;
++	unsigned len;
++	int res = -EINVAL;
++
++	rep = kmalloc(PAGE_SIZE, GFP_KERNEL);
++	if (!rep)
++		return -ENOMEM;
++
++	req.id = MFS_ID(file->f_dentry->d_inode->i_sb);
++	req.cmd = CMD_READDIR;
++	req.ino = file->f_dentry->d_inode->i_ino;
++	req.offset = file->f_pos;
++	req.size = PAGE_SIZE;
++
++	len = send_request(&req, sizeof(req), rep, PAGE_SIZE);
++	if (len <= sizeof(*rep)) {
++		if (len >= sizeof(int))
++			res = rep->status;
++		goto eod;
++	}
++	
++	dn = rep->entries;
++	res = 0;
++	while ((char *) dn + sizeof(struct dirnode) < (char *) rep + len) {
++		if ((char *) dn + dn->len > (char *) rep + len)
++			break;
++		if (filldir(dirent, dn->name, dn->len - sizeof(struct dirnode),
++			    dn->offset, dn->ino, dn->type) < 0)
++			break;
++		++res;
++		dn = (struct dirnode *) ((unsigned char *) dn + dn->len);
++	}
++	file->f_pos = rep->offset;
++
++  eod:
++	kfree(rep);
++	return res;
++}
++
++static int mfs_readpage(struct file *file, struct page *page)
++{
++	struct readpage_req req;
++	void *buf;
++	int res = -EIO;
++	unsigned len;
++	unsigned tx;
++	unsigned rx;
++
++	buf = kmap(page);
++	if (!buf)
++		goto err_out;
++
++	req.id = MFS_ID(file->f_dentry->d_inode->i_sb);
++	req.cmd = CMD_READPAGE;
++	req.ino = file->f_dentry->d_inode->i_ino;
++	req.offset = page_offset(page);
++	req.size = PAGE_SIZE;
++
++	start_new_request(&tx, 1, &rx, 2);
++	prepare_receive(rx, &res, sizeof(res));
++	prepare_receive(rx + 1, buf, PAGE_SIZE);
++	post_request(tx, &req, sizeof(req));
++
++	if (wait_for_reply(rx) < sizeof(res)) {
++		res = -EINVAL;
++		goto err_out;
++	}
++	if (res) {
++		memset(buf, 0, PAGE_SIZE);
++		SetPageError(page);
++		goto err_buf;
++	}
++	len = wait_for_reply(rx + 1);
++
++	memset(buf + len, 0, PAGE_SIZE - len);
++	SetPageUptodate(page);
++
++  err_buf:
++	kunmap(page);
++	flush_dcache_page(page);
++  err_out:
++	unlock_page(page);
++	return res;
++}
++
++static int mfs_write_begin(struct file *file, struct address_space *mapping,
++			   loff_t pos, unsigned len, unsigned flags,
++			   struct page **pagep, void **fsdata)
++{
++	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
++
++	*pagep = grab_cache_page_write_begin(mapping, index, flags);
++	if (!*pagep)
++		return -ENOMEM;
++
++	// FIXME: do prereading
++
++	return 0;
++}
++
++static int mfs_write_end(struct file *file, struct address_space *mapping,
++			 loff_t pos, unsigned blen, unsigned copied,
++			 struct page *page, void *fsdata)
++{
++	struct inode *i = file->f_dentry->d_inode;
++	struct writepage_req req;
++	void *buf;
++	int len = -EFAULT;
++	unsigned tx;
++	unsigned rx;
++	unsigned size;
++
++	flush_dcache_page(page);
++
++	buf = kmap(page);
++	if (!buf)
++		return -EINVAL;
++
++	req.id = MFS_ID(i->i_sb);
++	req.cmd = CMD_WRITEPAGE;
++	req.ino = file->f_dentry->d_inode->i_ino;
++	req.offset = pos;
++	req.size = blen;
++
++	start_new_request(&tx, 2, &rx, 1);
++	prepare_receive(rx, &len, sizeof(len));
++	post_request(tx, &req, sizeof(req));
++	post_request(tx + 1, buf + (pos & (PAGE_CACHE_SIZE - 1)), blen);
++	wait_for_reply(rx);
++
++	if (len >= 0) {
++		if (len != blen) {
++			SetPageError(page);
++			ClearPageUptodate(page);
++		} else {
++			SetPageUptodate(page);
++		}
++
++		size = req.offset + len;
++		if (size > i_size_read(i)) i_size_write(i, size);
++	}
++
++	kunmap(page);
++	unlock_page(page);
++	page_cache_release(page);
++	return len;
++}
++
++static int mfs_fsync(struct file *file, struct dentry *dentry, int datasync)
++{
++	struct fsync_req req;
++	int err = -EINVAL;
++
++	req.id = MFS_ID(dentry->d_inode->i_sb);
++	req.cmd = CMD_FSYNC;
++	req.ino = file->f_dentry->d_inode->i_ino;
++
++	send_request(&req, sizeof(req), &err, sizeof(err));
++	return err;
++}
++
++static void *mfs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++	struct readlink_req req;
++	struct readlink_rep *rep;
++	int len;
++
++	rep = kmalloc(256, GFP_KERNEL);
++	if (!rep)
++		return ERR_PTR(-ENOMEM);
++
++	req.id = MFS_ID(dentry->d_inode->i_sb);
++	req.cmd = CMD_READLINK;
++	req.ino = dentry->d_inode->i_ino;
++	
++	rep->status = -EINVAL;
++	len = send_request(&req, sizeof(req), rep, 255);
++	if (len < sizeof(*rep) + 1) {
++		kfree(rep);
++		return ERR_PTR(rep->status);
++	}
++
++	*((char *) rep + len) = 0;
++	nd_set_link(nd, rep->target);
++	return NULL;
++}
++
++static void mfs_put_link(struct dentry *direntry,
++			 struct nameidata *nd, void *cookie)
++{
++	char *p = nd_get_link(nd);
++
++	if (!IS_ERR(p))
++		kfree(p - sizeof(struct readlink_rep));
++}
++
++static int mfs_setattr(struct dentry *dentry, struct iattr *attr)
++{
++	struct setinode_req req;
++	struct inode_rep rep;
++	struct inode *i = dentry->d_inode;
++	unsigned ia = attr->ia_valid;
++	unsigned len;
++
++	req.id = MFS_ID(i->i_sb);
++	req.cmd = CMD_SETINODE;
++	req.ino = i->i_ino;
++	req.mode = ia & ATTR_MODE ? attr->ia_mode : i->i_mode;
++	req.uid = ia & ATTR_UID ? attr->ia_uid : i->i_uid;
++	req.gid = ia & ATTR_GID ? attr->ia_gid : i->i_gid;
++	req.size = ia & ATTR_SIZE ? attr->ia_size : i->i_size;
++
++	len = send_request(&req, sizeof(req), &rep, sizeof(rep));
++	if (len < sizeof(rep))
++		return -EINVAL;
++	    
++	if (rep.status)
++		return rep.status;
++
++	mfs_update_inode(i, &rep);
++	return 0;
++}
++
++static const struct file_operations mfs_dir_fops = {
++	.read		= generic_read_dir,
++	.readdir	= mfs_readdir,
++};
++
++static const struct inode_operations mfs_dir_ops = {
++	.lookup		= mfs_lookup,
++	.create		= mfs_create,
++	.link		= mfs_link,
++	.unlink		= mfs_unlink,
++	.symlink	= mfs_symlink,
++	.mkdir		= mfs_mkdir,
++	.rmdir		= mfs_rmdir,
++	.mknod		= mfs_mknod,
++	.rename		= mfs_rename,
++	.setattr	= mfs_setattr,
++};
++
++static const struct inode_operations mfs_file_ops = {
++	.setattr	= mfs_setattr,
++};
++
++static const struct file_operations mfs_fops = {
++	.llseek		= generic_file_llseek,
++	.read		= do_sync_read,
++	.write		= do_sync_write,
++	.aio_read	= generic_file_aio_read,
++	.aio_write	= generic_file_aio_write,
++	.mmap		= generic_file_readonly_mmap,
++	.splice_read	= generic_file_splice_read,
++	.fsync		= mfs_fsync,
++};
++
++static const struct address_space_operations mfs_aops = {
++	.readpage	= mfs_readpage,
++	.write_begin	= mfs_write_begin,
++	.write_end	= mfs_write_end,
++};
++
++static const struct inode_operations mfs_link_ops = {
++	.readlink	= generic_readlink,
++	.follow_link	= mfs_follow_link,
++	.put_link	= mfs_put_link,
++	.setattr	= mfs_setattr,
++};
++
++static void mfs_update_inode(struct inode *i, struct inode_rep *rep)
++{
++	i->i_ino = rep->ino;
++	i->i_mode = rep->mode;
++	i->i_nlink = rep->nlink;
++	i->i_uid = rep->uid;
++	i->i_gid = rep->gid;
++	i->i_size = rep->size;
++	i->i_atime.tv_sec = rep->atime.sec;
++	i->i_atime.tv_nsec = rep->atime.nsec;
++	i->i_mtime.tv_sec = rep->mtime.sec;
++	i->i_mtime.tv_nsec = rep->mtime.nsec;
++	i->i_ctime.tv_sec = rep->ctime.sec;
++	i->i_ctime.tv_nsec = rep->ctime.nsec;
++	i->i_blkbits = ffs(rep->blksize);
++	i->i_blocks = rep->blocks;
++
++	if (i->i_sb->s_flags & MS_RDONLY)
++		i->i_mode &= ~0222;
++}
++
++static struct inode *mfs_new_inode(struct super_block *sb,
++				   struct inode_rep *rep)
++{
++	struct inode *i = new_inode(sb);
++	if (!i) return NULL;
++
++	mfs_update_inode(i, rep);
++
++	if (S_ISREG(rep->mode)) {
++		i->i_op = &mfs_file_ops;
++		i->i_fop = &mfs_fops;
++		i->i_data.a_ops = &mfs_aops;
++	} else if (S_ISDIR(rep->mode)) {
++		i->i_op = &mfs_dir_ops;
++		i->i_fop = &mfs_dir_fops;
++	} else if (S_ISLNK(rep->mode)) {
++		i->i_op = &mfs_link_ops;
++	} else {
++		init_special_inode(i, rep->mode, (dev_t) rep->rdev);
++	}
++
++	insert_inode_hash(i);
++	return i;
++}
++
++static struct inode *mfs_getinode(struct super_block *sb,
++				  unsigned long long ino)
++{
++	struct getinode_req req;
++	struct inode_rep rep;
++	unsigned len;
++
++	req.id = MFS_ID(sb);
++	req.cmd = CMD_GETINODE;
++	req.ino = ino;
++	len = send_request(&req, sizeof(req), &rep, sizeof(rep));
++
++	if (len < sizeof(rep) || rep.status)
++		return NULL;
++
++	return mfs_new_inode(sb, &rep);
++}
++
++static void mfs_put_super(struct super_block *sb)
++{
++}
++
++static int mfs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++	struct statfs_req req;
++	struct statfs_rep rep;
++	struct super_block *sb = dentry->d_sb;
++	unsigned len;
++
++	req.id = MFS_ID(sb);
++	req.cmd = CMD_STATFS;
++	rep.status = -EINVAL;
++	len = send_request(&req, sizeof(req), &rep, sizeof(rep));
++
++	if (len < sizeof(rep) || rep.status)
++		return rep.status;
++
++	buf->f_type = sb->s_magic;
++	buf->f_bsize = 512;
++	buf->f_blocks = rep.blocks;
++	buf->f_bfree = rep.bfree;
++	buf->f_bavail = rep.bfree;
++	buf->f_namelen = 255;
++
++	return 0;
++}
++
++static const struct super_operations mfs_ops = {
++	.alloc_inode	= mfs_alloc_inode,
++	.destroy_inode	= mfs_destroy_inode,
++	.put_super	= mfs_put_super,
++	.statfs		= mfs_statfs,
++};
++
++static int mfs_fill_super(struct super_block *sb, void *data, int silent)
++{
++	struct inode *root;
++	unsigned id;
++
++	if (*(char *) data == '/') ++data;
++	id = simple_strtoul((char *) data, NULL, 10);
++
++	sb->s_magic = 0xdeadbeef;
++	sb->s_op = &mfs_ops;
++	if (id == 0)
++		sb->s_flags |= MS_RDONLY;
++	sb->s_fs_info = (void *) id;
++
++	root = mfs_getinode(sb, 0);
++	if (!root)	    
++		goto out;
++
++	sb->s_root = d_alloc_root(root);
++	if (!sb->s_root)
++		goto outiput;
++
++	return 0;
++
++  outiput:
++	iput(root);
++  out:
++	return -EINVAL;
++}
++
++static int mfs_get_sb(struct file_system_type *fs_type,
++	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
++{
++	return get_sb_nodev(fs_type, flags,
++			    (void *) dev_name, mfs_fill_super, mnt);
++}
++
++static struct file_system_type mfs_fs_type = {
++	.owner		= THIS_MODULE,
++	.name		= "metafs",
++	.get_sb		= mfs_get_sb,
++	.kill_sb	= kill_block_super,
++	.fs_flags	= FS_REQUIRES_DEV,
++};
++
++static void init_once(void *foo)
++{
++	struct inode * inode = (struct inode *) foo;
++
++	inode_init_once(inode);
++}
++
++static int __init init_mfs_fs(void)
++{
++	unsigned i;
++	int err;
++
++	if (vm_running() != 0)
++		return 0;
++
++	printk("MFS init\n");
++	mfs_inode_cachep = kmem_cache_create("metafs_inode_cache",
++					     sizeof(struct inode),
++					     0, (SLAB_RECLAIM_ACCOUNT|
++						 SLAB_MEM_SPREAD),
++					     init_once);
++	if (!mfs_inode_cachep)
++		return -ENOMEM;
++
++	for (i = 0; i < BUF_COUNT; ++i) {
++		tx_descr[i].addr = 0;
++		tx_descr[i].size = 0;
++		tx_descr[i].next = (unsigned) &tx_descr[i + 1];
++
++		rx_descr[i].addr = 0;
++		rx_descr[i].size = DONE;
++		rx_descr[i].next = (unsigned) &rx_descr[i + 1];
++	}
++	tx_descr[BUF_COUNT - 1].next = (unsigned) &tx_descr[0];
++	rx_descr[BUF_COUNT - 1].next = (unsigned) &rx_descr[0];
++	
++	vm_create_queue(2, -1u,
++			(unsigned) &tx_descr[0], (unsigned) &rx_descr[0]);
++
++        err = register_filesystem(&mfs_fs_type);
++	if (err != 0) {
++		kmem_cache_destroy(mfs_inode_cachep);
++		return err;
++	}
++
++	return 0;
++}
++
++static void __exit exit_mfs_fs(void)
++{
++	unregister_filesystem(&mfs_fs_type);
++	kmem_cache_destroy(mfs_inode_cachep);
++}
++
++module_init(init_mfs_fs);
++module_exit(exit_mfs_fs);
+diff -uNr linux-3.10.4/fs/metafs/Kconfig linux-3.10.4.new/fs/metafs/Kconfig
+--- linux-3.10.4/fs/metafs/Kconfig	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/fs/metafs/Kconfig	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1,3 @@
++config META_FS
++	depends on METAROUTER
++	tristate "MetaFS on Mikrotik MetaROUTER"
+diff -uNr linux-3.10.4/fs/metafs/Makefile linux-3.10.4.new/fs/metafs/Makefile
+--- linux-3.10.4/fs/metafs/Makefile	1970-01-01 03:00:00.000000000 +0300
++++ linux-3.10.4.new/fs/metafs/Makefile	2013-02-08 15:54:46.000000000 +0300
+@@ -0,0 +1,3 @@
++obj-y += metafs.o
++
++metafs-objs := inode.o
Index: target/linux/mr-mips/patches-3.10/499-mips_module_reloc_fix.patch
===================================================================
--- target/linux/mr-mips/patches-3.10/499-mips_module_reloc_fix.patch	(revision 0)
+++ target/linux/mr-mips/patches-3.10/499-mips_module_reloc_fix.patch	(revision 0)
@@ -0,0 +1,12 @@
+diff -uNr linux-3.10.4/arch/mips/kernel/module.c linux-3.10.4.mod/arch/mips/kernel/module.c
+--- linux-3.10.4/arch/mips/kernel/module.c	2010-04-10 13:37:22.000000000 +0300
++++ linux-3.10.4.mod/arch/mips/kernel/module.c	2013-02-08 13:42:46.000000000 +0300
+@@ -182,7 +182,7 @@
+ #ifdef CONFIG_64BIT
+        return (KSEGX((unsigned long)ptr) == CKSEG0);
+ #else
+-       return (KSEGX(ptr) == KSEG0);
++       return ((_ACAST32_ (ptr)) & 0xf0000000) == 0xc0000000;
+ #endif
+ }
+
Index: target/linux/mr-mips/image/Makefile
===================================================================
--- target/linux/mr-mips/image/Makefile	(revision 0)
+++ target/linux/mr-mips/image/Makefile	(revision 0)
@@ -0,0 +1,14 @@
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+define Image/BuildKernel
+	cp $(KDIR)/vmlinux.elf $(TARGET_DIR)/kernel
+endef
+
+$(eval $(call BuildImage))
Index: target/linux/mr-mips/base-files/etc/inittab
===================================================================
--- target/linux/mr-mips/base-files/etc/inittab	(revision 0)
+++ target/linux/mr-mips/base-files/etc/inittab	(revision 0)
@@ -0,0 +1,3 @@
+::sysinit:/etc/init.d/rcS S boot
+::shutdown:/etc/init.d/rcS K stop
+hvc0::askfirst:/bin/ash --login
Index: target/linux/mr-mips/base-files/etc/hotplug2-init.rules
===================================================================
--- target/linux/mr-mips/base-files/etc/hotplug2-init.rules	(revision 0)
+++ target/linux/mr-mips/base-files/etc/hotplug2-init.rules	(revision 0)
@@ -0,0 +1,7 @@
+$include /etc/hotplug2-common.rules
+
+DEVICENAME ~~ (hvc) {
+        nothrottle
+        makedev /dev/%DEVICENAME% 0666
+        next
+}
Index: target/linux/mr-mips/Makefile
===================================================================
--- target/linux/mr-mips/Makefile	(revision 0)
+++ target/linux/mr-mips/Makefile	(revision 0)
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2007-2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+ARCH:=mips
+BOARD:=mr-mips
+BOARDNAME:=Mikrotik MetaROUTER MIPS
+FEATURES:=targz
+
+LINUX_VERSION:=3.10.4
+
+include $(INCLUDE_DIR)/target.mk
+$(eval $(call BuildTarget))
Patch seem ok, but the problem is compiling, in kernel 3.0 some things have changed and i can't compil irq.c :

arch/mips/metarouter/irq.c:38:2: error: unknown field 'ack' specified in initializer
arch/mips/metarouter/irq.c:38:2: warning: initialization from incompatible pointer type [enabled by default]
arch/mips/metarouter/irq.c:38:2: warning: (near initialization for 'virq_controller.irq_startup') [enabled by default]
arch/mips/metarouter/irq.c:39:2: error: unknown field 'unmask' specified in initializer
arch/mips/metarouter/irq.c:39:2: warning: initialization from incompatible pointer type [enabled by default]
arch/mips/metarouter/irq.c:39:2: warning: (near initialization for 'virq_controller.irq_shutdown') [enabled by default]
arch/mips/metarouter/irq.c:40:2: error: unknown field 'mask' specified in initializer
arch/mips/metarouter/irq.c:40:2: warning: initialization from incompatible pointer type [enabled by default]
arch/mips/metarouter/irq.c:40:2: warning: (near initialization for 'virq_controller.irq_enable') [enabled by default]
arch/mips/metarouter/irq.c:81:2: error: unknown field 'ack' specified in initializer
arch/mips/metarouter/irq.c:81:2: warning: initialization from incompatible pointer type [enabled by default]
arch/mips/metarouter/irq.c:81:2: warning: (near initialization for 'soft_irq_controller.irq_startup') [enabled by default]
arch/mips/metarouter/irq.c:82:2: error: unknown field 'unmask' specified in initializer
arch/mips/metarouter/irq.c:82:2: warning: initialization from incompatible pointer type [enabled by default]
arch/mips/metarouter/irq.c:82:2: warning: (near initialization for 'soft_irq_controller.irq_shutdown') [enabled by default]
arch/mips/metarouter/irq.c:83:2: error: unknown field 'mask' specified in initializer
arch/mips/metarouter/irq.c:83:2: warning: initialization from incompatible pointer type [enabled by default]
arch/mips/metarouter/irq.c:83:2: warning: (near initialization for 'soft_irq_controller.irq_enable') [enabled by default]
arch/mips/metarouter/irq.c: In function 'arch_init_irq':
arch/mips/metarouter/irq.c:92:2: error: implicit declaration of function 'set_irq_chip_and_handler' [-Werror=implicit-function-declaration]

I am not able to correct this, i don't hae the knowledges :-(

I have read this http://kernel.opensuse.org/cgit/kernel/ ... c2afc93597 and this http://us.generation-nt.com/answer/impl ... 12981.html But too hard for me :-(

Who is online

Users browsing this forum: No registered users and 14 guests