OpenWrt Forum Archive

Topic: Mikrotik metarouter openwrt patch kernel 3.10.4 need help

The content of this topic has been archived on 15 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

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))

(Last edited by itsmorefun on 3 Aug 2013, 10:53)

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 have the knowledges :-(

Source code of arch/mips/metarouter/irq.c made from the patch:

#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);
}

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 :-(

(Last edited by itsmorefun on 3 Aug 2013, 21:30)

itsmorefun wrote:
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 have the knowledges :-(

Source code of arch/mips/metarouter/irq.c made from the patch:

#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);
}

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 :-(

Im not also able to help you too much, but did you see this link? https://code.google.com/p/metarouter-ap … g%2Ftincan

I think it may help in you port.

The discussion might have continued from here.