diff options
author | Koen Kooi <koen@openembedded.org> | 2009-11-26 13:45:32 +0100 |
---|---|---|
committer | Koen Kooi <koen@openembedded.org> | 2009-11-26 13:45:32 +0100 |
commit | 8af5e0ed1a7c79cd97ac5c58a7663c56b7f11621 (patch) | |
tree | 39c6c19e441e1dc48a671a96e81d6c9aa3ebad63 /recipes/linux/linux-2.6.24/smartq5/smartq-gitupdate.diff | |
parent | 39e66d2f9b322ea7f8711bdcfa9b251b614e60fa (diff) |
linux 2.6.24: add support for smartq5 device (machine.conf will follow later)
* also fix task ordering due to kernel.bbclass changes
Diffstat (limited to 'recipes/linux/linux-2.6.24/smartq5/smartq-gitupdate.diff')
-rw-r--r-- | recipes/linux/linux-2.6.24/smartq5/smartq-gitupdate.diff | 8974 |
1 files changed, 8974 insertions, 0 deletions
diff --git a/recipes/linux/linux-2.6.24/smartq5/smartq-gitupdate.diff b/recipes/linux/linux-2.6.24/smartq5/smartq-gitupdate.diff new file mode 100644 index 0000000000..d9acf581ab --- /dev/null +++ b/recipes/linux/linux-2.6.24/smartq5/smartq-gitupdate.diff @@ -0,0 +1,8974 @@ + Makefile | 2 + arch/mips/Kconfig | 28 + arch/mips/Makefile | 4 + arch/mips/au1000/common/clocks.c | 1 + arch/mips/au1000/common/cputable.c | 36 + arch/mips/au1000/common/dbdma.c | 34 + arch/mips/au1000/common/gpio.c | 6 + arch/mips/au1000/common/platform.c | 14 + arch/mips/au1000/common/setup.c | 13 + arch/mips/au1000/common/time.c | 24 + arch/mips/fw/arc/identify.c | 5 + arch/mips/kernel/Makefile | 3 + arch/mips/kernel/asm-offsets.c | 108 + + arch/mips/kernel/cevt-r4k.c | 173 - + arch/mips/kernel/cevt-smtc.c | 321 +++ + arch/mips/kernel/cevt-txx9.c | 3 + arch/mips/kernel/cpu-bugs64.c | 2 + arch/mips/kernel/cpu-probe.c | 36 + arch/mips/kernel/csrc-r4k.c | 9 + arch/mips/kernel/entry.S | 10 + arch/mips/kernel/gdb-low.S | 24 + arch/mips/kernel/gdb-stub.c | 3 + arch/mips/kernel/genex.S | 41 + arch/mips/kernel/head.S | 4 + arch/mips/kernel/i8253.c | 1 + arch/mips/kernel/irixelf.c | 11 + arch/mips/kernel/irq-rm7000.c | 1 + arch/mips/kernel/irq-rm9000.c | 1 + arch/mips/kernel/kspd.c | 5 + arch/mips/kernel/mips-mt-fpaff.c | 4 + arch/mips/kernel/proc.c | 2 + arch/mips/kernel/process.c | 19 + arch/mips/kernel/ptrace.c | 2 + arch/mips/kernel/rtlx.c | 65 + arch/mips/kernel/scall32-o32.S | 15 + arch/mips/kernel/scall64-64.S | 2 + arch/mips/kernel/scall64-n32.S | 2 + arch/mips/kernel/scall64-o32.S | 16 + arch/mips/kernel/setup.c | 5 + arch/mips/kernel/smp.c | 6 + arch/mips/kernel/smtc.c | 257 +- + arch/mips/kernel/sysirix.c | 2 + arch/mips/kernel/time.c | 2 + arch/mips/kernel/traps.c | 124 - + arch/mips/kernel/unaligned.c | 8 + arch/mips/kernel/vpe.c | 46 + arch/mips/lasat/interrupt.c | 2 + arch/mips/lasat/lasat_board.c | 13 + arch/mips/lasat/sysctl.c | 172 - + arch/mips/lasat/sysctl.h | 24 + arch/mips/lib/csum_partial.S | 21 + arch/mips/lib/ucmpdi2.c | 2 + arch/mips/lib/uncached.c | 2 + arch/mips/math-emu/cp1emu.c | 8 + arch/mips/mips-boards/generic/time.c | 2 + arch/mips/mips-boards/malta/Makefile | 3 + arch/mips/mips-boards/malta/malta_smtc.c | 12 + arch/mips/mipssim/sim_time.c | 2 + arch/mips/mm/c-r3k.c | 8 + arch/mips/mm/c-r4k.c | 60 + arch/mips/mm/c-tx39.c | 17 + arch/mips/mm/cache.c | 23 + arch/mips/mm/cex-sb1.S | 8 + arch/mips/mm/dma-default.c | 5 + arch/mips/mm/init.c | 9 + arch/mips/mm/pg-r4k.c | 22 + arch/mips/mm/pg-sb1.c | 18 + arch/mips/mm/sc-ip22.c | 2 + arch/mips/mm/sc-mips.c | 3 + arch/mips/mm/sc-r5k.c | 2 + arch/mips/mm/sc-rm7k.c | 6 + arch/mips/mm/tlb-r3k.c | 6 + arch/mips/mm/tlb-r4k.c | 15 + arch/mips/mm/tlb-r8k.c | 4 + arch/mips/mm/tlbex.c | 160 - + arch/mips/pci/pci-bcm1480.c | 11 + arch/mips/pci/pci-bcm1480ht.c | 21 + arch/mips/pci/pci-ip27.c | 42 + arch/mips/pci/pci.c | 9 + arch/mips/pmc-sierra/yosemite/smp.c | 6 + arch/mips/sgi-ip22/ip22-int.c | 8 + arch/mips/sgi-ip22/ip22-platform.c | 2 + arch/mips/sgi-ip27/ip27-init.c | 2 + arch/mips/sgi-ip27/ip27-timer.c | 6 + arch/mips/sgi-ip27/ip27-xtalk.c | 6 + arch/mips/sgi-ip32/ip32-irq.c | 5 + arch/mips/sibyte/bcm1480/irq.c | 1 + arch/mips/sibyte/sb1250/irq.c | 1 + arch/mips/vr41xx/common/irq.c | 6 + drivers/net/Kconfig | 7 + drivers/net/Makefile | 2 + drivers/net/titan_ge.c | 2069 +++++++++++++++++++++ + drivers/net/titan_ge.h | 415 ++++ + drivers/net/titan_mdio.c | 217 ++ + drivers/net/titan_mdio.h | 56 + drivers/scsi/NCR53C9x.h | 7 + include/asm-mips/asmmacro.h | 10 + include/asm-mips/atomic.h | 4 + include/asm-mips/byteorder.h | 5 + include/asm-mips/cacheflush.h | 20 + include/asm-mips/cevt-r4k.h | 46 + include/asm-mips/elf.h | 2 + include/asm-mips/gdb-stub.h | 149 - + include/asm-mips/irqflags.h | 26 + include/asm-mips/lasat/serial.h | 4 + include/asm-mips/mach-au1x00/au1000.h | 1 + include/asm-mips/mach-ip27/cpu-feature-overrides.h | 4 + include/asm-mips/mach-ip27/dma-coherence.h | 2 + include/asm-mips/mach-jmr3927/ioremap.h | 2 + include/asm-mips/mach-lasat/irq.h | 2 + include/asm-mips/mach-pb1x00/pb1200.h | 2 + include/asm-mips/mach-qemu/cpu-feature-overrides.h | 2 + include/asm-mips/mipsregs.h | 6 + include/asm-mips/pgtable-32.h | 2 + include/asm-mips/pgtable.h | 3 + include/asm-mips/rtlx.h | 6 + include/asm-mips/smtc.h | 8 + include/asm-mips/sn/mapped_kernel.h | 8 + include/asm-mips/stackframe.h | 72 + include/asm-mips/time.h | 7 + 120 files changed, 4344 insertions(+), 1079 deletions(-) +diff -Nurd linux-2.6.24/arch/mips/au1000/common/clocks.c mer-smartq-kernel/arch/mips/au1000/common/clocks.c +--- linux-2.6.24/arch/mips/au1000/common/clocks.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/au1000/common/clocks.c 2009-11-17 12:13:28.000000000 +0100 +@@ -46,6 +46,7 @@ + { + return au1x00_clock; + } ++EXPORT_SYMBOL(get_au1x00_speed); + + + +diff -Nurd linux-2.6.24/arch/mips/au1000/common/cputable.c mer-smartq-kernel/arch/mips/au1000/common/cputable.c +--- linux-2.6.24/arch/mips/au1000/common/cputable.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/au1000/common/cputable.c 2009-11-17 12:13:28.000000000 +0100 +@@ -22,24 +22,24 @@ + /* With some thought, we can probably use the mask to reduce the + * size of the table. + */ +-struct cpu_spec cpu_specs[] = { +- { 0xffffffff, 0x00030100, "Au1000 DA", 1, 0 }, +- { 0xffffffff, 0x00030201, "Au1000 HA", 1, 0 }, +- { 0xffffffff, 0x00030202, "Au1000 HB", 1, 0 }, +- { 0xffffffff, 0x00030203, "Au1000 HC", 1, 1 }, +- { 0xffffffff, 0x00030204, "Au1000 HD", 1, 1 }, +- { 0xffffffff, 0x01030200, "Au1500 AB", 1, 1 }, +- { 0xffffffff, 0x01030201, "Au1500 AC", 0, 1 }, +- { 0xffffffff, 0x01030202, "Au1500 AD", 0, 1 }, +- { 0xffffffff, 0x02030200, "Au1100 AB", 1, 1 }, +- { 0xffffffff, 0x02030201, "Au1100 BA", 1, 1 }, +- { 0xffffffff, 0x02030202, "Au1100 BC", 1, 1 }, +- { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1 }, +- { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 }, +- { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 }, +- { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 }, +- { 0xffffffff, 0x04030201, "Au1200 AC", 1, 0 }, +- { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 }, ++struct cpu_spec cpu_specs[] = { ++ { 0xffffffff, 0x00030100, "Au1000 DA", 1, 0, 1 }, ++ { 0xffffffff, 0x00030201, "Au1000 HA", 1, 0, 1 }, ++ { 0xffffffff, 0x00030202, "Au1000 HB", 1, 0, 1 }, ++ { 0xffffffff, 0x00030203, "Au1000 HC", 1, 1, 0 }, ++ { 0xffffffff, 0x00030204, "Au1000 HD", 1, 1, 0 }, ++ { 0xffffffff, 0x01030200, "Au1500 AB", 1, 1, 0 }, ++ { 0xffffffff, 0x01030201, "Au1500 AC", 0, 1, 0 }, ++ { 0xffffffff, 0x01030202, "Au1500 AD", 0, 1, 0 }, ++ { 0xffffffff, 0x02030200, "Au1100 AB", 1, 1, 0 }, ++ { 0xffffffff, 0x02030201, "Au1100 BA", 1, 1, 0 }, ++ { 0xffffffff, 0x02030202, "Au1100 BC", 1, 1, 0 }, ++ { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1, 0 }, ++ { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1, 0 }, ++ { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1, 0 }, ++ { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0, 0 }, ++ { 0xffffffff, 0x04030201, "Au1200 AC", 1, 0, 0 }, ++ { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0, 0 } + }; + + void +diff -Nurd linux-2.6.24/arch/mips/au1000/common/dbdma.c mer-smartq-kernel/arch/mips/au1000/common/dbdma.c +--- linux-2.6.24/arch/mips/au1000/common/dbdma.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/au1000/common/dbdma.c 2009-11-17 12:13:28.000000000 +0100 +@@ -161,22 +161,22 @@ + { DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, + + /* Provide 16 user definable device types */ +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, +- { 0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, ++ { ~0, 0, 0, 0, 0, 0, 0 }, + }; + + #define DBDEV_TAB_SIZE (sizeof(dbdev_tab) / sizeof(dbdev_tab_t)) +@@ -209,7 +209,7 @@ + dbdev_tab_t *p=NULL; + static u16 new_id=0x1000; + +- p = find_dbdev_id(0); ++ p = find_dbdev_id(~0); + if ( NULL != p ) + { + memcpy(p, dev, sizeof(dbdev_tab_t)); +diff -Nurd linux-2.6.24/arch/mips/au1000/common/gpio.c mer-smartq-kernel/arch/mips/au1000/common/gpio.c +--- linux-2.6.24/arch/mips/au1000/common/gpio.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/au1000/common/gpio.c 2009-11-17 12:13:28.000000000 +0100 +@@ -54,7 +54,7 @@ + { + gpio -= AU1XXX_GPIO_BASE; + +- gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | (value << gpio); ++ gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | ((!!value) << gpio); + } + + static int au1xxx_gpio2_direction_input(unsigned gpio) +@@ -67,7 +67,8 @@ + static int au1xxx_gpio2_direction_output(unsigned gpio, int value) + { + gpio -= AU1XXX_GPIO_BASE; +- gpio2->dir = (0x01 << gpio) | (value << gpio); ++ gpio2->dir |= 0x01 << gpio; ++ gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | ((!!value) << gpio); + return 0; + } + +@@ -96,6 +97,7 @@ + static int au1xxx_gpio1_direction_output(unsigned gpio, int value) + { + gpio1->trioutclr = (0x01 & gpio); ++ au1xxx_gpio1_write(gpio, value); + return 0; + } + +diff -Nurd linux-2.6.24/arch/mips/au1000/common/platform.c mer-smartq-kernel/arch/mips/au1000/common/platform.c +--- linux-2.6.24/arch/mips/au1000/common/platform.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/au1000/common/platform.c 2009-11-17 12:13:28.000000000 +0100 +@@ -118,12 +118,12 @@ + static struct resource au1xxx_mmc_resources[] = { + [0] = { + .start = SD0_PHYS_ADDR, +- .end = SD0_PHYS_ADDR + 0x40, ++ .end = SD0_PHYS_ADDR + 0x7ffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = SD1_PHYS_ADDR, +- .end = SD1_PHYS_ADDR + 0x40, ++ .end = SD1_PHYS_ADDR + 0x7ffff, + .flags = IORESOURCE_MEM, + }, + [2] = { +@@ -245,13 +245,12 @@ + .id = 0, + }; + +-#ifdef CONFIG_MIPS_DB1200 +- ++#if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200) + static struct resource smc91x_resources[] = { + [0] = { + .name = "smc91x-regs", + .start = AU1XXX_SMC91111_PHYS_ADDR, +- .end = AU1XXX_SMC91111_PHYS_ADDR + 0xfffff, ++ .end = AU1XXX_SMC91111_PHYS_ADDR + 0xf, + .flags = IORESOURCE_MEM, + }, + [1] = { +@@ -267,8 +266,7 @@ + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, + }; +- +-#endif ++#endif /* defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200) */ + + static struct platform_device *au1xxx_platform_devices[] __initdata = { + &au1xxx_usb_ohci_device, +@@ -284,7 +282,7 @@ + &au1200_ide0_device, + &au1xxx_mmc_device, + #endif +-#ifdef CONFIG_MIPS_DB1200 ++#if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200) + &smc91x_device, + #endif + }; +diff -Nurd linux-2.6.24/arch/mips/au1000/common/setup.c mer-smartq-kernel/arch/mips/au1000/common/setup.c +--- linux-2.6.24/arch/mips/au1000/common/setup.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/au1000/common/setup.c 2009-11-17 12:13:28.000000000 +0100 +@@ -57,7 +57,7 @@ + { + struct cpu_spec *sp; + char *argptr; +- unsigned long prid, cpupll, bclk = 1; ++ unsigned long prid, cpufreq, bclk = 1; + + set_cpuspec(); + sp = cur_cpu_spec[0]; +@@ -65,8 +65,15 @@ + board_setup(); /* board specific setup */ + + prid = read_c0_prid(); +- cpupll = (au_readl(0xB1900060) & 0x3F) * 12; +- printk("(PRId %08lx) @ %ldMHZ\n", prid, cpupll); ++ if (sp->cpu_pll_wo) ++#ifdef CONFIG_SOC_AU1000_FREQUENCY ++ cpufreq = CONFIG_SOC_AU1000_FREQUENCY / 1000000; ++#else ++ cpufreq = 396; ++#endif ++ else ++ cpufreq = (au_readl(SYS_CPUPLL) & 0x3F) * 12; ++ printk(KERN_INFO "(PRID %08lx) @ %ld MHz\n", prid, cpufreq); + + bclk = sp->cpu_bclk; + if (bclk) +diff -Nurd linux-2.6.24/arch/mips/au1000/common/time.c mer-smartq-kernel/arch/mips/au1000/common/time.c +--- linux-2.6.24/arch/mips/au1000/common/time.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/au1000/common/time.c 2009-11-17 12:13:28.000000000 +0100 +@@ -209,18 +209,22 @@ + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); + au_writel(0, SYS_TOYWRITE); + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); ++ } else ++ no_au1xxx_32khz = 1; + +- cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * +- AU1000_SRC_CLK; +- } +- else { +- /* The 32KHz oscillator isn't running, so assume there +- * isn't one and grab the processor speed from the PLL. +- * NOTE: some old silicon doesn't allow reading the PLL. +- */ ++ /* ++ * On early Au1000, sys_cpupll was write-only. Since these ++ * silicon versions of Au1000 are not sold by AMD, we don't bend ++ * over backwards trying to determine the frequency. ++ */ ++ if (cur_cpu_spec[0]->cpu_pll_wo) ++#ifdef CONFIG_SOC_AU1000_FREQUENCY ++ cpu_speed = CONFIG_SOC_AU1000_FREQUENCY; ++#else ++ cpu_speed = 396000000; ++#endif ++ else + cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK; +- no_au1xxx_32khz = 1; +- } + mips_hpt_frequency = cpu_speed; + // Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) + set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16)); +diff -Nurd linux-2.6.24/arch/mips/fw/arc/identify.c mer-smartq-kernel/arch/mips/fw/arc/identify.c +--- linux-2.6.24/arch/mips/fw/arc/identify.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/fw/arc/identify.c 2009-11-17 12:13:29.000000000 +0100 +@@ -67,6 +67,11 @@ + .liname = "SNI RM200_PCI", + .type = MACH_SNI_RM200_PCI, + .flags = PROM_FLAG_DONT_FREE_TEMP, ++ }, { ++ .arcname = "RM200PCI-R5K", ++ .liname = "SNI RM200_PCI-R5K", ++ .type = MACH_SNI_RM200_PCI, ++ .flags = PROM_FLAG_DONT_FREE_TEMP, + } + }; + +diff -Nurd linux-2.6.24/arch/mips/Kconfig mer-smartq-kernel/arch/mips/Kconfig +--- linux-2.6.24/arch/mips/Kconfig 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/Kconfig 2009-11-17 12:13:28.000000000 +0100 +@@ -1453,7 +1453,6 @@ + depends on CPU_MIPS32_R2 + #depends on CPU_MIPS64_R2 # once there is hardware ... + depends on SYS_SUPPORTS_MULTITHREADING +- select GENERIC_CLOCKEVENTS_BROADCAST + select CPU_MIPSR2_IRQ_VI + select CPU_MIPSR2_IRQ_EI + select MIPS_MT +@@ -1487,32 +1486,17 @@ + Includes a loader for loading an elf relocatable object + onto another VPE and running it. + +-config MIPS_MT_SMTC_INSTANT_REPLAY +- bool "Low-latency Dispatch of Deferred SMTC IPIs" +- depends on MIPS_MT_SMTC && !PREEMPT +- default y +- help +- SMTC pseudo-interrupts between TCs are deferred and queued +- if the target TC is interrupt-inhibited (IXMT). In the first +- SMTC prototypes, these queued IPIs were serviced on return +- to user mode, or on entry into the kernel idle loop. The +- INSTANT_REPLAY option dispatches them as part of local_irq_restore() +- processing, which adds runtime overhead (hence the option to turn +- it off), but ensures that IPIs are handled promptly even under +- heavy I/O interrupt load. +- + config MIPS_MT_SMTC_IM_BACKSTOP + bool "Use per-TC register bits as backstop for inhibited IM bits" + depends on MIPS_MT_SMTC +- default y ++ default n + help + To support multiple TC microthreads acting as "CPUs" within + a VPE, VPE-wide interrupt mask bits must be specially manipulated + during interrupt handling. To support legacy drivers and interrupt + controller management code, SMTC has a "backstop" to track and + if necessary restore the interrupt mask. This has some performance +- impact on interrupt service overhead. Disable it only if you know +- what you are doing. ++ impact on interrupt service overhead. + + config MIPS_MT_SMTC_IRQAFF + bool "Support IRQ affinity API" +@@ -1522,10 +1506,8 @@ + Enables SMP IRQ affinity API (/proc/irq/*/smp_affinity, etc.) + for SMTC Linux kernel. Requires platform support, of which + an example can be found in the MIPS kernel i8259 and Malta +- platform code. It is recommended that MIPS_MT_SMTC_INSTANT_REPLAY +- be enabled if MIPS_MT_SMTC_IRQAFF is used. Adds overhead to +- interrupt dispatch, and should be used only if you know what +- you are doing. ++ platform code. Adds some overhead to interrupt dispatch, and ++ should be used only if you know what you are doing. + + config MIPS_VPE_LOADER_TOM + bool "Load VPE program into memory hidden from linux" +@@ -1781,7 +1763,7 @@ + Allows the configuration of the timer frequency. + + config HZ_48 +- bool "48 HZ" if SYS_SUPPORTS_48HZ ++ bool "48 HZ" if SYS_SUPPORTS_48HZ || SYS_SUPPORTS_ARBIT_HZ + + config HZ_100 + bool "100 HZ" if SYS_SUPPORTS_100HZ || SYS_SUPPORTS_ARBIT_HZ +diff -Nurd linux-2.6.24/arch/mips/kernel/asm-offsets.c mer-smartq-kernel/arch/mips/kernel/asm-offsets.c +--- linux-2.6.24/arch/mips/kernel/asm-offsets.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/asm-offsets.c 2009-11-17 12:13:29.000000000 +0100 +@@ -13,7 +13,7 @@ + #include <linux/sched.h> + #include <linux/mm.h> + #include <linux/interrupt.h> +- ++#include <asm/gdb-stub.h> + #include <asm/ptrace.h> + #include <asm/processor.h> + +@@ -337,3 +337,109 @@ + size("#define IC_IRQ_CPUSTAT_T ", irq_cpustat_t); + linefeed; + } ++ ++void output_gdbreg_defines(void) ++{ ++ text("/* MIPS struct gdb_regs offsets. */"); ++ offset("#define GDB_FR_REG0 ", struct gdb_regs, reg0); ++ offset("#define GDB_FR_REG1 ", struct gdb_regs, reg1); ++ offset("#define GDB_FR_REG2 ", struct gdb_regs, reg2); ++ offset("#define GDB_FR_REG3 ", struct gdb_regs, reg3); ++ offset("#define GDB_FR_REG4 ", struct gdb_regs, reg4); ++ offset("#define GDB_FR_REG5 ", struct gdb_regs, reg5); ++ offset("#define GDB_FR_REG6 ", struct gdb_regs, reg6); ++ offset("#define GDB_FR_REG7 ", struct gdb_regs, reg7); ++ offset("#define GDB_FR_REG8 ", struct gdb_regs, reg8); ++ offset("#define GDB_FR_REG9 ", struct gdb_regs, reg9); ++ offset("#define GDB_FR_REG10 ", struct gdb_regs, reg10); ++ offset("#define GDB_FR_REG11 ", struct gdb_regs, reg11); ++ offset("#define GDB_FR_REG12 ", struct gdb_regs, reg12); ++ offset("#define GDB_FR_REG13 ", struct gdb_regs, reg13); ++ offset("#define GDB_FR_REG14 ", struct gdb_regs, reg14); ++ offset("#define GDB_FR_REG15 ", struct gdb_regs, reg15); ++ offset("#define GDB_FR_REG16 ", struct gdb_regs, reg16); ++ offset("#define GDB_FR_REG17 ", struct gdb_regs, reg17); ++ offset("#define GDB_FR_REG18 ", struct gdb_regs, reg18); ++ offset("#define GDB_FR_REG19 ", struct gdb_regs, reg19); ++ offset("#define GDB_FR_REG20 ", struct gdb_regs, reg20); ++ offset("#define GDB_FR_REG21 ", struct gdb_regs, reg21); ++ offset("#define GDB_FR_REG22 ", struct gdb_regs, reg22); ++ offset("#define GDB_FR_REG23 ", struct gdb_regs, reg23); ++ offset("#define GDB_FR_REG24 ", struct gdb_regs, reg24); ++ offset("#define GDB_FR_REG25 ", struct gdb_regs, reg25); ++ offset("#define GDB_FR_REG26 ", struct gdb_regs, reg26); ++ offset("#define GDB_FR_REG27 ", struct gdb_regs, reg27); ++ offset("#define GDB_FR_REG28 ", struct gdb_regs, reg28); ++ offset("#define GDB_FR_REG29 ", struct gdb_regs, reg29); ++ offset("#define GDB_FR_REG30 ", struct gdb_regs, reg30); ++ offset("#define GDB_FR_REG31 ", struct gdb_regs, reg31); ++ linefeed; ++ ++ offset("#define GDB_FR_STATUS ", struct gdb_regs, cp0_status); ++ offset("#define GDB_FR_HI ", struct gdb_regs, hi); ++ offset("#define GDB_FR_LO ", struct gdb_regs, lo); ++#ifdef CONFIG_CPU_HAS_SMARTMIPS ++ offset("#define GDB_FR_ACX ", struct gdb_regs, acx); ++#endif ++ offset("#define GDB_FR_BADVADDR ", struct gdb_regs, cp0_badvaddr); ++ offset("#define GDB_FR_CAUSE ", struct gdb_regs, cp0_cause); ++ offset("#define GDB_FR_EPC ", struct gdb_regs, cp0_epc); ++ linefeed; ++ ++ offset("#define GDB_FR_FPR0 ", struct gdb_regs, fpr0); ++ offset("#define GDB_FR_FPR1 ", struct gdb_regs, fpr1); ++ offset("#define GDB_FR_FPR2 ", struct gdb_regs, fpr2); ++ offset("#define GDB_FR_FPR3 ", struct gdb_regs, fpr3); ++ offset("#define GDB_FR_FPR4 ", struct gdb_regs, fpr4); ++ offset("#define GDB_FR_FPR5 ", struct gdb_regs, fpr5); ++ offset("#define GDB_FR_FPR6 ", struct gdb_regs, fpr6); ++ offset("#define GDB_FR_FPR7 ", struct gdb_regs, fpr7); ++ offset("#define GDB_FR_FPR8 ", struct gdb_regs, fpr8); ++ offset("#define GDB_FR_FPR9 ", struct gdb_regs, fpr9); ++ offset("#define GDB_FR_FPR10 ", struct gdb_regs, fpr10); ++ offset("#define GDB_FR_FPR11 ", struct gdb_regs, fpr11); ++ offset("#define GDB_FR_FPR12 ", struct gdb_regs, fpr12); ++ offset("#define GDB_FR_FPR13 ", struct gdb_regs, fpr13); ++ offset("#define GDB_FR_FPR14 ", struct gdb_regs, fpr14); ++ offset("#define GDB_FR_FPR15 ", struct gdb_regs, fpr15); ++ offset("#define GDB_FR_FPR16 ", struct gdb_regs, fpr16); ++ offset("#define GDB_FR_FPR17 ", struct gdb_regs, fpr17); ++ offset("#define GDB_FR_FPR18 ", struct gdb_regs, fpr18); ++ offset("#define GDB_FR_FPR19 ", struct gdb_regs, fpr19); ++ offset("#define GDB_FR_FPR20 ", struct gdb_regs, fpr20); ++ offset("#define GDB_FR_FPR21 ", struct gdb_regs, fpr21); ++ offset("#define GDB_FR_FPR22 ", struct gdb_regs, fpr22); ++ offset("#define GDB_FR_FPR23 ", struct gdb_regs, fpr23); ++ offset("#define GDB_FR_FPR24 ", struct gdb_regs, fpr24); ++ offset("#define GDB_FR_FPR25 ", struct gdb_regs, fpr25); ++ offset("#define GDB_FR_FPR26 ", struct gdb_regs, fpr26); ++ offset("#define GDB_FR_FPR27 ", struct gdb_regs, fpr27); ++ offset("#define GDB_FR_FPR28 ", struct gdb_regs, fpr28); ++ offset("#define GDB_FR_FPR29 ", struct gdb_regs, fpr29); ++ offset("#define GDB_FR_FPR30 ", struct gdb_regs, fpr30); ++ offset("#define GDB_FR_FPR31 ", struct gdb_regs, fpr31); ++ linefeed; ++ ++ offset("#define GDB_FR_FSR ", struct gdb_regs, cp1_fsr); ++ offset("#define GDB_FR_FIR ", struct gdb_regs, cp1_fir); ++ offset("#define GDB_FR_FRP ", struct gdb_regs, frame_ptr); ++ offset("#define GDB_FR_DUMMY ", struct gdb_regs, dummy); ++ ++ offset("#define GDB_FR_CP0_INDEX ", struct gdb_regs, cp0_index); ++ offset("#define GDB_FR_CP0_RANDOM ", struct gdb_regs, cp0_random); ++ offset("#define GDB_FR_CP0_ENTRYLO0 ", struct gdb_regs, cp0_entrylo0); ++ offset("#define GDB_FR_CP0_ENTRYLO1 ", struct gdb_regs, cp0_entrylo1); ++ offset("#define GDB_FR_CP0_CONTEXT ", struct gdb_regs, cp0_context); ++ offset("#define GDB_FR_CP0_PAGEMASK ", struct gdb_regs, cp0_pagemask); ++ offset("#define GDB_FR_CP0_WIRED ", struct gdb_regs, cp0_wired); ++ offset("#define GDB_FR_CP0_REG7 ", struct gdb_regs, cp0_reg7); ++ offset("#define GDB_FR_CP0_REG8 ", struct gdb_regs, cp0_reg8); ++ offset("#define GDB_FR_CP0_REG9 ", struct gdb_regs, cp0_reg9); ++ offset("#define GDB_FR_CP0_ENTRYHI ", struct gdb_regs, cp0_entryhi); ++ offset("#define GDB_FR_CP0_REG11 ", struct gdb_regs, cp0_reg11); ++ offset("#define GDB_FR_CP0_REG12 ", struct gdb_regs, cp0_reg12); ++ offset("#define GDB_FR_CP0_REG13 ", struct gdb_regs, cp0_reg13); ++ offset("#define GDB_FR_CP0_REG14 ", struct gdb_regs, cp0_reg14); ++ offset("#define GDB_FR_CP0_PRID ", struct gdb_regs, cp0_prid); ++ size("#define GDB_FR_SIZE ", struct gdb_regs); ++} +diff -Nurd linux-2.6.24/arch/mips/kernel/cevt-r4k.c mer-smartq-kernel/arch/mips/kernel/cevt-r4k.c +--- linux-2.6.24/arch/mips/kernel/cevt-r4k.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/cevt-r4k.c 2009-11-17 12:13:29.000000000 +0100 +@@ -12,6 +12,14 @@ + + #include <asm/smtc_ipi.h> + #include <asm/time.h> ++#include <asm/cevt-r4k.h> ++ ++/* ++ * The SMTC Kernel for the 34K, 1004K, et. al. replaces several ++ * of these routines with SMTC-specific variants. ++ */ ++ ++#ifndef CONFIG_MIPS_MT_SMTC + + static int mips_next_event(unsigned long delta, + struct clock_event_device *evt) +@@ -19,60 +27,27 @@ + unsigned int cnt; + int res; + +-#ifdef CONFIG_MIPS_MT_SMTC +- { +- unsigned long flags, vpflags; +- local_irq_save(flags); +- vpflags = dvpe(); +-#endif + cnt = read_c0_count(); + cnt += delta; + write_c0_compare(cnt); + res = ((int)(read_c0_count() - cnt) > 0) ? -ETIME : 0; +-#ifdef CONFIG_MIPS_MT_SMTC +- evpe(vpflags); +- local_irq_restore(flags); +- } +-#endif + return res; + } + +-static void mips_set_mode(enum clock_event_mode mode, +- struct clock_event_device *evt) ++#endif /* CONFIG_MIPS_MT_SMTC */ ++ ++void mips_set_clock_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) + { + /* Nothing to do ... */ + } + +-static DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); +-static int cp0_timer_irq_installed; +- +-/* +- * Timer ack for an R4k-compatible timer of a known frequency. +- */ +-static void c0_timer_ack(void) +-{ +- write_c0_compare(read_c0_compare()); +-} ++DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); ++int cp0_timer_irq_installed; + +-/* +- * Possibly handle a performance counter interrupt. +- * Return true if the timer interrupt should not be checked +- */ +-static inline int handle_perf_irq(int r2) +-{ +- /* +- * The performance counter overflow interrupt may be shared with the +- * timer interrupt (cp0_perfcount_irq < 0). If it is and a +- * performance counter has overflowed (perf_irq() == IRQ_HANDLED) +- * and we can't reliably determine if a counter interrupt has also +- * happened (!r2) then don't check for a timer interrupt. +- */ +- return (cp0_perfcount_irq < 0) && +- perf_irq() == IRQ_HANDLED && +- !r2; +-} ++#ifndef CONFIG_MIPS_MT_SMTC + +-static irqreturn_t c0_compare_interrupt(int irq, void *dev_id) ++irqreturn_t c0_compare_interrupt(int irq, void *dev_id) + { + const int r2 = cpu_has_mips_r2; + struct clock_event_device *cd; +@@ -93,12 +68,8 @@ + * interrupt. Being the paranoiacs we are we check anyway. + */ + if (!r2 || (read_c0_cause() & (1 << 30))) { +- c0_timer_ack(); +-#ifdef CONFIG_MIPS_MT_SMTC +- if (cpu_data[cpu].vpe_id) +- goto out; +- cpu = 0; +-#endif ++ /* Clear Count/Compare Interrupt */ ++ write_c0_compare(read_c0_compare()); + cd = &per_cpu(mips_clockevent_device, cpu); + cd->event_handler(cd); + } +@@ -107,65 +78,16 @@ + return IRQ_HANDLED; + } + +-static struct irqaction c0_compare_irqaction = { ++#endif /* Not CONFIG_MIPS_MT_SMTC */ ++ ++struct irqaction c0_compare_irqaction = { + .handler = c0_compare_interrupt, +-#ifdef CONFIG_MIPS_MT_SMTC +- .flags = IRQF_DISABLED, +-#else + .flags = IRQF_DISABLED | IRQF_PERCPU, +-#endif + .name = "timer", + }; + +-#ifdef CONFIG_MIPS_MT_SMTC +-DEFINE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device); + +-static void smtc_set_mode(enum clock_event_mode mode, +- struct clock_event_device *evt) +-{ +-} +- +-static void mips_broadcast(cpumask_t mask) +-{ +- unsigned int cpu; +- +- for_each_cpu_mask(cpu, mask) +- smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0); +-} +- +-static void setup_smtc_dummy_clockevent_device(void) +-{ +- //uint64_t mips_freq = mips_hpt_^frequency; +- unsigned int cpu = smp_processor_id(); +- struct clock_event_device *cd; +- +- cd = &per_cpu(smtc_dummy_clockevent_device, cpu); +- +- cd->name = "SMTC"; +- cd->features = CLOCK_EVT_FEAT_DUMMY; +- +- /* Calculate the min / max delta */ +- cd->mult = 0; //div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32); +- cd->shift = 0; //32; +- cd->max_delta_ns = 0; //clockevent_delta2ns(0x7fffffff, cd); +- cd->min_delta_ns = 0; //clockevent_delta2ns(0x30, cd); +- +- cd->rating = 200; +- cd->irq = 17; //-1; +-// if (cpu) +-// cd->cpumask = CPU_MASK_ALL; // cpumask_of_cpu(cpu); +-// else +- cd->cpumask = cpumask_of_cpu(cpu); +- +- cd->set_mode = smtc_set_mode; +- +- cd->broadcast = mips_broadcast; +- +- clockevents_register_device(cd); +-} +-#endif +- +-static void mips_event_handler(struct clock_event_device *dev) ++void mips_event_handler(struct clock_event_device *dev) + { + } + +@@ -177,7 +99,23 @@ + return (read_c0_cause() >> cp0_compare_irq) & 0x100; + } + +-static int c0_compare_int_usable(void) ++/* ++ * Compare interrupt can be routed and latched outside the core, ++ * so a single execution hazard barrier may not be enough to give ++ * it time to clear as seen in the Cause register. 4 time the ++ * pipeline depth seems reasonably conservative, and empirically ++ * works better in configurations with high CPU/bus clock ratios. ++ */ ++ ++#define compare_change_hazard() \ ++ do { \ ++ irq_disable_hazard(); \ ++ irq_disable_hazard(); \ ++ irq_disable_hazard(); \ ++ irq_disable_hazard(); \ ++ } while (0) ++ ++int c0_compare_int_usable(void) + { + unsigned int delta; + unsigned int cnt; +@@ -187,7 +125,7 @@ + */ + if (c0_compare_int_pending()) { + write_c0_compare(read_c0_count()); +- irq_disable_hazard(); ++ compare_change_hazard(); + if (c0_compare_int_pending()) + return 0; + } +@@ -196,7 +134,7 @@ + cnt = read_c0_count(); + cnt += delta; + write_c0_compare(cnt); +- irq_disable_hazard(); ++ compare_change_hazard(); + if ((int)(read_c0_count() - cnt) < 0) + break; + /* increase delta if the timer was already expired */ +@@ -205,11 +143,12 @@ + while ((int)(read_c0_count() - cnt) <= 0) + ; /* Wait for expiry */ + ++ compare_change_hazard(); + if (!c0_compare_int_pending()) + return 0; + + write_c0_compare(read_c0_count()); +- irq_disable_hazard(); ++ compare_change_hazard(); + if (c0_compare_int_pending()) + return 0; + +@@ -219,6 +158,8 @@ + return 1; + } + ++#ifndef CONFIG_MIPS_MT_SMTC ++ + int __cpuinit mips_clockevent_init(void) + { + uint64_t mips_freq = mips_hpt_frequency; +@@ -229,17 +170,6 @@ + if (!cpu_has_counter || !mips_hpt_frequency) + return -ENXIO; + +-#ifdef CONFIG_MIPS_MT_SMTC +- setup_smtc_dummy_clockevent_device(); +- +- /* +- * On SMTC we only register VPE0's compare interrupt as clockevent +- * device. +- */ +- if (cpu) +- return 0; +-#endif +- + if (!c0_compare_int_usable()) + return -ENXIO; + +@@ -265,13 +195,9 @@ + + cd->rating = 300; + cd->irq = irq; +-#ifdef CONFIG_MIPS_MT_SMTC +- cd->cpumask = CPU_MASK_ALL; +-#else + cd->cpumask = cpumask_of_cpu(cpu); +-#endif + cd->set_next_event = mips_next_event; +- cd->set_mode = mips_set_mode; ++ cd->set_mode = mips_set_clock_mode; + cd->event_handler = mips_event_handler; + + clockevents_register_device(cd); +@@ -281,12 +207,9 @@ + + cp0_timer_irq_installed = 1; + +-#ifdef CONFIG_MIPS_MT_SMTC +-#define CPUCTR_IMASKBIT (0x100 << cp0_compare_irq) +- setup_irq_smtc(irq, &c0_compare_irqaction, CPUCTR_IMASKBIT); +-#else + setup_irq(irq, &c0_compare_irqaction); +-#endif + + return 0; + } ++ ++#endif /* Not CONFIG_MIPS_MT_SMTC */ +diff -Nurd linux-2.6.24/arch/mips/kernel/cevt-smtc.c mer-smartq-kernel/arch/mips/kernel/cevt-smtc.c +--- linux-2.6.24/arch/mips/kernel/cevt-smtc.c 1970-01-01 01:00:00.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/cevt-smtc.c 2009-11-17 12:13:29.000000000 +0100 +@@ -0,0 +1,321 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2007 MIPS Technologies, Inc. ++ * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org> ++ * Copyright (C) 2008 Kevin D. Kissell, Paralogos sarl ++ */ ++#include <linux/clockchips.h> ++#include <linux/interrupt.h> ++#include <linux/percpu.h> ++ ++#include <asm/smtc_ipi.h> ++#include <asm/time.h> ++#include <asm/cevt-r4k.h> ++ ++/* ++ * Variant clock event timer support for SMTC on MIPS 34K, 1004K ++ * or other MIPS MT cores. ++ * ++ * Notes on SMTC Support: ++ * ++ * SMTC has multiple microthread TCs pretending to be Linux CPUs. ++ * But there's only one Count/Compare pair per VPE, and Compare ++ * interrupts are taken opportunisitically by available TCs ++ * bound to the VPE with the Count register. The new timer ++ * framework provides for global broadcasts, but we really ++ * want VPE-level multicasts for best behavior. So instead ++ * of invoking the high-level clock-event broadcast code, ++ * this version of SMTC support uses the historical SMTC ++ * multicast mechanisms "under the hood", appearing to the ++ * generic clock layer as if the interrupts are per-CPU. ++ * ++ * The approach taken here is to maintain a set of NR_CPUS ++ * virtual timers, and track which "CPU" needs to be alerted ++ * at each event. ++ * ++ * It's unlikely that we'll see a MIPS MT core with more than ++ * 2 VPEs, but we *know* that we won't need to handle more ++ * VPEs than we have "CPUs". So NCPUs arrays of NCPUs elements ++ * is always going to be overkill, but always going to be enough. ++ */ ++ ++unsigned long smtc_nexttime[NR_CPUS][NR_CPUS]; ++static int smtc_nextinvpe[NR_CPUS]; ++ ++/* ++ * Timestamps stored are absolute values to be programmed ++ * into Count register. Valid timestamps will never be zero. ++ * If a Zero Count value is actually calculated, it is converted ++ * to be a 1, which will introduce 1 or two CPU cycles of error ++ * roughly once every four billion events, which at 1000 HZ means ++ * about once every 50 days. If that's actually a problem, one ++ * could alternate squashing 0 to 1 and to -1. ++ */ ++ ++#define MAKEVALID(x) (((x) == 0L) ? 1L : (x)) ++#define ISVALID(x) ((x) != 0L) ++ ++/* ++ * Time comparison is subtle, as it's really truncated ++ * modular arithmetic. ++ */ ++ ++#define IS_SOONER(a, b, reference) \ ++ (((a) - (unsigned long)(reference)) < ((b) - (unsigned long)(reference))) ++ ++/* ++ * CATCHUP_INCREMENT, used when the function falls behind the counter. ++ * Could be an increasing function instead of a constant; ++ */ ++ ++#define CATCHUP_INCREMENT 64 ++ ++static int mips_next_event(unsigned long delta, ++ struct clock_event_device *evt) ++{ ++ unsigned long flags; ++ unsigned int mtflags; ++ unsigned long timestamp, reference, previous; ++ unsigned long nextcomp = 0L; ++ int vpe = current_cpu_data.vpe_id; ++ int cpu = smp_processor_id(); ++ local_irq_save(flags); ++ mtflags = dmt(); ++ ++ /* ++ * Maintain the per-TC virtual timer ++ * and program the per-VPE shared Count register ++ * as appropriate here... ++ */ ++ reference = (unsigned long)read_c0_count(); ++ timestamp = MAKEVALID(reference + delta); ++ /* ++ * To really model the clock, we have to catch the case ++ * where the current next-in-VPE timestamp is the old ++ * timestamp for the calling CPE, but the new value is ++ * in fact later. In that case, we have to do a full ++ * scan and discover the new next-in-VPE CPU id and ++ * timestamp. ++ */ ++ previous = smtc_nexttime[vpe][cpu]; ++ if (cpu == smtc_nextinvpe[vpe] && ISVALID(previous) ++ && IS_SOONER(previous, timestamp, reference)) { ++ int i; ++ int soonest = cpu; ++ ++ /* ++ * Update timestamp array here, so that new ++ * value gets considered along with those of ++ * other virtual CPUs on the VPE. ++ */ ++ smtc_nexttime[vpe][cpu] = timestamp; ++ for_each_online_cpu(i) { ++ if (ISVALID(smtc_nexttime[vpe][i]) ++ && IS_SOONER(smtc_nexttime[vpe][i], ++ smtc_nexttime[vpe][soonest], reference)) { ++ soonest = i; ++ } ++ } ++ smtc_nextinvpe[vpe] = soonest; ++ nextcomp = smtc_nexttime[vpe][soonest]; ++ /* ++ * Otherwise, we don't have to process the whole array rank, ++ * we just have to see if the event horizon has gotten closer. ++ */ ++ } else { ++ if (!ISVALID(smtc_nexttime[vpe][smtc_nextinvpe[vpe]]) || ++ IS_SOONER(timestamp, ++ smtc_nexttime[vpe][smtc_nextinvpe[vpe]], reference)) { ++ smtc_nextinvpe[vpe] = cpu; ++ nextcomp = timestamp; ++ } ++ /* ++ * Since next-in-VPE may me the same as the executing ++ * virtual CPU, we update the array *after* checking ++ * its value. ++ */ ++ smtc_nexttime[vpe][cpu] = timestamp; ++ } ++ ++ /* ++ * It may be that, in fact, we don't need to update Compare, ++ * but if we do, we want to make sure we didn't fall into ++ * a crack just behind Count. ++ */ ++ if (ISVALID(nextcomp)) { ++ write_c0_compare(nextcomp); ++ ehb(); ++ /* ++ * We never return an error, we just make sure ++ * that we trigger the handlers as quickly as ++ * we can if we fell behind. ++ */ ++ while ((nextcomp - (unsigned long)read_c0_count()) ++ > (unsigned long)LONG_MAX) { ++ nextcomp += CATCHUP_INCREMENT; ++ write_c0_compare(nextcomp); ++ ehb(); ++ } ++ } ++ emt(mtflags); ++ local_irq_restore(flags); ++ return 0; ++} ++ ++ ++void smtc_distribute_timer(int vpe) ++{ ++ unsigned long flags; ++ unsigned int mtflags; ++ int cpu; ++ struct clock_event_device *cd; ++ unsigned long nextstamp = 0L; ++ unsigned long reference; ++ ++ ++repeat: ++ for_each_online_cpu(cpu) { ++ /* ++ * Find virtual CPUs within the current VPE who have ++ * unserviced timer requests whose time is now past. ++ */ ++ local_irq_save(flags); ++ mtflags = dmt(); ++ if (cpu_data[cpu].vpe_id == vpe && ++ ISVALID(smtc_nexttime[vpe][cpu])) { ++ reference = (unsigned long)read_c0_count(); ++ if ((smtc_nexttime[vpe][cpu] - reference) ++ > (unsigned long)LONG_MAX) { ++ smtc_nexttime[vpe][cpu] = 0L; ++ emt(mtflags); ++ local_irq_restore(flags); ++ /* ++ * We don't send IPIs to ourself. ++ */ ++ if (cpu != smp_processor_id()) { ++ smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0); ++ } else { ++ cd = &per_cpu(mips_clockevent_device, cpu); ++ cd->event_handler(cd); ++ } ++ } else { ++ /* Local to VPE but Valid Time not yet reached. */ ++ if (!ISVALID(nextstamp) || ++ IS_SOONER(smtc_nexttime[vpe][cpu], nextstamp, ++ reference)) { ++ smtc_nextinvpe[vpe] = cpu; ++ nextstamp = smtc_nexttime[vpe][cpu]; ++ } ++ emt(mtflags); ++ local_irq_restore(flags); ++ } ++ } else { ++ emt(mtflags); ++ local_irq_restore(flags); ++ ++ } ++ } ++ /* Reprogram for interrupt at next soonest timestamp for VPE */ ++ if (ISVALID(nextstamp)) { ++ write_c0_compare(nextstamp); ++ ehb(); ++ if ((nextstamp - (unsigned long)read_c0_count()) ++ > (unsigned long)LONG_MAX) ++ goto repeat; ++ } ++} ++ ++ ++irqreturn_t c0_compare_interrupt(int irq, void *dev_id) ++{ ++ int cpu = smp_processor_id(); ++ ++ /* If we're running SMTC, we've got MIPS MT and therefore MIPS32R2 */ ++ handle_perf_irq(1); ++ ++ if (read_c0_cause() & (1 << 30)) { ++ /* Clear Count/Compare Interrupt */ ++ write_c0_compare(read_c0_compare()); ++ smtc_distribute_timer(cpu_data[cpu].vpe_id); ++ } ++ return IRQ_HANDLED; ++} ++ ++ ++int __cpuinit mips_clockevent_init(void) ++{ ++ uint64_t mips_freq = mips_hpt_frequency; ++ unsigned int cpu = smp_processor_id(); ++ struct clock_event_device *cd; ++ unsigned int irq; ++ int i; ++ int j; ++ ++ if (!cpu_has_counter || !mips_hpt_frequency) ++ return -ENXIO; ++ if (cpu == 0) { ++ for (i = 0; i < num_possible_cpus(); i++) { ++ smtc_nextinvpe[i] = 0; ++ for (j = 0; j < num_possible_cpus(); j++) ++ smtc_nexttime[i][j] = 0L; ++ } ++ /* ++ * SMTC also can't have the usablility test ++ * run by secondary TCs once Compare is in use. ++ */ ++ if (!c0_compare_int_usable()) ++ return -ENXIO; ++ } ++ ++ /* ++ * With vectored interrupts things are getting platform specific. ++ * get_c0_compare_int is a hook to allow a platform to return the ++ * interrupt number of it's liking. ++ */ ++ irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; ++ if (get_c0_compare_int) ++ irq = get_c0_compare_int(); ++ ++ cd = &per_cpu(mips_clockevent_device, cpu); ++ ++ cd->name = "MIPS"; ++ cd->features = CLOCK_EVT_FEAT_ONESHOT; ++ ++ /* Calculate the min / max delta */ ++ cd->mult = div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32); ++ cd->shift = 32; ++ cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); ++ cd->min_delta_ns = clockevent_delta2ns(0x300, cd); ++ ++ cd->rating = 300; ++ cd->irq = irq; ++ cd->cpumask = cpumask_of_cpu(cpu); ++ cd->set_next_event = mips_next_event; ++ cd->set_mode = mips_set_clock_mode; ++ cd->event_handler = mips_event_handler; ++ ++ clockevents_register_device(cd); ++ ++ /* ++ * On SMTC we only want to do the data structure ++ * initialization and IRQ setup once. ++ */ ++ if (cpu) ++ return 0; ++ /* ++ * And we need the hwmask associated with the c0_compare ++ * vector to be initialized. ++ */ ++ irq_hwmask[irq] = (0x100 << cp0_compare_irq); ++ if (cp0_timer_irq_installed) ++ return 0; ++ ++ cp0_timer_irq_installed = 1; ++ ++ setup_irq(irq, &c0_compare_irqaction); ++ ++ return 0; ++} +diff -Nurd linux-2.6.24/arch/mips/kernel/cevt-txx9.c mer-smartq-kernel/arch/mips/kernel/cevt-txx9.c +--- linux-2.6.24/arch/mips/kernel/cevt-txx9.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/cevt-txx9.c 2009-11-17 12:13:29.000000000 +0100 +@@ -161,6 +161,9 @@ + struct txx9_tmr_reg __iomem *tmrptr; + + tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg)); ++ /* Start once to make CounterResetEnable effective */ ++ __raw_writel(TXx9_TMTCR_CRE | TXx9_TMTCR_TCE, &tmrptr->tcr); ++ /* Stop and reset the counter */ + __raw_writel(TXx9_TMTCR_CRE, &tmrptr->tcr); + __raw_writel(0, &tmrptr->tisr); + __raw_writel(0xffffffff, &tmrptr->cpra); +diff -Nurd linux-2.6.24/arch/mips/kernel/cpu-bugs64.c mer-smartq-kernel/arch/mips/kernel/cpu-bugs64.c +--- linux-2.6.24/arch/mips/kernel/cpu-bugs64.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/cpu-bugs64.c 2009-11-17 12:13:29.000000000 +0100 +@@ -164,7 +164,7 @@ + ); + } + +-static volatile int daddi_ov __initdata = 0; ++static volatile int daddi_ov __cpuinitdata = 0; + + asmlinkage void __init do_daddi_ov(struct pt_regs *regs) + { +diff -Nurd linux-2.6.24/arch/mips/kernel/cpu-probe.c mer-smartq-kernel/arch/mips/kernel/cpu-probe.c +--- linux-2.6.24/arch/mips/kernel/cpu-probe.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/cpu-probe.c 2009-11-17 12:13:29.000000000 +0100 +@@ -45,18 +45,7 @@ + local_irq_enable(); + } + +-/* +- * There is a race when WAIT instruction executed with interrupt +- * enabled. +- * But it is implementation-dependent wheter the pipelie restarts when +- * a non-enabled interrupt is requested. +- */ +-static void r4k_wait(void) +-{ +- __asm__(" .set mips3 \n" +- " wait \n" +- " .set mips0 \n"); +-} ++extern void r4k_wait(void); + + /* + * This variant is preferable as it allows testing need_resched and going to +@@ -65,14 +54,18 @@ + * interrupt is requested" restriction in the MIPS32/MIPS64 architecture makes + * using this version a gamble. + */ +-static void r4k_wait_irqoff(void) ++void r4k_wait_irqoff(void) + { + local_irq_disable(); + if (!need_resched()) +- __asm__(" .set mips3 \n" ++ __asm__(" .set push \n" ++ " .set mips3 \n" + " wait \n" +- " .set mips0 \n"); ++ " .set pop \n"); + local_irq_enable(); ++ __asm__(" .globl __pastwait \n" ++ "__pastwait: \n"); ++ return; + } + + /* +@@ -128,7 +121,7 @@ + + __setup("nowait", wait_disable); + +-static inline void check_wait(void) ++void __init check_wait(void) + { + struct cpuinfo_mips *c = ¤t_cpu_data; + +@@ -239,7 +232,6 @@ + + void __init check_bugs32(void) + { +- check_wait(); + check_errata(); + } + +@@ -548,7 +540,7 @@ + } + } + +-static char unknown_isa[] __initdata = KERN_ERR \ ++static char unknown_isa[] __cpuinitdata = KERN_ERR \ + "Unsupported ISA type, c0.config0: %d."; + + static inline unsigned int decode_config0(struct cpuinfo_mips *c) +@@ -654,7 +646,7 @@ + return config3 & MIPS_CONF_M; + } + +-static void __init decode_configs(struct cpuinfo_mips *c) ++static void __cpuinit decode_configs(struct cpuinfo_mips *c) + { + /* MIPS32 or MIPS64 compliant CPU. */ + c->options = MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER | +@@ -807,7 +799,7 @@ + /* + * Name a CPU + */ +-static __init const char *cpu_to_name(struct cpuinfo_mips *c) ++static __cpuinit const char *cpu_to_name(struct cpuinfo_mips *c) + { + const char *name = NULL; + +@@ -887,7 +879,7 @@ + return name; + } + +-__init void cpu_probe(void) ++__cpuinit void cpu_probe(void) + { + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int cpu = smp_processor_id(); +@@ -950,7 +942,7 @@ + c->srsets = 1; + } + +-__init void cpu_report(void) ++__cpuinit void cpu_report(void) + { + struct cpuinfo_mips *c = ¤t_cpu_data; + +diff -Nurd linux-2.6.24/arch/mips/kernel/csrc-r4k.c mer-smartq-kernel/arch/mips/kernel/csrc-r4k.c +--- linux-2.6.24/arch/mips/kernel/csrc-r4k.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/csrc-r4k.c 2009-11-17 12:13:29.000000000 +0100 +@@ -22,12 +22,17 @@ + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }; + +-void __init init_mips_clocksource(void) ++int __init init_mips_clocksource(void) + { +- /* Calclate a somewhat reasonable rating value */ ++ if (!cpu_has_counter || !mips_hpt_frequency) ++ return -ENXIO; ++ ++ /* Calculate a somewhat reasonable rating value */ + clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; + + clocksource_set_clock(&clocksource_mips, mips_hpt_frequency); + + clocksource_register(&clocksource_mips); ++ ++ return 0; + } +diff -Nurd linux-2.6.24/arch/mips/kernel/entry.S mer-smartq-kernel/arch/mips/kernel/entry.S +--- linux-2.6.24/arch/mips/kernel/entry.S 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/entry.S 2009-11-17 12:13:29.000000000 +0100 +@@ -79,11 +79,6 @@ + + FEXPORT(restore_all) # restore full frame + #ifdef CONFIG_MIPS_MT_SMTC +-/* Detect and execute deferred IPI "interrupts" */ +- LONG_L s0, TI_REGS($28) +- LONG_S sp, TI_REGS($28) +- jal deferred_smtc_ipi +- LONG_S s0, TI_REGS($28) + #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP + /* Re-arm any temporarily masked interrupts not explicitly "acked" */ + mfc0 v0, CP0_TCSTATUS +@@ -112,6 +107,11 @@ + xor t0, t0, t3 + mtc0 t0, CP0_TCCONTEXT + #endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */ ++/* Detect and execute deferred IPI "interrupts" */ ++ LONG_L s0, TI_REGS($28) ++ LONG_S sp, TI_REGS($28) ++ jal deferred_smtc_ipi ++ LONG_S s0, TI_REGS($28) + #endif /* CONFIG_MIPS_MT_SMTC */ + .set noat + RESTORE_TEMP +diff -Nurd linux-2.6.24/arch/mips/kernel/gdb-low.S mer-smartq-kernel/arch/mips/kernel/gdb-low.S +--- linux-2.6.24/arch/mips/kernel/gdb-low.S 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/gdb-low.S 2009-11-17 12:13:29.000000000 +0100 +@@ -9,21 +9,21 @@ + #include <asm/errno.h> + #include <asm/irqflags.h> + #include <asm/mipsregs.h> ++#include <asm/asm-offsets.h> + #include <asm/regdef.h> + #include <asm/stackframe.h> +-#include <asm/gdb-stub.h> + + #ifdef CONFIG_32BIT + #define DMFC0 mfc0 + #define DMTC0 mtc0 + #define LDC1 lwc1 +-#define SDC1 lwc1 ++#define SDC1 swc1 + #endif + #ifdef CONFIG_64BIT + #define DMFC0 dmfc0 + #define DMTC0 dmtc0 + #define LDC1 ldc1 +-#define SDC1 ldc1 ++#define SDC1 sdc1 + #endif + + /* +@@ -78,10 +78,19 @@ + LONG_S v0, GDB_FR_EPC(sp) + DMFC0 v0, CP0_BADVADDR + LONG_S v0, GDB_FR_BADVADDR(sp) ++#ifdef CONFIG_CPU_HAS_SMARTMIPS ++ mflhxu v0 ++ LONG_S v0, GDB_FR_LO(sp) ++ mflhxu v0 ++ LONG_S v0, GDB_FR_HI(sp) ++ mflhxu v0 ++ LONG_S v0, GDB_FR_ACX(sp) ++#else + mfhi v0 + LONG_S v0, GDB_FR_HI(sp) + mflo v0 + LONG_S v0, GDB_FR_LO(sp) ++#endif + + /* + * Now the integer registers +@@ -317,10 +326,19 @@ + LONG_L v1, GDB_FR_EPC(sp) + mtc0 v0, CP0_STATUS + DMTC0 v1, CP0_EPC ++#ifdef CONFIG_CPU_HAS_SMARTMIPS ++ LONG_L v0, GDB_FR_ACX(sp) ++ mtlhx v0 ++ LONG_L v0, GDB_FR_HI(sp) ++ mtlhx v0 ++ LONG_L v0, GDB_FR_LO(sp) ++ mtlhx v0 ++#else + LONG_L v0, GDB_FR_HI(sp) + LONG_L v1, GDB_FR_LO(sp) + mthi v0 + mtlo v1 ++#endif + LONG_L $31, GDB_FR_REG31(sp) + LONG_L $30, GDB_FR_REG30(sp) + LONG_L $28, GDB_FR_REG28(sp) +diff -Nurd linux-2.6.24/arch/mips/kernel/gdb-stub.c mer-smartq-kernel/arch/mips/kernel/gdb-stub.c +--- linux-2.6.24/arch/mips/kernel/gdb-stub.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/gdb-stub.c 2009-11-17 12:13:29.000000000 +0100 +@@ -139,7 +139,6 @@ + #include <asm/system.h> + #include <asm/gdb-stub.h> + #include <asm/inst.h> +-#include <asm/smp.h> + + /* + * external low-level support routines +@@ -656,6 +655,7 @@ + *epc = (unsigned long)async_breakpoint; + } + ++#ifdef CONFIG_SMP + static void kgdb_wait(void *arg) + { + unsigned flags; +@@ -668,6 +668,7 @@ + + local_irq_restore(flags); + } ++#endif + + /* + * GDB stub needs to call kgdb_wait on all processor with interrupts +diff -Nurd linux-2.6.24/arch/mips/kernel/genex.S mer-smartq-kernel/arch/mips/kernel/genex.S +--- linux-2.6.24/arch/mips/kernel/genex.S 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/genex.S 2009-11-17 12:13:29.000000000 +0100 +@@ -20,6 +20,7 @@ + #include <asm/stackframe.h> + #include <asm/war.h> + #include <asm/page.h> ++#include <asm/thread_info.h> + + #define PANIC_PIC(msg) \ + .set push; \ +@@ -126,7 +127,42 @@ + + __FINIT + ++ .align 5 /* 32 byte rollback region */ ++LEAF(r4k_wait) ++ .set push ++ .set noreorder ++ /* start of rollback region */ ++ LONG_L t0, TI_FLAGS($28) ++ nop ++ andi t0, _TIF_NEED_RESCHED ++ bnez t0, 1f ++ nop ++ nop ++ nop ++ .set mips3 ++ wait ++ /* end of rollback region (the region size must be power of two) */ ++ .set pop ++1: ++ jr ra ++ END(r4k_wait) ++ ++ .macro BUILD_ROLLBACK_PROLOGUE handler ++ FEXPORT(rollback_\handler) ++ .set push ++ .set noat ++ MFC0 k0, CP0_EPC ++ PTR_LA k1, r4k_wait ++ ori k0, 0x1f /* 32 byte rollback region */ ++ xori k0, 0x1f ++ bne k0, k1, 9f ++ MTC0 k0, CP0_EPC ++9: ++ .set pop ++ .endm ++ + .align 5 ++BUILD_ROLLBACK_PROLOGUE handle_int + NESTED(handle_int, PT_SIZE, sp) + #ifdef CONFIG_TRACE_IRQFLAGS + /* +@@ -201,6 +237,7 @@ + * This prototype is copied to ebase + n*IntCtl.VS and patched + * to invoke the handler + */ ++BUILD_ROLLBACK_PROLOGUE except_vec_vi + NESTED(except_vec_vi, 0, sp) + SAVE_SOME + SAVE_AT +@@ -245,8 +282,8 @@ + and t0, a0, t1 + #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP + mfc0 t2, CP0_TCCONTEXT +- or t0, t0, t2 +- mtc0 t0, CP0_TCCONTEXT ++ or t2, t0, t2 ++ mtc0 t2, CP0_TCCONTEXT + #endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */ + xor t1, t1, t0 + mtc0 t1, CP0_STATUS +diff -Nurd linux-2.6.24/arch/mips/kernel/head.S mer-smartq-kernel/arch/mips/kernel/head.S +--- linux-2.6.24/arch/mips/kernel/head.S 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/head.S 2009-11-17 12:13:29.000000000 +0100 +@@ -22,6 +22,7 @@ + #include <asm/irqflags.h> + #include <asm/regdef.h> + #include <asm/page.h> ++#include <asm/pgtable-bits.h> + #include <asm/mipsregs.h> + #include <asm/stackframe.h> + +@@ -194,8 +195,11 @@ + + j start_kernel + END(kernel_entry) ++ __FINIT + ++#ifndef CONFIG_HOTPLUG_CPU + __INIT ++#endif + + #ifdef CONFIG_SMP + /* +diff -Nurd linux-2.6.24/arch/mips/kernel/i8253.c mer-smartq-kernel/arch/mips/kernel/i8253.c +--- linux-2.6.24/arch/mips/kernel/i8253.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/i8253.c 2009-11-17 12:13:29.000000000 +0100 +@@ -15,6 +15,7 @@ + #include <asm/time.h> + + DEFINE_SPINLOCK(i8253_lock); ++EXPORT_SYMBOL(i8253_lock); + + /* + * Initialize the PIT timer. +diff -Nurd linux-2.6.24/arch/mips/kernel/irixelf.c mer-smartq-kernel/arch/mips/kernel/irixelf.c +--- linux-2.6.24/arch/mips/kernel/irixelf.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/irixelf.c 2009-11-17 12:13:29.000000000 +0100 +@@ -578,7 +578,7 @@ + * process and the system, here we map the page and fill the + * structure + */ +-static void irix_map_prda_page(void) ++static int irix_map_prda_page(void) + { + unsigned long v; + struct prda *pp; +@@ -587,8 +587,8 @@ + v = do_brk(PRDA_ADDRESS, PAGE_SIZE); + up_write(¤t->mm->mmap_sem); + +- if (v < 0) +- return; ++ if (v != PRDA_ADDRESS) ++ return v; /* v must be an error code */ + + pp = (struct prda *) v; + pp->prda_sys.t_pid = current->pid; +@@ -596,6 +596,8 @@ + pp->prda_sys.t_rpid = current->pid; + + /* We leave the rest set to zero */ ++ ++ return 0; + } + + +@@ -781,7 +783,8 @@ + * IRIX maps a page at 0x200000 which holds some system + * information. Programs depend on this. + */ +- irix_map_prda_page(); ++ if (irix_map_prda_page()) ++ goto out_free_dentry; + + padzero(elf_bss); + +diff -Nurd linux-2.6.24/arch/mips/kernel/irq-rm7000.c mer-smartq-kernel/arch/mips/kernel/irq-rm7000.c +--- linux-2.6.24/arch/mips/kernel/irq-rm7000.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/irq-rm7000.c 2009-11-17 12:13:29.000000000 +0100 +@@ -33,6 +33,7 @@ + .mask = mask_rm7k_irq, + .mask_ack = mask_rm7k_irq, + .unmask = unmask_rm7k_irq, ++ .eoi = unmask_rm7k_irq + }; + + void __init rm7k_cpu_irq_init(void) +diff -Nurd linux-2.6.24/arch/mips/kernel/irq-rm9000.c mer-smartq-kernel/arch/mips/kernel/irq-rm9000.c +--- linux-2.6.24/arch/mips/kernel/irq-rm9000.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/irq-rm9000.c 2009-11-17 12:13:29.000000000 +0100 +@@ -75,6 +75,7 @@ + .mask = mask_rm9k_irq, + .mask_ack = mask_rm9k_irq, + .unmask = unmask_rm9k_irq, ++ .eoi = unmask_rm9k_irq + }; + + static struct irq_chip rm9k_perfcounter_irq = { +diff -Nurd linux-2.6.24/arch/mips/kernel/kspd.c mer-smartq-kernel/arch/mips/kernel/kspd.c +--- linux-2.6.24/arch/mips/kernel/kspd.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/kspd.c 2009-11-17 12:13:29.000000000 +0100 +@@ -257,7 +257,7 @@ + + vcwd = vpe_getcwd(tclimit); + +- /* change to the cwd of the process that loaded the SP program */ ++ /* change to cwd of the process that loaded the SP program */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + sys_chdir(vcwd); +@@ -323,6 +323,9 @@ + set >>= 1; + } + } ++ ++ /* Put daemon cwd back to root to avoid umount problems */ ++ sys_chdir("/"); + } + + static int channel_open = 0; +diff -Nurd linux-2.6.24/arch/mips/kernel/Makefile mer-smartq-kernel/arch/mips/kernel/Makefile +--- linux-2.6.24/arch/mips/kernel/Makefile 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/Makefile 2009-11-17 12:13:29.000000000 +0100 +@@ -10,6 +10,7 @@ + + obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o + obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o ++obj-$(CONFIG_MIPS_MT_SMTC) += cevt-smtc.o + obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o + obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o + obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o +@@ -51,9 +52,9 @@ + obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o + obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o + +-obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o + obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o + obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o ++obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o + + obj-$(CONFIG_I8259) += i8259.o + obj-$(CONFIG_IRQ_CPU) += irq_cpu.o +diff -Nurd linux-2.6.24/arch/mips/kernel/mips-mt-fpaff.c mer-smartq-kernel/arch/mips/kernel/mips-mt-fpaff.c +--- linux-2.6.24/arch/mips/kernel/mips-mt-fpaff.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/mips-mt-fpaff.c 2009-11-17 12:13:29.000000000 +0100 +@@ -36,7 +36,7 @@ + */ + static inline struct task_struct *find_process_by_pid(pid_t pid) + { +- return pid ? find_task_by_pid(pid) : current; ++ return pid ? find_task_by_vpid(pid) : current; + } + + +@@ -159,7 +159,7 @@ + /* + * FPU Use Factor empirically derived from experiments on 34K + */ +-#define FPUSEFACTOR 333 ++#define FPUSEFACTOR 2000 + + static __init int mt_fp_affinity_init(void) + { +diff -Nurd linux-2.6.24/arch/mips/kernel/proc.c mer-smartq-kernel/arch/mips/kernel/proc.c +--- linux-2.6.24/arch/mips/kernel/proc.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/proc.c 2009-11-17 12:13:29.000000000 +0100 +@@ -38,7 +38,7 @@ + seq_printf(m, "processor\t\t: %ld\n", n); + sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", + cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : ""); +- seq_printf(m, fmt, __cpu_name[smp_processor_id()], ++ seq_printf(m, fmt, __cpu_name[n], + (version >> 4) & 0x0f, version & 0x0f, + (fp_vers >> 4) & 0x0f, fp_vers & 0x0f); + seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n", +diff -Nurd linux-2.6.24/arch/mips/kernel/process.c mer-smartq-kernel/arch/mips/kernel/process.c +--- linux-2.6.24/arch/mips/kernel/process.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/process.c 2009-11-17 12:13:29.000000000 +0100 +@@ -55,7 +55,7 @@ + while (1) { + tick_nohz_stop_sched_tick(); + while (!need_resched()) { +-#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG ++#ifdef CONFIG_MIPS_MT_SMTC + extern void smtc_idle_loop_hook(void); + + smtc_idle_loop_hook(); +@@ -152,17 +152,18 @@ + */ + p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1); + childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); +- clear_tsk_thread_flag(p, TIF_USEDFPU); + +-#ifdef CONFIG_MIPS_MT_FPAFF ++#ifdef CONFIG_MIPS_MT_SMTC + /* +- * FPU affinity support is cleaner if we track the +- * user-visible CPU affinity from the very beginning. +- * The generic cpus_allowed mask will already have +- * been copied from the parent before copy_thread +- * is invoked. ++ * SMTC restores TCStatus after Status, and the CU bits ++ * are aliased there. + */ +- p->thread.user_cpus_allowed = p->cpus_allowed; ++ childregs->cp0_tcstatus &= ~(ST0_CU2|ST0_CU1); ++#endif ++ clear_tsk_thread_flag(p, TIF_USEDFPU); ++ ++#ifdef CONFIG_MIPS_MT_FPAFF ++ clear_tsk_thread_flag(p, TIF_FPUBOUND); + #endif /* CONFIG_MIPS_MT_FPAFF */ + + if (clone_flags & CLONE_SETTLS) +diff -Nurd linux-2.6.24/arch/mips/kernel/ptrace.c mer-smartq-kernel/arch/mips/kernel/ptrace.c +--- linux-2.6.24/arch/mips/kernel/ptrace.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/ptrace.c 2009-11-17 12:13:29.000000000 +0100 +@@ -238,7 +238,7 @@ + case FPC_EIR: { /* implementation / version register */ + unsigned int flags; + #ifdef CONFIG_MIPS_MT_SMTC +- unsigned int irqflags; ++ unsigned long irqflags; + unsigned int mtflags; + #endif /* CONFIG_MIPS_MT_SMTC */ + +diff -Nurd linux-2.6.24/arch/mips/kernel/rtlx.c mer-smartq-kernel/arch/mips/kernel/rtlx.c +--- linux-2.6.24/arch/mips/kernel/rtlx.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/rtlx.c 2009-11-17 12:13:29.000000000 +0100 +@@ -73,6 +73,15 @@ + static irqreturn_t rtlx_interrupt(int irq, void *dev_id) + { + int i; ++ unsigned int flags, vpeflags; ++ ++ /* Ought not to be strictly necessary for SMTC builds */ ++ local_irq_save(flags); ++ vpeflags = dvpe(); ++ set_c0_status(0x100 << MIPS_CPU_RTLX_IRQ); ++ irq_enable_hazard(); ++ evpe(vpeflags); ++ local_irq_restore(flags); + + for (i = 0; i < RTLX_CHANNELS; i++) { + wake_up(&channel_wqs[i].lx_queue); +@@ -109,7 +118,8 @@ + static int rtlx_init(struct rtlx_info *rtlxi) + { + if (rtlxi->id != RTLX_ID) { +- printk(KERN_ERR "no valid RTLX id at 0x%p 0x%lx\n", rtlxi, rtlxi->id); ++ printk(KERN_ERR "no valid RTLX id at 0x%p 0x%lx\n", ++ rtlxi, rtlxi->id); + return -ENOEXEC; + } + +@@ -163,18 +173,17 @@ + + if (rtlx == NULL) { + if( (p = vpe_get_shared(tclimit)) == NULL) { +- if (can_sleep) { +- __wait_event_interruptible(channel_wqs[index].lx_queue, +- (p = vpe_get_shared(tclimit)), +- ret); +- if (ret) +- goto out_fail; +- } else { +- printk(KERN_DEBUG "No SP program loaded, and device " +- "opened with O_NONBLOCK\n"); +- ret = -ENOSYS; ++ if (can_sleep) { ++ __wait_event_interruptible(channel_wqs[index].lx_queue, ++ (p = vpe_get_shared(tclimit)), ret); ++ if (ret) + goto out_fail; +- } ++ } else { ++ printk(KERN_DEBUG "No SP program loaded, and device " ++ "opened with O_NONBLOCK\n"); ++ ret = -ENOSYS; ++ goto out_fail; ++ } + } + + smp_rmb(); +@@ -183,7 +192,9 @@ + DEFINE_WAIT(wait); + + for (;;) { +- prepare_to_wait(&channel_wqs[index].lx_queue, &wait, TASK_INTERRUPTIBLE); ++ prepare_to_wait( ++ &channel_wqs[index].lx_queue, ++ &wait, TASK_INTERRUPTIBLE); + smp_rmb(); + if (*p != NULL) + break; +@@ -196,7 +207,7 @@ + } + finish_wait(&channel_wqs[index].lx_queue, &wait); + } else { +- printk(" *vpe_get_shared is NULL. " ++ pr_err(" *vpe_get_shared is NULL. " + "Has an SP program been loaded?\n"); + ret = -ENOSYS; + goto out_fail; +@@ -204,8 +215,9 @@ + } + + if ((unsigned int)*p < KSEG0) { +- printk(KERN_WARNING "vpe_get_shared returned an invalid pointer " +- "maybe an error code %d\n", (int)*p); ++ printk(KERN_WARNING "vpe_get_shared returned an " ++ "invalid pointer maybe an error code %d\n", ++ (int)*p); + ret = -ENOSYS; + goto out_fail; + } +@@ -233,6 +245,10 @@ + + int rtlx_release(int index) + { ++ if (rtlx == NULL) { ++ pr_err("rtlx_release() with null rtlx\n"); ++ return 0; ++ } + rtlx->channel[index].lx_state = RTLX_STATE_UNUSED; + return 0; + } +@@ -252,8 +268,8 @@ + int ret = 0; + + __wait_event_interruptible(channel_wqs[index].lx_queue, +- chan->lx_read != chan->lx_write || sp_stopping, +- ret); ++ (chan->lx_read != chan->lx_write) || ++ sp_stopping, ret); + if (ret) + return ret; + +@@ -283,7 +299,9 @@ + unsigned int rtlx_write_poll(int index) + { + struct rtlx_channel *chan = &rtlx->channel[index]; +- return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size); ++ ++ return write_spacefree(chan->rt_read, chan->rt_write, ++ chan->buffer_size); + } + + ssize_t rtlx_read(int index, void __user *buff, size_t count) +@@ -345,8 +363,8 @@ + rt_read = rt->rt_read; + + /* total number of bytes to copy */ +- count = min(count, +- (size_t)write_spacefree(rt_read, rt->rt_write, rt->buffer_size)); ++ count = min(count, (size_t)write_spacefree(rt_read, rt->rt_write, ++ rt->buffer_size)); + + /* first bit from write pointer to the end of the buffer, or count */ + fl = min(count, (size_t) rt->buffer_size - rt->rt_write); +@@ -515,6 +533,11 @@ + + if (cpu_has_vint) + set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch); ++ else { ++ pr_err("APRP RTLX init on non-vectored-interrupt processor\n"); ++ err = -ENODEV; ++ goto out_chrdev; ++ } + + rtlx_irq.dev_id = rtlx; + setup_irq(rtlx_irq_num, &rtlx_irq); +diff -Nurd linux-2.6.24/arch/mips/kernel/scall32-o32.S mer-smartq-kernel/arch/mips/kernel/scall32-o32.S +--- linux-2.6.24/arch/mips/kernel/scall32-o32.S 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/scall32-o32.S 2009-11-17 12:13:29.000000000 +0100 +@@ -184,7 +184,7 @@ + * The system call does not exist in this kernel + */ + illegal_syscall: +- li v0, -ENOSYS # error ++ li v0, ENOSYS # error + sw v0, PT_R2(sp) + li t0, 1 # set error flag + sw t0, PT_R7(sp) +@@ -270,18 +270,11 @@ + subu t0, a0, __NR_O32_Linux # check syscall number + sltiu v0, t0, __NR_O32_Linux_syscalls + 1 + #endif ++ beqz t0, einval # do not recurse + sll t1, t0, 3 + beqz v0, einval +- + lw t2, sys_call_table(t1) # syscall routine + +-#if defined(CONFIG_BINFMT_IRIX) +- li v1, 4000 # nr of sys_syscall +-#else +- li v1, 4000 - __NR_O32_Linux # index of sys_syscall +-#endif +- beq t0, v1, einval # do not recurse +- + /* Some syscalls like execve get their arguments from struct pt_regs + and claim zero arguments in the syscall table. Thus we have to + assume the worst case and shuffle around all potential arguments. +@@ -305,7 +298,7 @@ + jr t2 + /* Unreached */ + +-einval: li v0, -EINVAL ++einval: li v0, -ENOSYS + jr ra + END(sys_syscall) + +@@ -646,7 +639,7 @@ + sys sys_pselect6 6 + sys sys_ppoll 5 + sys sys_unshare 1 +- sys sys_splice 4 ++ sys sys_splice 6 + sys sys_sync_file_range 7 /* 4305 */ + sys sys_tee 4 + sys sys_vmsplice 4 +diff -Nurd linux-2.6.24/arch/mips/kernel/scall64-64.S mer-smartq-kernel/arch/mips/kernel/scall64-64.S +--- linux-2.6.24/arch/mips/kernel/scall64-64.S 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/scall64-64.S 2009-11-17 12:13:29.000000000 +0100 +@@ -117,7 +117,7 @@ + + illegal_syscall: + /* This also isn't a 64-bit syscall, throw an error. */ +- li v0, -ENOSYS # error ++ li v0, ENOSYS # error + sd v0, PT_R2(sp) + li t0, 1 # set error flag + sd t0, PT_R7(sp) +diff -Nurd linux-2.6.24/arch/mips/kernel/scall64-n32.S mer-smartq-kernel/arch/mips/kernel/scall64-n32.S +--- linux-2.6.24/arch/mips/kernel/scall64-n32.S 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/scall64-n32.S 2009-11-17 12:13:29.000000000 +0100 +@@ -390,7 +390,7 @@ + PTR sys_splice + PTR sys_sync_file_range + PTR sys_tee +- PTR sys_vmsplice /* 6270 */ ++ PTR compat_sys_vmsplice /* 6270 */ + PTR sys_move_pages + PTR compat_sys_set_robust_list + PTR compat_sys_get_robust_list +diff -Nurd linux-2.6.24/arch/mips/kernel/scall64-o32.S mer-smartq-kernel/arch/mips/kernel/scall64-o32.S +--- linux-2.6.24/arch/mips/kernel/scall64-o32.S 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/scall64-o32.S 2009-11-17 12:13:29.000000000 +0100 +@@ -174,14 +174,12 @@ + END(handle_sys) + + LEAF(sys32_syscall) +- sltu v0, a0, __NR_O32_Linux + __NR_O32_Linux_syscalls + 1 ++ subu t0, a0, __NR_O32_Linux # check syscall number ++ sltiu v0, t0, __NR_O32_Linux_syscalls + 1 ++ beqz t0, einval # do not recurse ++ dsll t1, t0, 3 + beqz v0, einval +- +- dsll v0, a0, 3 +- ld t2, (sys_call_table - (__NR_O32_Linux * 8))(v0) +- +- li v1, 4000 # indirect syscall number +- beq a0, v1, einval # do not recurse ++ ld t2, sys_call_table(t1) # syscall routine + + move a0, a1 # shift argument registers + move a1, a2 +@@ -198,7 +196,7 @@ + jr t2 + /* Unreached */ + +-einval: li v0, -EINVAL ++einval: li v0, -ENOSYS + jr ra + END(sys32_syscall) + +@@ -512,7 +510,7 @@ + PTR sys_splice + PTR sys32_sync_file_range /* 4305 */ + PTR sys_tee +- PTR sys_vmsplice ++ PTR compat_sys_vmsplice + PTR compat_sys_move_pages + PTR compat_sys_set_robust_list + PTR compat_sys_get_robust_list /* 4310 */ +diff -Nurd linux-2.6.24/arch/mips/kernel/setup.c mer-smartq-kernel/arch/mips/kernel/setup.c +--- linux-2.6.24/arch/mips/kernel/setup.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/setup.c 2009-11-17 12:13:29.000000000 +0100 +@@ -329,6 +329,7 @@ + /* + * Determine low and high memory ranges + */ ++ max_pfn = max_low_pfn; + if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) { + #ifdef CONFIG_HIGHMEM + highstart_pfn = PFN_DOWN(HIGHMEM_START); +@@ -609,8 +610,8 @@ + struct dentry *d; + + d = debugfs_create_dir("mips", NULL); +- if (IS_ERR(d)) +- return PTR_ERR(d); ++ if (!d) ++ return -ENOMEM; + mips_debugfs_dir = d; + return 0; + } +diff -Nurd linux-2.6.24/arch/mips/kernel/smp.c mer-smartq-kernel/arch/mips/kernel/smp.c +--- linux-2.6.24/arch/mips/kernel/smp.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/smp.c 2009-11-17 12:13:29.000000000 +0100 +@@ -238,8 +238,10 @@ + * Remove this CPU: + */ + cpu_clear(smp_processor_id(), cpu_online_map); +- local_irq_enable(); /* May need to service _machine_restart IPI */ +- for (;;); /* Wait if available. */ ++ for (;;) { ++ if (cpu_wait) ++ (*cpu_wait)(); /* Wait if available. */ ++ } + } + + void smp_send_stop(void) +diff -Nurd linux-2.6.24/arch/mips/kernel/smtc.c mer-smartq-kernel/arch/mips/kernel/smtc.c +--- linux-2.6.24/arch/mips/kernel/smtc.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/smtc.c 2009-11-17 12:13:29.000000000 +0100 +@@ -1,4 +1,21 @@ +-/* Copyright (C) 2004 Mips Technologies, Inc */ ++/* ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) 2004 Mips Technologies, Inc ++ * Copyright (C) 2008 Kevin D. Kissell ++ */ + + #include <linux/clockchips.h> + #include <linux/kernel.h> +@@ -22,7 +39,6 @@ + #include <asm/time.h> + #include <asm/addrspace.h> + #include <asm/smtc.h> +-#include <asm/smtc_ipi.h> + #include <asm/smtc_proc.h> + + /* +@@ -59,11 +75,6 @@ + + asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS]; + +-/* +- * Clock interrupt "latch" buffers, per "CPU" +- */ +- +-static atomic_t ipi_timer_latch[NR_CPUS]; + + /* + * Number of InterProcessor Interupt (IPI) message buffers to allocate +@@ -71,7 +82,7 @@ + + #define IPIBUF_PER_CPU 4 + +-static struct smtc_ipi_q IPIQ[NR_CPUS]; ++struct smtc_ipi_q IPIQ[NR_CPUS]; + static struct smtc_ipi_q freeIPIq; + + +@@ -291,7 +302,7 @@ + * phys_cpu_present_map and the logical/physical mappings. + */ + +-int __init mipsmt_build_cpu_map(int start_cpu_slot) ++int __init smtc_build_cpu_map(int start_cpu_slot) + { + int i, ntcs; + +@@ -334,7 +345,12 @@ + write_tc_c0_tcstatus((read_tc_c0_tcstatus() + & ~(TCSTATUS_TKSU | TCSTATUS_DA | TCSTATUS_IXMT)) + | TCSTATUS_A); +- write_tc_c0_tccontext(0); ++ /* ++ * TCContext gets an offset from the base of the IPIQ array ++ * to be used in low-level code to detect the presence of ++ * an active IPI queue ++ */ ++ write_tc_c0_tccontext((sizeof(struct smtc_ipi_q) * cpu) << 16); + /* Bind tc to vpe */ + write_tc_c0_tcbind(vpe); + /* In general, all TCs should have the same cpu_data indications */ +@@ -346,8 +362,14 @@ + cpu_data[cpu].tc_id = tc; + } + ++/* ++ * Tweak to get Count registes in as close a sync as possible. ++ * Value seems good for 34K-class cores. ++ */ + +-void mipsmt_prepare_cpus(void) ++#define CP0_SKEW 8 ++ ++void smtc_prepare_cpus(int cpus) + { + int i, vpe, tc, ntc, nvpe, tcpervpe[NR_CPUS], slop, cpu; + unsigned long flags; +@@ -371,7 +393,6 @@ + IPIQ[i].head = IPIQ[i].tail = NULL; + spin_lock_init(&IPIQ[i].lock); + IPIQ[i].depth = 0; +- atomic_set(&ipi_timer_latch[i], 0); + } + + /* cpu_data index starts at zero */ +@@ -492,7 +513,8 @@ + write_vpe_c0_compare(0); + /* Propagate Config7 */ + write_vpe_c0_config7(read_c0_config7()); +- write_vpe_c0_count(read_c0_count()); ++ write_vpe_c0_count(read_c0_count() + CP0_SKEW); ++ ehb(); + } + /* enable multi-threading within VPE */ + write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() | VPECONTROL_TE); +@@ -564,7 +586,7 @@ + void __cpuinit smtc_boot_secondary(int cpu, struct task_struct *idle) + { + extern u32 kernelsp[NR_CPUS]; +- long flags; ++ unsigned long flags; + int mtflags; + + LOCK_MT_PRA(); +@@ -593,24 +615,22 @@ + + void smtc_init_secondary(void) + { +- /* +- * Start timer on secondary VPEs if necessary. +- * plat_timer_setup has already have been invoked by init/main +- * on "boot" TC. Like per_cpu_trap_init() hack, this assumes that +- * SMTC init code assigns TCs consdecutively and in ascending order +- * to across available VPEs. +- */ +- if (((read_c0_tcbind() & TCBIND_CURTC) != 0) && +- ((read_c0_tcbind() & TCBIND_CURVPE) +- != cpu_data[smp_processor_id() - 1].vpe_id)){ +- write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ); +- } +- + local_irq_enable(); + } + + void smtc_smp_finish(void) + { ++ int cpu = smp_processor_id(); ++ ++ /* ++ * Lowest-numbered CPU per VPE starts a clock tick. ++ * Like per_cpu_trap_init() hack, this assumes that ++ * SMTC init code assigns TCs consdecutively and ++ * in ascending order across available VPEs. ++ */ ++ if (cpu > 0 && (cpu_data[cpu].vpe_id != cpu_data[cpu - 1].vpe_id)) ++ write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ); ++ + printk("TC %d going on-line as CPU %d\n", + cpu_data[smp_processor_id()].tc_id, smp_processor_id()); + } +@@ -761,8 +781,10 @@ + { + int tcstatus; + struct smtc_ipi *pipi; +- long flags; ++ unsigned long flags; + int mtflags; ++ unsigned long tcrestart; ++ extern void r4k_wait_irqoff(void), __pastwait(void); + + if (cpu == smp_processor_id()) { + printk("Cannot Send IPI to self!\n"); +@@ -779,9 +801,7 @@ + pipi->arg = (void *)action; + pipi->dest = cpu; + if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) { +- if (type == SMTC_CLOCK_TICK) +- atomic_inc(&ipi_timer_latch[cpu]); +- /* If not on same VPE, enqueue and send cross-VPE interupt */ ++ /* If not on same VPE, enqueue and send cross-VPE interrupt */ + smtc_ipi_nq(&IPIQ[cpu], pipi); + LOCK_CORE_PRA(); + settc(cpu_data[cpu].tc_id); +@@ -808,22 +828,29 @@ + + if ((tcstatus & TCSTATUS_IXMT) != 0) { + /* +- * Spin-waiting here can deadlock, +- * so we queue the message for the target TC. ++ * If we're in the the irq-off version of the wait ++ * loop, we need to force exit from the wait and ++ * do a direct post of the IPI. ++ */ ++ if (cpu_wait == r4k_wait_irqoff) { ++ tcrestart = read_tc_c0_tcrestart(); ++ if (tcrestart >= (unsigned long)r4k_wait_irqoff ++ && tcrestart < (unsigned long)__pastwait) { ++ write_tc_c0_tcrestart(__pastwait); ++ tcstatus &= ~TCSTATUS_IXMT; ++ write_tc_c0_tcstatus(tcstatus); ++ goto postdirect; ++ } ++ } ++ /* ++ * Otherwise we queue the message for the target TC ++ * to pick up when he does a local_irq_restore() + */ + write_tc_c0_tchalt(0); + UNLOCK_CORE_PRA(); +- /* Try to reduce redundant timer interrupt messages */ +- if (type == SMTC_CLOCK_TICK) { +- if (atomic_postincrement(&ipi_timer_latch[cpu])!=0){ +- smtc_ipi_nq(&freeIPIq, pipi); +- return; +- } +- } + smtc_ipi_nq(&IPIQ[cpu], pipi); + } else { +- if (type == SMTC_CLOCK_TICK) +- atomic_inc(&ipi_timer_latch[cpu]); ++postdirect: + post_direct_ipi(cpu, pipi); + write_tc_c0_tchalt(0); + UNLOCK_CORE_PRA(); +@@ -892,7 +919,7 @@ + smp_call_function_interrupt(); + } + +-DECLARE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device); ++DECLARE_PER_CPU(struct clock_event_device, mips_clockevent_device); + + void ipi_decode(struct smtc_ipi *pipi) + { +@@ -900,20 +927,13 @@ + struct clock_event_device *cd; + void *arg_copy = pipi->arg; + int type_copy = pipi->type; +- int ticks; +- + smtc_ipi_nq(&freeIPIq, pipi); + switch (type_copy) { + case SMTC_CLOCK_TICK: + irq_enter(); + kstat_this_cpu.irqs[MIPS_CPU_IRQ_BASE + 1]++; +- cd = &per_cpu(smtc_dummy_clockevent_device, cpu); +- ticks = atomic_read(&ipi_timer_latch[cpu]); +- atomic_sub(ticks, &ipi_timer_latch[cpu]); +- while (ticks) { +- cd->event_handler(cd); +- ticks--; +- } ++ cd = &per_cpu(mips_clockevent_device, cpu); ++ cd->event_handler(cd); + irq_exit(); + break; + +@@ -946,24 +966,48 @@ + } + } + ++/* ++ * Similar to smtc_ipi_replay(), but invoked from context restore, ++ * so it reuses the current exception frame rather than set up a ++ * new one with self_ipi. ++ */ ++ + void deferred_smtc_ipi(void) + { +- struct smtc_ipi *pipi; +- unsigned long flags; +-/* DEBUG */ +- int q = smp_processor_id(); ++ int cpu = smp_processor_id(); + + /* + * Test is not atomic, but much faster than a dequeue, + * and the vast majority of invocations will have a null queue. ++ * If irq_disabled when this was called, then any IPIs queued ++ * after we test last will be taken on the next irq_enable/restore. ++ * If interrupts were enabled, then any IPIs added after the ++ * last test will be taken directly. + */ +- if (IPIQ[q].head != NULL) { +- while((pipi = smtc_ipi_dq(&IPIQ[q])) != NULL) { +- /* ipi_decode() should be called with interrupts off */ +- local_irq_save(flags); ++ ++ while (IPIQ[cpu].head != NULL) { ++ struct smtc_ipi_q *q = &IPIQ[cpu]; ++ struct smtc_ipi *pipi; ++ unsigned long flags; ++ ++ /* ++ * It may be possible we'll come in with interrupts ++ * already enabled. ++ */ ++ local_irq_save(flags); ++ ++ spin_lock(&q->lock); ++ pipi = __smtc_ipi_dq(q); ++ spin_unlock(&q->lock); ++ if (pipi != NULL) + ipi_decode(pipi); +- local_irq_restore(flags); +- } ++ /* ++ * The use of the __raw_local restore isn't ++ * as obviously necessary here as in smtc_ipi_replay(), ++ * but it's more efficient, given that we're already ++ * running down the IPI queue. ++ */ ++ __raw_local_irq_restore(flags); + } + } + +@@ -984,7 +1028,7 @@ + struct smtc_ipi *pipi; + unsigned long tcstatus; + int sent; +- long flags; ++ unsigned long flags; + unsigned int mtflags; + unsigned int vpflags; + +@@ -1075,55 +1119,53 @@ + + /* + * SMTC-specific hacks invoked from elsewhere in the kernel. +- * +- * smtc_ipi_replay is called from raw_local_irq_restore which is only ever +- * called with interrupts disabled. We do rely on interrupts being disabled +- * here because using spin_lock_irqsave()/spin_unlock_irqrestore() would +- * result in a recursive call to raw_local_irq_restore(). + */ + +-static void __smtc_ipi_replay(void) ++ /* ++ * smtc_ipi_replay is called from raw_local_irq_restore ++ */ ++ ++void smtc_ipi_replay(void) + { + unsigned int cpu = smp_processor_id(); + + /* + * To the extent that we've ever turned interrupts off, + * we may have accumulated deferred IPIs. This is subtle. +- * If we use the smtc_ipi_qdepth() macro, we'll get an +- * exact number - but we'll also disable interrupts +- * and create a window of failure where a new IPI gets +- * queued after we test the depth but before we re-enable +- * interrupts. So long as IXMT never gets set, however, + * we should be OK: If we pick up something and dispatch + * it here, that's great. If we see nothing, but concurrent + * with this operation, another TC sends us an IPI, IXMT + * is clear, and we'll handle it as a real pseudo-interrupt +- * and not a pseudo-pseudo interrupt. ++ * and not a pseudo-pseudo interrupt. The important thing ++ * is to do the last check for queued message *after* the ++ * re-enabling of interrupts. + */ +- if (IPIQ[cpu].depth > 0) { +- while (1) { +- struct smtc_ipi_q *q = &IPIQ[cpu]; +- struct smtc_ipi *pipi; +- extern void self_ipi(struct smtc_ipi *); ++ while (IPIQ[cpu].head != NULL) { ++ struct smtc_ipi_q *q = &IPIQ[cpu]; ++ struct smtc_ipi *pipi; ++ unsigned long flags; + +- spin_lock(&q->lock); +- pipi = __smtc_ipi_dq(q); +- spin_unlock(&q->lock); +- if (!pipi) +- break; ++ /* ++ * It's just possible we'll come in with interrupts ++ * already enabled. ++ */ ++ local_irq_save(flags); + ++ spin_lock(&q->lock); ++ pipi = __smtc_ipi_dq(q); ++ spin_unlock(&q->lock); ++ /* ++ ** But use a raw restore here to avoid recursion. ++ */ ++ __raw_local_irq_restore(flags); ++ ++ if (pipi) { + self_ipi(pipi); + smtc_cpu_stats[cpu].selfipis++; + } + } + } + +-void smtc_ipi_replay(void) +-{ +- raw_local_irq_disable(); +- __smtc_ipi_replay(); +-} +- + EXPORT_SYMBOL(smtc_ipi_replay); + + void smtc_idle_loop_hook(void) +@@ -1202,40 +1244,13 @@ + } + } + +- /* +- * Now that we limit outstanding timer IPIs, check for hung TC +- */ +- for (tc = 0; tc < NR_CPUS; tc++) { +- /* Don't check ourself - we'll dequeue IPIs just below */ +- if ((tc != smp_processor_id()) && +- atomic_read(&ipi_timer_latch[tc]) > timerq_limit) { +- if (clock_hang_reported[tc] == 0) { +- pdb_msg += sprintf(pdb_msg, +- "TC %d looks hung with timer latch at %d\n", +- tc, atomic_read(&ipi_timer_latch[tc])); +- clock_hang_reported[tc]++; +- } +- } +- } + emt(mtflags); + local_irq_restore(flags); + if (pdb_msg != &id_ho_db_msg[0]) + printk("CPU%d: %s", smp_processor_id(), id_ho_db_msg); + #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ + +- /* +- * Replay any accumulated deferred IPIs. If "Instant Replay" +- * is in use, there should never be any. +- */ +-#ifndef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY +- { +- unsigned long flags; +- +- local_irq_save(flags); +- __smtc_ipi_replay(); +- local_irq_restore(flags); +- } +-#endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */ ++ smtc_ipi_replay(); + } + + void smtc_soft_dump(void) +@@ -1251,10 +1266,6 @@ + printk("%d: %ld\n", i, smtc_cpu_stats[i].selfipis); + } + smtc_ipi_qdump(); +- printk("Timer IPI Backlogs:\n"); +- for (i=0; i < NR_CPUS; i++) { +- printk("%d: %d\n", i, atomic_read(&ipi_timer_latch[i])); +- } + printk("%d Recoveries of \"stolen\" FPU\n", + atomic_read(&smtc_fpu_recoveries)); + } +diff -Nurd linux-2.6.24/arch/mips/kernel/sysirix.c mer-smartq-kernel/arch/mips/kernel/sysirix.c +--- linux-2.6.24/arch/mips/kernel/sysirix.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/sysirix.c 2009-11-17 12:13:29.000000000 +0100 +@@ -111,7 +111,7 @@ + printk("irix_prctl[%s:%d]: Wants PR_ISBLOCKED\n", + current->comm, current->pid); + read_lock(&tasklist_lock); +- task = find_task_by_pid(va_arg(args, pid_t)); ++ task = find_task_by_vpid(va_arg(args, pid_t)); + error = -ESRCH; + if (error) + error = (task->run_list.next != NULL); +diff -Nurd linux-2.6.24/arch/mips/kernel/time.c mer-smartq-kernel/arch/mips/kernel/time.c +--- linux-2.6.24/arch/mips/kernel/time.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/time.c 2009-11-17 12:13:29.000000000 +0100 +@@ -159,6 +159,6 @@ + { + plat_time_init(); + +- if (mips_clockevent_init() || !cpu_has_mfc0_count_bug()) ++ if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug()) + init_mips_clocksource(); + } +diff -Nurd linux-2.6.24/arch/mips/kernel/traps.c mer-smartq-kernel/arch/mips/kernel/traps.c +--- linux-2.6.24/arch/mips/kernel/traps.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/traps.c 2009-11-17 12:13:29.000000000 +0100 +@@ -43,6 +43,9 @@ + #include <asm/types.h> + #include <asm/stacktrace.h> + ++extern void check_wait(void); ++extern asmlinkage void r4k_wait(void); ++extern asmlinkage void rollback_handle_int(void); + extern asmlinkage void handle_int(void); + extern asmlinkage void handle_tlbm(void); + extern asmlinkage void handle_tlbl(void); +@@ -638,35 +641,24 @@ + force_sig_info(SIGFPE, &info, current); + } + +-asmlinkage void do_bp(struct pt_regs *regs) ++static void do_trap_or_bp(struct pt_regs *regs, unsigned int code, ++ const char *str) + { +- unsigned int opcode, bcode; + siginfo_t info; +- +- if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) +- goto out_sigsegv; +- +- /* +- * There is the ancient bug in the MIPS assemblers that the break +- * code starts left to bit 16 instead to bit 6 in the opcode. +- * Gas is bug-compatible, but not always, grrr... +- * We handle both cases with a simple heuristics. --macro +- */ +- bcode = ((opcode >> 6) & ((1 << 20) - 1)); +- if (bcode < (1 << 10)) +- bcode <<= 10; ++ char b[40]; + + /* +- * (A short test says that IRIX 5.3 sends SIGTRAP for all break +- * insns, even for break codes that indicate arithmetic failures. +- * Weird ...) ++ * A short test says that IRIX 5.3 sends SIGTRAP for all trap ++ * insns, even for trap and break codes that indicate arithmetic ++ * failures. Weird ... + * But should we continue the brokenness??? --macro + */ +- switch (bcode) { +- case BRK_OVERFLOW << 10: +- case BRK_DIVZERO << 10: +- die_if_kernel("Break instruction in kernel code", regs); +- if (bcode == (BRK_DIVZERO << 10)) ++ switch (code) { ++ case BRK_OVERFLOW: ++ case BRK_DIVZERO: ++ scnprintf(b, sizeof(b), "%s instruction in kernel code", str); ++ die_if_kernel(b, regs); ++ if (code == BRK_DIVZERO) + info.si_code = FPE_INTDIV; + else + info.si_code = FPE_INTOVF; +@@ -676,12 +668,34 @@ + force_sig_info(SIGFPE, &info, current); + break; + case BRK_BUG: +- die("Kernel bug detected", regs); ++ die_if_kernel("Kernel bug detected", regs); ++ force_sig(SIGTRAP, current); + break; + default: +- die_if_kernel("Break instruction in kernel code", regs); ++ scnprintf(b, sizeof(b), "%s instruction in kernel code", str); ++ die_if_kernel(b, regs); + force_sig(SIGTRAP, current); + } ++} ++ ++asmlinkage void do_bp(struct pt_regs *regs) ++{ ++ unsigned int opcode, bcode; ++ ++ if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) ++ goto out_sigsegv; ++ ++ /* ++ * There is the ancient bug in the MIPS assemblers that the break ++ * code starts left to bit 16 instead to bit 6 in the opcode. ++ * Gas is bug-compatible, but not always, grrr... ++ * We handle both cases with a simple heuristics. --macro ++ */ ++ bcode = ((opcode >> 6) & ((1 << 20) - 1)); ++ if (bcode >= (1 << 10)) ++ bcode >>= 10; ++ ++ do_trap_or_bp(regs, bcode, "Break"); + return; + + out_sigsegv: +@@ -691,7 +705,6 @@ + asmlinkage void do_tr(struct pt_regs *regs) + { + unsigned int opcode, tcode = 0; +- siginfo_t info; + + if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) + goto out_sigsegv; +@@ -700,32 +713,7 @@ + if (!(opcode & OPCODE)) + tcode = ((opcode >> 6) & ((1 << 10) - 1)); + +- /* +- * (A short test says that IRIX 5.3 sends SIGTRAP for all trap +- * insns, even for trap codes that indicate arithmetic failures. +- * Weird ...) +- * But should we continue the brokenness??? --macro +- */ +- switch (tcode) { +- case BRK_OVERFLOW: +- case BRK_DIVZERO: +- die_if_kernel("Trap instruction in kernel code", regs); +- if (tcode == BRK_DIVZERO) +- info.si_code = FPE_INTDIV; +- else +- info.si_code = FPE_INTOVF; +- info.si_signo = SIGFPE; +- info.si_errno = 0; +- info.si_addr = (void __user *) regs->cp0_epc; +- force_sig_info(SIGFPE, &info, current); +- break; +- case BRK_BUG: +- die("Kernel bug detected", regs); +- break; +- default: +- die_if_kernel("Trap instruction in kernel code", regs); +- force_sig(SIGTRAP, current); +- } ++ do_trap_or_bp(regs, tcode, "Trap"); + return; + + out_sigsegv: +@@ -783,8 +771,10 @@ + if (cpus_intersects(current->cpus_allowed, mt_fpu_cpumask)) { + cpumask_t tmask; + +- cpus_and(tmask, current->thread.user_cpus_allowed, +- mt_fpu_cpumask); ++ current->thread.user_cpus_allowed ++ = current->cpus_allowed; ++ cpus_and(tmask, current->cpus_allowed, ++ mt_fpu_cpumask); + set_cpus_allowed(current, tmask); + set_thread_flag(TIF_FPUBOUND); + } +@@ -1146,6 +1136,9 @@ + + extern char except_vec_vi, except_vec_vi_lui; + extern char except_vec_vi_ori, except_vec_vi_end; ++ extern char rollback_except_vec_vi; ++ char *vec_start = (cpu_wait == r4k_wait) ? ++ &rollback_except_vec_vi : &except_vec_vi; + #ifdef CONFIG_MIPS_MT_SMTC + /* + * We need to provide the SMTC vectored interrupt handler +@@ -1153,11 +1146,11 @@ + * Status.IM bit to be masked before going there. + */ + extern char except_vec_vi_mori; +- const int mori_offset = &except_vec_vi_mori - &except_vec_vi; ++ const int mori_offset = &except_vec_vi_mori - vec_start; + #endif /* CONFIG_MIPS_MT_SMTC */ +- const int handler_len = &except_vec_vi_end - &except_vec_vi; +- const int lui_offset = &except_vec_vi_lui - &except_vec_vi; +- const int ori_offset = &except_vec_vi_ori - &except_vec_vi; ++ const int handler_len = &except_vec_vi_end - vec_start; ++ const int lui_offset = &except_vec_vi_lui - vec_start; ++ const int ori_offset = &except_vec_vi_ori - vec_start; + + if (handler_len > VECTORSPACING) { + /* +@@ -1167,7 +1160,7 @@ + panic("VECTORSPACING too small"); + } + +- memcpy(b, &except_vec_vi, handler_len); ++ memcpy(b, vec_start, handler_len); + #ifdef CONFIG_MIPS_MT_SMTC + BUG_ON(n > 7); /* Vector index %d exceeds SMTC maximum. */ + +@@ -1287,7 +1280,7 @@ + int cp0_perfcount_irq; + EXPORT_SYMBOL_GPL(cp0_perfcount_irq); + +-void __init per_cpu_trap_init(void) ++void __cpuinit per_cpu_trap_init(void) + { + unsigned int cpu = smp_processor_id(); + unsigned int status_set = ST0_CU0; +@@ -1404,11 +1397,12 @@ + flush_icache_range(ebase + offset, ebase + offset + size); + } + +-static char panic_null_cerr[] __initdata = ++static char panic_null_cerr[] __cpuinitdata = + "Trying to set NULL cache error exception handler"; + + /* Install uncached CPU exception handler */ +-void __init set_uncached_handler(unsigned long offset, void *addr, unsigned long size) ++void __cpuinit set_uncached_handler(unsigned long offset, void *addr, ++ unsigned long size) + { + #ifdef CONFIG_32BIT + unsigned long uncached_ebase = KSEG1ADDR(ebase); +@@ -1437,6 +1431,10 @@ + extern char except_vec3_generic, except_vec3_r4000; + extern char except_vec4; + unsigned long i; ++ int rollback; ++ ++ check_wait(); ++ rollback = (cpu_wait == r4k_wait); + + if (cpu_has_veic || cpu_has_vint) + ebase = (unsigned long) alloc_bootmem_low_pages(0x200 + VECTORSPACING*64); +@@ -1496,7 +1494,7 @@ + if (board_be_init) + board_be_init(); + +- set_except_vector(0, handle_int); ++ set_except_vector(0, rollback ? rollback_handle_int : handle_int); + set_except_vector(1, handle_tlbm); + set_except_vector(2, handle_tlbl); + set_except_vector(3, handle_tlbs); +diff -Nurd linux-2.6.24/arch/mips/kernel/unaligned.c mer-smartq-kernel/arch/mips/kernel/unaligned.c +--- linux-2.6.24/arch/mips/kernel/unaligned.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/unaligned.c 2009-11-17 12:13:29.000000000 +0100 +@@ -560,12 +560,12 @@ + return -ENODEV; + d = debugfs_create_u32("unaligned_instructions", S_IRUGO, + mips_debugfs_dir, &unaligned_instructions); +- if (IS_ERR(d)) +- return PTR_ERR(d); ++ if (!d) ++ return -ENOMEM; + d = debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR, + mips_debugfs_dir, &unaligned_action); +- if (IS_ERR(d)) +- return PTR_ERR(d); ++ if (!d) ++ return -ENOMEM; + return 0; + } + __initcall(debugfs_unaligned); +diff -Nurd linux-2.6.24/arch/mips/kernel/vpe.c mer-smartq-kernel/arch/mips/kernel/vpe.c +--- linux-2.6.24/arch/mips/kernel/vpe.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/kernel/vpe.c 2009-11-17 12:13:29.000000000 +0100 +@@ -263,13 +263,21 @@ + /* Find some VPE program space */ + static void *alloc_progmem(unsigned long len) + { ++ void *addr; ++ + #ifdef CONFIG_MIPS_VPE_LOADER_TOM +- /* this means you must tell linux to use less memory than you physically have */ +- return pfn_to_kaddr(max_pfn); ++ /* ++ * This means you must tell Linux to use less memory than you ++ * physically have, for example by passing a mem= boot argument. ++ */ ++ addr = pfn_to_kaddr(max_pfn); ++ memset(addr, 0, len); + #else +- // simple grab some mem for now +- return kmalloc(len, GFP_KERNEL); ++ /* simple grab some mem for now */ ++ addr = kzalloc(len, GFP_KERNEL); + #endif ++ ++ return addr; + } + + static void release_progmem(void *ptr) +@@ -774,10 +782,15 @@ + /* take system out of configuration state */ + clear_c0_mvpcontrol(MVPCONTROL_VPC); + ++ /* ++ * SMTC/SMVP kernels manage VPE enable independently, ++ * but uniprocessor kernels need to turn it on, even ++ * if that wasn't the pre-dvpe() state. ++ */ + #ifdef CONFIG_SMP +- evpe(EVPE_ENABLE); +-#else + evpe(vpeflags); ++#else ++ evpe(EVPE_ENABLE); + #endif + emt(dmt_flag); + local_irq_restore(flags); +@@ -885,9 +898,10 @@ + } + + v->load_addr = alloc_progmem(mod.core_size); +- memset(v->load_addr, 0, mod.core_size); ++ if (!v->load_addr) ++ return -ENOMEM; + +- printk("VPE loader: loading to %p\n", v->load_addr); ++ pr_info("VPE loader: loading to %p\n", v->load_addr); + + if (relocate) { + for (i = 0; i < hdr->e_shnum; i++) { +@@ -939,12 +953,14 @@ + struct elf_phdr *phdr = (struct elf_phdr *) ((char *)hdr + hdr->e_phoff); + + for (i = 0; i < hdr->e_phnum; i++) { +- if (phdr->p_type != PT_LOAD) +- continue; +- +- memcpy((void *)phdr->p_paddr, (char *)hdr + phdr->p_offset, phdr->p_filesz); +- memset((void *)phdr->p_paddr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); +- phdr++; ++ if (phdr->p_type == PT_LOAD) { ++ memcpy((void *)phdr->p_paddr, ++ (char *)hdr + phdr->p_offset, ++ phdr->p_filesz); ++ memset((void *)phdr->p_paddr + phdr->p_filesz, ++ 0, phdr->p_memsz - phdr->p_filesz); ++ } ++ phdr++; + } + + for (i = 0; i < hdr->e_shnum; i++) { +@@ -1113,7 +1129,7 @@ + + /* It's good to be able to run the SP and if it chokes have a look at + the /dev/rt?. But if we reset the pointer to the shared struct we +- loose what has happened. So perhaps if garbage is sent to the vpe ++ lose what has happened. So perhaps if garbage is sent to the vpe + device, use it as a trigger for the reset. Hopefully a nice + executable will be along shortly. */ + if (ret < 0) +diff -Nurd linux-2.6.24/arch/mips/lasat/interrupt.c mer-smartq-kernel/arch/mips/lasat/interrupt.c +--- linux-2.6.24/arch/mips/lasat/interrupt.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/lasat/interrupt.c 2009-11-17 12:13:29.000000000 +0100 +@@ -34,11 +34,13 @@ + + void disable_lasat_irq(unsigned int irq_nr) + { ++ irq_nr -= LASAT_IRQ_BASE; + *lasat_int_mask &= ~(1 << irq_nr) << lasat_int_mask_shift; + } + + void enable_lasat_irq(unsigned int irq_nr) + { ++ irq_nr -= LASAT_IRQ_BASE; + *lasat_int_mask |= (1 << irq_nr) << lasat_int_mask_shift; + } + +diff -Nurd linux-2.6.24/arch/mips/lasat/lasat_board.c mer-smartq-kernel/arch/mips/lasat/lasat_board.c +--- linux-2.6.24/arch/mips/lasat/lasat_board.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/lasat/lasat_board.c 2009-11-17 12:13:29.000000000 +0100 +@@ -23,18 +23,19 @@ + #include <linux/kernel.h> + #include <linux/string.h> + #include <linux/ctype.h> ++#include <linux/mutex.h> + #include <asm/bootinfo.h> + #include <asm/addrspace.h> + #include "at93c.h" + /* New model description table */ + #include "lasat_models.h" + ++static DEFINE_MUTEX(lasat_eeprom_mutex); ++ + #define EEPROM_CRC(data, len) (~crc32(~0, data, len)) + + struct lasat_info lasat_board_info; + +-void update_bcastaddr(void); +- + int EEPROMRead(unsigned int pos, unsigned char *data, int len) + { + int i; +@@ -258,10 +259,6 @@ + sprintf(lasat_board_info.li_typestr, "%d", 10 * c); + } + +-#if defined(CONFIG_INET) && defined(CONFIG_SYSCTL) +- update_bcastaddr(); +-#endif +- + return 0; + } + +@@ -269,6 +266,8 @@ + { + unsigned long crc; + ++ mutex_lock(&lasat_eeprom_mutex); ++ + /* Generate the CRC */ + crc = EEPROM_CRC((unsigned char *)(&lasat_board_info.li_eeprom_info), + sizeof(struct lasat_eeprom_struct) - 4); +@@ -277,4 +276,6 @@ + /* Write the EEPROM info */ + EEPROMWrite(0, (unsigned char *)&lasat_board_info.li_eeprom_info, + sizeof(struct lasat_eeprom_struct)); ++ ++ mutex_unlock(&lasat_eeprom_mutex); + } +diff -Nurd linux-2.6.24/arch/mips/lasat/sysctl.c mer-smartq-kernel/arch/mips/lasat/sysctl.c +--- linux-2.6.24/arch/mips/lasat/sysctl.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/lasat/sysctl.c 2009-11-17 12:13:29.000000000 +0100 +@@ -29,15 +29,13 @@ + #include <linux/string.h> + #include <linux/net.h> + #include <linux/inet.h> +-#include <linux/mutex.h> + #include <linux/uaccess.h> + + #include <asm/time.h> + +-#include "sysctl.h" ++#ifdef CONFIG_DS1603 + #include "ds1603.h" +- +-static DEFINE_MUTEX(lasat_info_mutex); ++#endif + + /* Strategy function to write EEPROM after changing string entry */ + int sysctl_lasatstring(ctl_table *table, int *name, int nlen, +@@ -46,18 +44,15 @@ + { + int r; + +- mutex_lock(&lasat_info_mutex); + r = sysctl_string(table, name, + nlen, oldval, oldlenp, newval, newlen); +- if (r < 0) { +- mutex_unlock(&lasat_info_mutex); ++ if (r < 0) + return r; +- } ++ + if (newval && newlen) + lasat_write_eeprom_info(); +- mutex_unlock(&lasat_info_mutex); + +- return 1; ++ return 0; + } + + +@@ -67,14 +62,11 @@ + { + int r; + +- mutex_lock(&lasat_info_mutex); + r = proc_dostring(table, write, filp, buffer, lenp, ppos); +- if ((!write) || r) { +- mutex_unlock(&lasat_info_mutex); ++ if ((!write) || r) + return r; +- } ++ + lasat_write_eeprom_info(); +- mutex_unlock(&lasat_info_mutex); + + return 0; + } +@@ -85,28 +77,24 @@ + { + int r; + +- mutex_lock(&lasat_info_mutex); + r = proc_dointvec(table, write, filp, buffer, lenp, ppos); +- if ((!write) || r) { +- mutex_unlock(&lasat_info_mutex); ++ if ((!write) || r) + return r; +- } ++ + lasat_write_eeprom_info(); +- mutex_unlock(&lasat_info_mutex); + + return 0; + } + ++#ifdef CONFIG_DS1603 + static int rtctmp; + +-#ifdef CONFIG_DS1603 + /* proc function to read/write RealTime Clock */ + int proc_dolasatrtc(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp, loff_t *ppos) + { + int r; + +- mutex_lock(&lasat_info_mutex); + if (!write) { + rtctmp = read_persistent_clock(); + /* check for time < 0 and set to 0 */ +@@ -114,12 +102,11 @@ + rtctmp = 0; + } + r = proc_dointvec(table, write, filp, buffer, lenp, ppos); +- if ((!write) || r) { +- mutex_unlock(&lasat_info_mutex); ++ if (r) + return r; +- } +- rtc_mips_set_mmss(rtctmp); +- mutex_unlock(&lasat_info_mutex); ++ ++ if (write) ++ rtc_mips_set_mmss(rtctmp); + + return 0; + } +@@ -132,17 +119,14 @@ + { + int r; + +- mutex_lock(&lasat_info_mutex); + r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); +- if (r < 0) { +- mutex_unlock(&lasat_info_mutex); ++ if (r < 0) + return r; +- } ++ + if (newval && newlen) + lasat_write_eeprom_info(); +- mutex_unlock(&lasat_info_mutex); + +- return 1; ++ return 0; + } + + #ifdef CONFIG_DS1603 +@@ -153,50 +137,27 @@ + { + int r; + +- mutex_lock(&lasat_info_mutex); + rtctmp = read_persistent_clock(); + if (rtctmp < 0) + rtctmp = 0; + r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); +- if (r < 0) { +- mutex_unlock(&lasat_info_mutex); ++ if (r < 0) + return r; +- } + if (newval && newlen) + rtc_mips_set_mmss(rtctmp); +- mutex_unlock(&lasat_info_mutex); + +- return 1; ++ return r; + } + #endif + + #ifdef CONFIG_INET +-static char lasat_bcastaddr[16]; +- +-void update_bcastaddr(void) +-{ +- unsigned int ip; +- +- ip = (lasat_board_info.li_eeprom_info.ipaddr & +- lasat_board_info.li_eeprom_info.netmask) | +- ~lasat_board_info.li_eeprom_info.netmask; +- +- sprintf(lasat_bcastaddr, "%d.%d.%d.%d", +- (ip) & 0xff, +- (ip >> 8) & 0xff, +- (ip >> 16) & 0xff, +- (ip >> 24) & 0xff); +-} +- +-static char proc_lasat_ipbuf[32]; +- +-/* Parsing of IP address */ + int proc_lasat_ip(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp, loff_t *ppos) + { + unsigned int ip; + char *p, c; + int len; ++ char ipbuf[32]; + + if (!table->data || !table->maxlen || !*lenp || + (*ppos && !write)) { +@@ -204,117 +165,88 @@ + return 0; + } + +- mutex_lock(&lasat_info_mutex); + if (write) { + len = 0; + p = buffer; + while (len < *lenp) { +- if (get_user(c, p++)) { +- mutex_unlock(&lasat_info_mutex); ++ if (get_user(c, p++)) + return -EFAULT; +- } + if (c == 0 || c == '\n') + break; + len++; + } +- if (len >= sizeof(proc_lasat_ipbuf)-1) +- len = sizeof(proc_lasat_ipbuf) - 1; +- if (copy_from_user(proc_lasat_ipbuf, buffer, len)) { +- mutex_unlock(&lasat_info_mutex); ++ if (len >= sizeof(ipbuf)-1) ++ len = sizeof(ipbuf) - 1; ++ if (copy_from_user(ipbuf, buffer, len)) + return -EFAULT; +- } +- proc_lasat_ipbuf[len] = 0; ++ ipbuf[len] = 0; + *ppos += *lenp; + /* Now see if we can convert it to a valid IP */ +- ip = in_aton(proc_lasat_ipbuf); ++ ip = in_aton(ipbuf); + *(unsigned int *)(table->data) = ip; + lasat_write_eeprom_info(); + } else { + ip = *(unsigned int *)(table->data); +- sprintf(proc_lasat_ipbuf, "%d.%d.%d.%d", ++ sprintf(ipbuf, "%d.%d.%d.%d", + (ip) & 0xff, + (ip >> 8) & 0xff, + (ip >> 16) & 0xff, + (ip >> 24) & 0xff); +- len = strlen(proc_lasat_ipbuf); ++ len = strlen(ipbuf); + if (len > *lenp) + len = *lenp; + if (len) +- if (copy_to_user(buffer, proc_lasat_ipbuf, len)) { +- mutex_unlock(&lasat_info_mutex); ++ if (copy_to_user(buffer, ipbuf, len)) + return -EFAULT; +- } + if (len < *lenp) { +- if (put_user('\n', ((char *) buffer) + len)) { +- mutex_unlock(&lasat_info_mutex); ++ if (put_user('\n', ((char *) buffer) + len)) + return -EFAULT; +- } + len++; + } + *lenp = len; + *ppos += len; + } +- update_bcastaddr(); +- mutex_unlock(&lasat_info_mutex); + + return 0; + } +-#endif /* defined(CONFIG_INET) */ ++#endif + +-static int sysctl_lasat_eeprom_value(ctl_table *table, int *name, int nlen, ++static int sysctl_lasat_prid(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen) + { + int r; + +- mutex_lock(&lasat_info_mutex); + r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); +- if (r < 0) { +- mutex_unlock(&lasat_info_mutex); ++ if (r < 0) + return r; +- } +- + if (newval && newlen) { +- if (name && *name == LASAT_PRID) +- lasat_board_info.li_eeprom_info.prid = *(int *)newval; +- ++ lasat_board_info.li_eeprom_info.prid = *(int *)newval; + lasat_write_eeprom_info(); + lasat_init_board_info(); + } +- mutex_unlock(&lasat_info_mutex); +- + return 0; + } + +-int proc_lasat_eeprom_value(ctl_table *table, int write, struct file *filp, ++int proc_lasat_prid(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp, loff_t *ppos) + { + int r; + +- mutex_lock(&lasat_info_mutex); + r = proc_dointvec(table, write, filp, buffer, lenp, ppos); +- if ((!write) || r) { +- mutex_unlock(&lasat_info_mutex); ++ if (r < 0) + return r; ++ if (write) { ++ lasat_board_info.li_eeprom_info.prid = ++ lasat_board_info.li_prid; ++ lasat_write_eeprom_info(); ++ lasat_init_board_info(); + } +- if (filp && filp->f_path.dentry) { +- if (!strcmp(filp->f_path.dentry->d_name.name, "prid")) +- lasat_board_info.li_eeprom_info.prid = +- lasat_board_info.li_prid; +- if (!strcmp(filp->f_path.dentry->d_name.name, "debugaccess")) +- lasat_board_info.li_eeprom_info.debugaccess = +- lasat_board_info.li_debugaccess; +- } +- lasat_write_eeprom_info(); +- mutex_unlock(&lasat_info_mutex); +- + return 0; + } + + extern int lasat_boot_to_service; + +-#ifdef CONFIG_SYSCTL +- + static ctl_table lasat_table[] = { + { + .ctl_name = CTL_UNNUMBERED, +@@ -349,8 +281,8 @@ + .data = &lasat_board_info.li_prid, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = &proc_lasat_eeprom_value, +- .strategy = &sysctl_lasat_eeprom_value ++ .proc_handler = &proc_lasat_prid, ++ .strategy = &sysctl_lasat_prid + }, + #ifdef CONFIG_INET + { +@@ -363,7 +295,7 @@ + .strategy = &sysctl_lasat_intvec + }, + { +- .ctl_name = LASAT_NETMASK, ++ .ctl_name = CTL_UNNUMBERED, + .procname = "netmask", + .data = &lasat_board_info.li_eeprom_info.netmask, + .maxlen = sizeof(int), +@@ -371,15 +303,6 @@ + .proc_handler = &proc_lasat_ip, + .strategy = &sysctl_lasat_intvec + }, +- { +- .ctl_name = CTL_UNNUMBERED, +- .procname = "bcastaddr", +- .data = &lasat_bcastaddr, +- .maxlen = sizeof(lasat_bcastaddr), +- .mode = 0600, +- .proc_handler = &proc_dostring, +- .strategy = &sysctl_string +- }, + #endif + { + .ctl_name = CTL_UNNUMBERED, +@@ -417,7 +340,7 @@ + .data = &lasat_board_info.li_namestr, + .maxlen = sizeof(lasat_board_info.li_namestr), + .mode = 0444, +- .proc_handler = &proc_dostring, ++ .proc_handler = &proc_dostring, + .strategy = &sysctl_string + }, + { +@@ -448,9 +371,12 @@ + + lasat_table_header = + register_sysctl_table(lasat_root_table); ++ if (!lasat_table_header) { ++ printk(KERN_ERR "Unable to register LASAT sysctl\n"); ++ return -ENOMEM; ++ } + + return 0; + } + + __initcall(lasat_register_sysctl); +-#endif /* CONFIG_SYSCTL */ +diff -Nurd linux-2.6.24/arch/mips/lasat/sysctl.h mer-smartq-kernel/arch/mips/lasat/sysctl.h +--- linux-2.6.24/arch/mips/lasat/sysctl.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/lasat/sysctl.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,24 +0,0 @@ +-/* +- * LASAT sysctl values +- */ +- +-#ifndef _LASAT_SYSCTL_H +-#define _LASAT_SYSCTL_H +- +-/* /proc/sys/lasat */ +-enum { +- LASAT_CPU_HZ = 1, +- LASAT_BUS_HZ, +- LASAT_MODEL, +- LASAT_PRID, +- LASAT_IPADDR, +- LASAT_NETMASK, +- LASAT_BCAST, +- LASAT_PASSWORD, +- LASAT_SBOOT, +- LASAT_RTC, +- LASAT_NAMESTR, +- LASAT_TYPESTR, +-}; +- +-#endif /* _LASAT_SYSCTL_H */ +diff -Nurd linux-2.6.24/arch/mips/lib/csum_partial.S mer-smartq-kernel/arch/mips/lib/csum_partial.S +--- linux-2.6.24/arch/mips/lib/csum_partial.S 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/lib/csum_partial.S 2009-11-17 12:13:29.000000000 +0100 +@@ -38,12 +38,14 @@ + #ifdef USE_DOUBLE + + #define LOAD ld ++#define LOAD32 lwu + #define ADD daddu + #define NBYTES 8 + + #else + + #define LOAD lw ++#define LOAD32 lw + #define ADD addu + #define NBYTES 4 + +@@ -56,6 +58,14 @@ + sltu v1, sum, reg; \ + ADD sum, v1 + ++#define ADDC32(sum,reg) \ ++ .set push; \ ++ .set noat; \ ++ addu sum, reg; \ ++ sltu v1, sum, reg; \ ++ addu sum, v1; \ ++ .set pop ++ + #define CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3) \ + LOAD _t0, (offset + UNIT(0))(src); \ + LOAD _t1, (offset + UNIT(1))(src); \ +@@ -128,7 +138,7 @@ + beqz t8, qword_align + andi t8, src, 0x8 + +- lw t0, 0x00(src) ++ LOAD32 t0, 0x00(src) + LONG_SUBU a1, a1, 0x4 + ADDC(sum, t0) + PTR_ADDU src, src, 0x4 +@@ -205,7 +215,7 @@ + LONG_SRL t8, t8, 0x2 + + end_words: +- lw t0, (src) ++ LOAD32 t0, (src) + LONG_SUBU t8, t8, 0x1 + ADDC(sum, t0) + bnez t8, end_words +@@ -222,6 +232,9 @@ + /* Still a full word to go */ + ulw t1, (src) + PTR_ADDIU src, 4 ++#ifdef USE_DOUBLE ++ dsll t1, t1, 32 /* clear lower 32bit */ ++#endif + ADDC(sum, t1) + + 1: move t1, zero +@@ -269,7 +282,7 @@ + 1: + .set reorder + /* Add the passed partial csum. */ +- ADDC(sum, a2) ++ ADDC32(sum, a2) + jr ra + .set noreorder + END(csum_partial) +@@ -653,7 +666,7 @@ + andi sum, 0xffff + 1: + .set reorder +- ADDC(sum, psum) ++ ADDC32(sum, psum) + jr ra + .set noreorder + +diff -Nurd linux-2.6.24/arch/mips/lib/ucmpdi2.c mer-smartq-kernel/arch/mips/lib/ucmpdi2.c +--- linux-2.6.24/arch/mips/lib/ucmpdi2.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/lib/ucmpdi2.c 2009-11-17 12:13:29.000000000 +0100 +@@ -17,3 +17,5 @@ + return 2; + return 1; + } ++ ++EXPORT_SYMBOL(__ucmpdi2); +diff -Nurd linux-2.6.24/arch/mips/lib/uncached.c mer-smartq-kernel/arch/mips/lib/uncached.c +--- linux-2.6.24/arch/mips/lib/uncached.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/lib/uncached.c 2009-11-17 12:13:29.000000000 +0100 +@@ -36,7 +36,7 @@ + * values, so we can avoid sharing the same stack area between a cached + * and the uncached mode. + */ +-unsigned long __init run_uncached(void *func) ++unsigned long __cpuinit run_uncached(void *func) + { + register long sp __asm__("$sp"); + register long ret __asm__("$2"); +diff -Nurd linux-2.6.24/arch/mips/Makefile mer-smartq-kernel/arch/mips/Makefile +--- linux-2.6.24/arch/mips/Makefile 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/Makefile 2009-11-17 12:13:28.000000000 +0100 +@@ -548,7 +548,11 @@ + # + core-$(CONFIG_SNI_RM) += arch/mips/sni/ + cflags-$(CONFIG_SNI_RM) += -Iinclude/asm-mips/mach-rm ++ifdef CONFIG_CPU_LITTLE_ENDIAN + load-$(CONFIG_SNI_RM) += 0xffffffff80600000 ++else ++load-$(CONFIG_SNI_RM) += 0xffffffff80030000 ++endif + all-$(CONFIG_SNI_RM) := vmlinux.ecoff + + # +diff -Nurd linux-2.6.24/arch/mips/math-emu/cp1emu.c mer-smartq-kernel/arch/mips/math-emu/cp1emu.c +--- linux-2.6.24/arch/mips/math-emu/cp1emu.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/math-emu/cp1emu.c 2009-11-17 12:13:29.000000000 +0100 +@@ -1299,12 +1299,12 @@ + if (!mips_debugfs_dir) + return -ENODEV; + dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir); +- if (IS_ERR(dir)) +- return PTR_ERR(dir); ++ if (!dir) ++ return -ENOMEM; + for (i = 0; i < ARRAY_SIZE(vars); i++) { + d = debugfs_create_u32(vars[i].name, S_IRUGO, dir, vars[i].v); +- if (IS_ERR(d)) +- return PTR_ERR(d); ++ if (!d) ++ return -ENOMEM; + } + return 0; + } +diff -Nurd linux-2.6.24/arch/mips/mips-boards/generic/time.c mer-smartq-kernel/arch/mips/mips-boards/generic/time.c +--- linux-2.6.24/arch/mips/mips-boards/generic/time.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mips-boards/generic/time.c 2009-11-17 12:13:29.000000000 +0100 +@@ -146,7 +146,7 @@ + } + } + +-unsigned int __init get_c0_compare_int(void) ++unsigned int __cpuinit get_c0_compare_int(void) + { + #ifdef MSC01E_INT_BASE + if (cpu_has_veic) { +diff -Nurd linux-2.6.24/arch/mips/mips-boards/malta/Makefile mer-smartq-kernel/arch/mips/mips-boards/malta/Makefile +--- linux-2.6.24/arch/mips/mips-boards/malta/Makefile 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mips-boards/malta/Makefile 2009-11-17 12:13:29.000000000 +0100 +@@ -19,9 +19,8 @@ + # under Linux. + # + +-obj-y := malta_int.o malta_platform.o malta_setup.o ++obj-y := malta_int.o malta_mtd.o malta_platform.o malta_setup.o + +-obj-$(CONFIG_MTD) += malta_mtd.o + obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o + + EXTRA_CFLAGS += -Werror +diff -Nurd linux-2.6.24/arch/mips/mips-boards/malta/malta_smtc.c mer-smartq-kernel/arch/mips/mips-boards/malta/malta_smtc.c +--- linux-2.6.24/arch/mips/mips-boards/malta/malta_smtc.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mips-boards/malta/malta_smtc.c 2009-11-17 12:13:29.000000000 +0100 +@@ -62,14 +62,20 @@ + + void __cpuinit plat_smp_setup(void) + { +- if (read_c0_config3() & (1<<2)) +- mipsmt_build_cpu_map(0); ++ if (read_c0_config3() & (1<<2)) { ++ /* ++ * we won't get the definitive value until ++ * we've run smtc_prepare_cpus later, but ++ * we would appear to need an upper bound now. ++ */ ++ smtc_build_cpu_map(0); ++ } + } + + void __init plat_prepare_cpus(unsigned int max_cpus) + { + if (read_c0_config3() & (1<<2)) +- mipsmt_prepare_cpus(); ++ smtc_prepare_cpus(max_cpus); + } + + /* +diff -Nurd linux-2.6.24/arch/mips/mipssim/sim_time.c mer-smartq-kernel/arch/mips/mipssim/sim_time.c +--- linux-2.6.24/arch/mips/mipssim/sim_time.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mipssim/sim_time.c 2009-11-17 12:13:29.000000000 +0100 +@@ -83,7 +83,7 @@ + } + + +-unsigned __init get_c0_compare_int(void) ++unsigned __cpuinit get_c0_compare_int(void) + { + #ifdef MSC01E_INT_BASE + if (cpu_has_veic) { +diff -Nurd linux-2.6.24/arch/mips/mm/cache.c mer-smartq-kernel/arch/mips/mm/cache.c +--- linux-2.6.24/arch/mips/mm/cache.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/cache.c 2009-11-17 12:13:29.000000000 +0100 +@@ -30,6 +30,9 @@ + unsigned long pfn); + void (*flush_icache_range)(unsigned long start, unsigned long end); + ++void (*__flush_cache_vmap)(void); ++void (*__flush_cache_vunmap)(void); ++ + /* MIPS specific cache operations */ + void (*flush_cache_sigtramp)(unsigned long addr); + void (*local_flush_data_cache_page)(void * addr); +@@ -92,12 +95,17 @@ + + void __flush_anon_page(struct page *page, unsigned long vmaddr) + { +- if (pages_do_alias((unsigned long)page_address(page), vmaddr)) { +- void *kaddr; ++ unsigned long addr = (unsigned long) page_address(page); + +- kaddr = kmap_coherent(page, vmaddr); +- flush_data_cache_page((unsigned long)kaddr); +- kunmap_coherent(); ++ if (pages_do_alias(addr, vmaddr)) { ++ if (page_mapped(page) && !Page_dcache_dirty(page)) { ++ void *kaddr; ++ ++ kaddr = kmap_coherent(page, vmaddr); ++ flush_data_cache_page((unsigned long)kaddr); ++ kunmap_coherent(); ++ } else ++ flush_data_cache_page(addr); + } + } + +@@ -122,9 +130,10 @@ + } + } + +-static char cache_panic[] __initdata = "Yeee, unsupported cache architecture."; ++static char cache_panic[] __cpuinitdata = ++ "Yeee, unsupported cache architecture."; + +-void __init cpu_cache_init(void) ++void __cpuinit cpu_cache_init(void) + { + if (cpu_has_3k_cache) { + extern void __weak r3k_cache_init(void); +diff -Nurd linux-2.6.24/arch/mips/mm/cex-sb1.S mer-smartq-kernel/arch/mips/mm/cex-sb1.S +--- linux-2.6.24/arch/mips/mm/cex-sb1.S 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/cex-sb1.S 2009-11-17 12:13:29.000000000 +0100 +@@ -34,8 +34,6 @@ + * is changed. + */ + +- __INIT +- + .set mips64 + .set noreorder + .set noat +@@ -51,6 +49,10 @@ + * (0x170-0x17f) are used to preserve k0, k1, and ra. + */ + ++#ifndef CONFIG_HOTPLUG_CPU ++ __INIT /* no __CPUINIT; it's a 2.6.25 thing */ ++#endif ++ + LEAF(except_vec2_sb1) + /* + * If this error is recoverable, we need to exit the handler +@@ -142,7 +144,9 @@ + + END(except_vec2_sb1) + ++#ifndef CONFIG_HOTPLUG_CPU + __FINIT ++#endif + + LEAF(handle_vec2_sb1) + mfc0 k0,CP0_CONFIG +diff -Nurd linux-2.6.24/arch/mips/mm/c-r3k.c mer-smartq-kernel/arch/mips/mm/c-r3k.c +--- linux-2.6.24/arch/mips/mm/c-r3k.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/c-r3k.c 2009-11-17 12:13:29.000000000 +0100 +@@ -26,7 +26,7 @@ + static unsigned long icache_size, dcache_size; /* Size in bytes */ + static unsigned long icache_lsize, dcache_lsize; /* Size in bytes */ + +-unsigned long __init r3k_cache_size(unsigned long ca_flags) ++unsigned long __cpuinit r3k_cache_size(unsigned long ca_flags) + { + unsigned long flags, status, dummy, size; + volatile unsigned long *p; +@@ -61,7 +61,7 @@ + return size * sizeof(*p); + } + +-unsigned long __init r3k_cache_lsize(unsigned long ca_flags) ++unsigned long __cpuinit r3k_cache_lsize(unsigned long ca_flags) + { + unsigned long flags, status, lsize, i; + volatile unsigned long *p; +@@ -90,7 +90,7 @@ + return lsize * sizeof(*p); + } + +-static void __init r3k_probe_cache(void) ++static void __cpuinit r3k_probe_cache(void) + { + dcache_size = r3k_cache_size(ST0_ISC); + if (dcache_size) +@@ -307,7 +307,7 @@ + r3k_flush_dcache_range(start, start + size); + } + +-void __init r3k_cache_init(void) ++void __cpuinit r3k_cache_init(void) + { + extern void build_clear_page(void); + extern void build_copy_page(void); +diff -Nurd linux-2.6.24/arch/mips/mm/c-r4k.c mer-smartq-kernel/arch/mips/mm/c-r4k.c +--- linux-2.6.24/arch/mips/mm/c-r4k.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/c-r4k.c 2009-11-17 12:13:29.000000000 +0100 +@@ -93,7 +93,7 @@ + blast_dcache32_page(addr); + } + +-static void __init r4k_blast_dcache_page_setup(void) ++static void __cpuinit r4k_blast_dcache_page_setup(void) + { + unsigned long dc_lsize = cpu_dcache_line_size(); + +@@ -107,7 +107,7 @@ + + static void (* r4k_blast_dcache_page_indexed)(unsigned long addr); + +-static void __init r4k_blast_dcache_page_indexed_setup(void) ++static void __cpuinit r4k_blast_dcache_page_indexed_setup(void) + { + unsigned long dc_lsize = cpu_dcache_line_size(); + +@@ -121,7 +121,7 @@ + + static void (* r4k_blast_dcache)(void); + +-static void __init r4k_blast_dcache_setup(void) ++static void __cpuinit r4k_blast_dcache_setup(void) + { + unsigned long dc_lsize = cpu_dcache_line_size(); + +@@ -206,7 +206,7 @@ + + static void (* r4k_blast_icache_page)(unsigned long addr); + +-static void __init r4k_blast_icache_page_setup(void) ++static void __cpuinit r4k_blast_icache_page_setup(void) + { + unsigned long ic_lsize = cpu_icache_line_size(); + +@@ -223,7 +223,7 @@ + + static void (* r4k_blast_icache_page_indexed)(unsigned long addr); + +-static void __init r4k_blast_icache_page_indexed_setup(void) ++static void __cpuinit r4k_blast_icache_page_indexed_setup(void) + { + unsigned long ic_lsize = cpu_icache_line_size(); + +@@ -247,7 +247,7 @@ + + static void (* r4k_blast_icache)(void); + +-static void __init r4k_blast_icache_setup(void) ++static void __cpuinit r4k_blast_icache_setup(void) + { + unsigned long ic_lsize = cpu_icache_line_size(); + +@@ -268,7 +268,7 @@ + + static void (* r4k_blast_scache_page)(unsigned long addr); + +-static void __init r4k_blast_scache_page_setup(void) ++static void __cpuinit r4k_blast_scache_page_setup(void) + { + unsigned long sc_lsize = cpu_scache_line_size(); + +@@ -286,7 +286,7 @@ + + static void (* r4k_blast_scache_page_indexed)(unsigned long addr); + +-static void __init r4k_blast_scache_page_indexed_setup(void) ++static void __cpuinit r4k_blast_scache_page_indexed_setup(void) + { + unsigned long sc_lsize = cpu_scache_line_size(); + +@@ -304,7 +304,7 @@ + + static void (* r4k_blast_scache)(void); + +-static void __init r4k_blast_scache_setup(void) ++static void __cpuinit r4k_blast_scache_setup(void) + { + unsigned long sc_lsize = cpu_scache_line_size(); + +@@ -361,23 +361,36 @@ + #endif + } + ++static void r4k__flush_cache_vmap(void) ++{ ++ r4k_blast_dcache(); ++} ++ ++static void r4k__flush_cache_vunmap(void) ++{ ++ r4k_blast_dcache(); ++} ++ + static inline void local_r4k_flush_cache_range(void * args) + { + struct vm_area_struct *vma = args; ++ int exec = vma->vm_flags & VM_EXEC; + + if (!(has_valid_asid(vma->vm_mm))) + return; + + r4k_blast_dcache(); ++ if (exec) ++ r4k_blast_icache(); + } + + static void r4k_flush_cache_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) + { +- if (!cpu_has_dc_aliases) +- return; ++ int exec = vma->vm_flags & VM_EXEC; + +- r4k_on_each_cpu(local_r4k_flush_cache_range, vma, 1, 1); ++ if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) ++ r4k_on_each_cpu(local_r4k_flush_cache_range, vma, 1, 1); + } + + static inline void local_r4k_flush_cache_mm(void * args) +@@ -426,6 +439,7 @@ + struct page *page = pfn_to_page(fcp_args->pfn); + int exec = vma->vm_flags & VM_EXEC; + struct mm_struct *mm = vma->vm_mm; ++ int map_coherent = 0; + pgd_t *pgdp; + pud_t *pudp; + pmd_t *pmdp; +@@ -459,7 +473,9 @@ + * Use kmap_coherent or kmap_atomic to do flushes for + * another ASID than the current one. + */ +- if (cpu_has_dc_aliases) ++ map_coherent = (cpu_has_dc_aliases && ++ page_mapped(page) && !Page_dcache_dirty(page)); ++ if (map_coherent) + vaddr = kmap_coherent(page, addr); + else + vaddr = kmap_atomic(page, KM_USER0); +@@ -482,7 +498,7 @@ + } + + if (vaddr) { +- if (cpu_has_dc_aliases) ++ if (map_coherent) + kunmap_coherent(); + else + kunmap_atomic(vaddr, KM_USER0); +@@ -697,11 +713,11 @@ + } + } + +-static char *way_string[] __initdata = { NULL, "direct mapped", "2-way", ++static char *way_string[] __cpuinitdata = { NULL, "direct mapped", "2-way", + "3-way", "4-way", "5-way", "6-way", "7-way", "8-way" + }; + +-static void __init probe_pcache(void) ++static void __cpuinit probe_pcache(void) + { + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int config = read_c0_config(); +@@ -1020,7 +1036,7 @@ + * executes in KSEG1 space or else you will crash and burn badly. You have + * been warned. + */ +-static int __init probe_scache(void) ++static int __cpuinit probe_scache(void) + { + unsigned long flags, addr, begin, end, pow2; + unsigned int config = read_c0_config(); +@@ -1099,7 +1115,7 @@ + extern int rm7k_sc_init(void); + extern int mips_sc_init(void); + +-static void __init setup_scache(void) ++static void __cpuinit setup_scache(void) + { + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int config = read_c0_config(); +@@ -1210,7 +1226,7 @@ + } + } + +-static void __init coherency_setup(void) ++static void __cpuinit coherency_setup(void) + { + change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT); + +@@ -1242,7 +1258,7 @@ + } + } + +-void __init r4k_cache_init(void) ++void __cpuinit r4k_cache_init(void) + { + extern void build_clear_page(void); + extern void build_copy_page(void); +@@ -1285,6 +1301,10 @@ + PAGE_SIZE - 1); + else + shm_align_mask = PAGE_SIZE-1; ++ ++ __flush_cache_vmap = r4k__flush_cache_vmap; ++ __flush_cache_vunmap = r4k__flush_cache_vunmap; ++ + flush_cache_all = cache_noop; + __flush_cache_all = r4k___flush_cache_all; + flush_cache_mm = r4k_flush_cache_mm; +diff -Nurd linux-2.6.24/arch/mips/mm/c-tx39.c mer-smartq-kernel/arch/mips/mm/c-tx39.c +--- linux-2.6.24/arch/mips/mm/c-tx39.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/c-tx39.c 2009-11-17 12:13:29.000000000 +0100 +@@ -122,6 +122,16 @@ + local_irq_restore(flags); + } + ++static void tx39__flush_cache_vmap(void) ++{ ++ tx39_blast_dcache(); ++} ++ ++static void tx39__flush_cache_vunmap(void) ++{ ++ tx39_blast_dcache(); ++} ++ + static inline void tx39_flush_cache_all(void) + { + if (!cpu_has_dc_aliases) +@@ -329,7 +339,7 @@ + } + } + +-void __init tx39_cache_init(void) ++void __cpuinit tx39_cache_init(void) + { + extern void build_clear_page(void); + extern void build_copy_page(void); +@@ -344,6 +354,8 @@ + switch (current_cpu_type()) { + case CPU_TX3912: + /* TX39/H core (writethru direct-map cache) */ ++ __flush_cache_vmap = tx39__flush_cache_vmap; ++ __flush_cache_vunmap = tx39__flush_cache_vunmap; + flush_cache_all = tx39h_flush_icache_all; + __flush_cache_all = tx39h_flush_icache_all; + flush_cache_mm = (void *) tx39h_flush_icache_all; +@@ -369,6 +381,9 @@ + write_c0_wired(0); /* set 8 on reset... */ + /* board-dependent init code may set WBON */ + ++ __flush_cache_vmap = tx39__flush_cache_vmap; ++ __flush_cache_vunmap = tx39__flush_cache_vunmap; ++ + flush_cache_all = tx39_flush_cache_all; + __flush_cache_all = tx39___flush_cache_all; + flush_cache_mm = tx39_flush_cache_mm; +diff -Nurd linux-2.6.24/arch/mips/mm/dma-default.c mer-smartq-kernel/arch/mips/mm/dma-default.c +--- linux-2.6.24/arch/mips/mm/dma-default.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/dma-default.c 2009-11-17 12:13:29.000000000 +0100 +@@ -111,6 +111,7 @@ + void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle) + { ++ plat_unmap_dma_mem(dma_handle); + free_pages((unsigned long) vaddr, get_order(size)); + } + +@@ -121,6 +122,8 @@ + { + unsigned long addr = (unsigned long) vaddr; + ++ plat_unmap_dma_mem(dma_handle); ++ + if (!plat_device_is_coherent(dev)) + addr = CAC_ADDR(addr); + +@@ -324,7 +327,6 @@ + if (cpu_is_noncoherent_r10000(dev)) + __dma_sync((unsigned long)page_address(sg_page(sg)), + sg->length, direction); +- plat_unmap_dma_mem(sg->dma_address); + } + } + +@@ -342,7 +344,6 @@ + if (!plat_device_is_coherent(dev)) + __dma_sync((unsigned long)page_address(sg_page(sg)), + sg->length, direction); +- plat_unmap_dma_mem(sg->dma_address); + } + } + +diff -Nurd linux-2.6.24/arch/mips/mm/init.c mer-smartq-kernel/arch/mips/mm/init.c +--- linux-2.6.24/arch/mips/mm/init.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/init.c 2009-11-17 12:13:29.000000000 +0100 +@@ -211,7 +211,8 @@ + void *vfrom, *vto; + + vto = kmap_atomic(to, KM_USER1); +- if (cpu_has_dc_aliases && page_mapped(from)) { ++ if (cpu_has_dc_aliases && ++ page_mapped(from) && !Page_dcache_dirty(from)) { + vfrom = kmap_coherent(from, vaddr); + copy_page(vto, vfrom); + kunmap_coherent(); +@@ -234,7 +235,8 @@ + struct page *page, unsigned long vaddr, void *dst, const void *src, + unsigned long len) + { +- if (cpu_has_dc_aliases && page_mapped(page)) { ++ if (cpu_has_dc_aliases && ++ page_mapped(page) && !Page_dcache_dirty(page)) { + void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(vto, src, len); + kunmap_coherent(); +@@ -253,7 +255,8 @@ + struct page *page, unsigned long vaddr, void *dst, const void *src, + unsigned long len) + { +- if (cpu_has_dc_aliases && page_mapped(page)) { ++ if (cpu_has_dc_aliases && ++ page_mapped(page) && !Page_dcache_dirty(page)) { + void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(dst, vfrom, len); + kunmap_coherent(); +diff -Nurd linux-2.6.24/arch/mips/mm/pg-r4k.c mer-smartq-kernel/arch/mips/mm/pg-r4k.c +--- linux-2.6.24/arch/mips/mm/pg-r4k.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/pg-r4k.c 2009-11-17 12:13:29.000000000 +0100 +@@ -64,21 +64,21 @@ + * with 64-bit kernels. The prefetch offsets have been experimentally tuned + * an Origin 200. + */ +-static int pref_offset_clear __initdata = 512; +-static int pref_offset_copy __initdata = 256; ++static int pref_offset_clear __cpuinitdata = 512; ++static int pref_offset_copy __cpuinitdata = 256; + +-static unsigned int pref_src_mode __initdata; +-static unsigned int pref_dst_mode __initdata; ++static unsigned int pref_src_mode __cpuinitdata; ++static unsigned int pref_dst_mode __cpuinitdata; + +-static int load_offset __initdata; +-static int store_offset __initdata; ++static int load_offset __cpuinitdata; ++static int store_offset __cpuinitdata; + +-static unsigned int __initdata *dest, *epc; ++static unsigned int __cpuinitdata *dest, *epc; + + static unsigned int instruction_pending; + static union mips_instruction delayed_mi; + +-static void __init emit_instruction(union mips_instruction mi) ++static void __cpuinit emit_instruction(union mips_instruction mi) + { + if (instruction_pending) + *epc++ = delayed_mi.word; +@@ -220,7 +220,7 @@ + emit_instruction(mi); + } + +-static void __init __build_store_reg(int reg) ++static void __cpuinit __build_store_reg(int reg) + { + union mips_instruction mi; + unsigned int width; +@@ -343,7 +343,7 @@ + flush_delay_slot_or_nop(); + } + +-void __init build_clear_page(void) ++void __cpuinit build_clear_page(void) + { + unsigned int loop_start; + unsigned long off; +@@ -446,7 +446,7 @@ + pr_debug("\t.set pop\n"); + } + +-void __init build_copy_page(void) ++void __cpuinit build_copy_page(void) + { + unsigned int loop_start; + unsigned long off; +diff -Nurd linux-2.6.24/arch/mips/mm/pg-sb1.c mer-smartq-kernel/arch/mips/mm/pg-sb1.c +--- linux-2.6.24/arch/mips/mm/pg-sb1.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/pg-sb1.c 2009-11-17 12:13:29.000000000 +0100 +@@ -216,7 +216,7 @@ + int i; + + for (i = 0; i < DM_NUM_CHANNELS; i++) { +- const u64 base_val = CPHYSADDR(&page_descr[i]) | ++ const u64 base_val = CPHYSADDR((unsigned long)&page_descr[i]) | + V_DM_DSCR_BASE_RINGSZ(1); + void *base_reg = IOADDR(A_DM_REGISTER(i, R_DM_DSCR_BASE)); + +@@ -228,11 +228,11 @@ + + void clear_page(void *page) + { +- u64 to_phys = CPHYSADDR(page); ++ u64 to_phys = CPHYSADDR((unsigned long)page); + unsigned int cpu = smp_processor_id(); + + /* if the page is not in KSEG0, use old way */ +- if ((long)KSEGX(page) != (long)CKSEG0) ++ if ((long)KSEGX((unsigned long)page) != (long)CKSEG0) + return clear_page_cpu(page); + + page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_ZERO_MEM | +@@ -252,13 +252,13 @@ + + void copy_page(void *to, void *from) + { +- u64 from_phys = CPHYSADDR(from); +- u64 to_phys = CPHYSADDR(to); ++ u64 from_phys = CPHYSADDR((unsigned long)from); ++ u64 to_phys = CPHYSADDR((unsigned long)to); + unsigned int cpu = smp_processor_id(); + + /* if any page is not in KSEG0, use old way */ +- if ((long)KSEGX(to) != (long)CKSEG0 +- || (long)KSEGX(from) != (long)CKSEG0) ++ if ((long)KSEGX((unsigned long)to) != (long)CKSEG0 ++ || (long)KSEGX((unsigned long)from) != (long)CKSEG0) + return copy_page_cpu(to, from); + + page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_L2C_DEST | +@@ -293,10 +293,10 @@ + EXPORT_SYMBOL(clear_page); + EXPORT_SYMBOL(copy_page); + +-void __init build_clear_page(void) ++void __cpuinit build_clear_page(void) + { + } + +-void __init build_copy_page(void) ++void __cpuinit build_copy_page(void) + { + } +diff -Nurd linux-2.6.24/arch/mips/mm/sc-ip22.c mer-smartq-kernel/arch/mips/mm/sc-ip22.c +--- linux-2.6.24/arch/mips/mm/sc-ip22.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/sc-ip22.c 2009-11-17 12:13:29.000000000 +0100 +@@ -168,7 +168,7 @@ + .bc_inv = indy_sc_wback_invalidate + }; + +-void __init indy_sc_init(void) ++void __cpuinit indy_sc_init(void) + { + if (indy_sc_probe()) { + indy_sc_enable(); +diff -Nurd linux-2.6.24/arch/mips/mm/sc-mips.c mer-smartq-kernel/arch/mips/mm/sc-mips.c +--- linux-2.6.24/arch/mips/mm/sc-mips.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/sc-mips.c 2009-11-17 12:13:29.000000000 +0100 +@@ -100,7 +100,7 @@ + return 1; + } + +-int __init mips_sc_init(void) ++int __cpuinit mips_sc_init(void) + { + int found = mips_sc_probe(); + if (found) { +@@ -109,4 +109,3 @@ + } + return found; + } +- +diff -Nurd linux-2.6.24/arch/mips/mm/sc-r5k.c mer-smartq-kernel/arch/mips/mm/sc-r5k.c +--- linux-2.6.24/arch/mips/mm/sc-r5k.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/sc-r5k.c 2009-11-17 12:13:29.000000000 +0100 +@@ -99,7 +99,7 @@ + .bc_inv = r5k_dma_cache_inv_sc + }; + +-void __init r5k_sc_init(void) ++void __cpuinit r5k_sc_init(void) + { + if (r5k_sc_probe()) { + r5k_sc_enable(); +diff -Nurd linux-2.6.24/arch/mips/mm/sc-rm7k.c mer-smartq-kernel/arch/mips/mm/sc-rm7k.c +--- linux-2.6.24/arch/mips/mm/sc-rm7k.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/sc-rm7k.c 2009-11-17 12:13:29.000000000 +0100 +@@ -86,7 +86,7 @@ + /* + * This function is executed in uncached address space. + */ +-static __init void __rm7k_sc_enable(void) ++static __cpuinit void __rm7k_sc_enable(void) + { + int i; + +@@ -107,7 +107,7 @@ + } + } + +-static __init void rm7k_sc_enable(void) ++static __cpuinit void rm7k_sc_enable(void) + { + if (read_c0_config() & RM7K_CONF_SE) + return; +@@ -128,7 +128,7 @@ + .bc_inv = rm7k_sc_inv + }; + +-void __init rm7k_sc_init(void) ++void __cpuinit rm7k_sc_init(void) + { + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int config = read_c0_config(); +diff -Nurd linux-2.6.24/arch/mips/mm/tlbex.c mer-smartq-kernel/arch/mips/mm/tlbex.c +--- linux-2.6.24/arch/mips/mm/tlbex.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/tlbex.c 2009-11-17 12:13:29.000000000 +0100 +@@ -66,7 +66,7 @@ + * why; it's not an issue caused by the core RTL. + * + */ +-static __init int __attribute__((unused)) m4kc_tlbp_war(void) ++static __cpuinit int __attribute__((unused)) m4kc_tlbp_war(void) + { + return (current_cpu_data.processor_id & 0xffff00) == + (PRID_COMP_MIPS | PRID_IMP_4KC); +@@ -140,7 +140,7 @@ + | (e) << RE_SH \ + | (f) << FUNC_SH) + +-static __initdata struct insn insn_table[] = { ++static __cpuinitdata struct insn insn_table[] = { + { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD }, + { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD }, +@@ -193,7 +193,7 @@ + + #undef M + +-static __init u32 build_rs(u32 arg) ++static __cpuinit u32 build_rs(u32 arg) + { + if (arg & ~RS_MASK) + printk(KERN_WARNING "TLB synthesizer field overflow\n"); +@@ -201,7 +201,7 @@ + return (arg & RS_MASK) << RS_SH; + } + +-static __init u32 build_rt(u32 arg) ++static __cpuinit u32 build_rt(u32 arg) + { + if (arg & ~RT_MASK) + printk(KERN_WARNING "TLB synthesizer field overflow\n"); +@@ -209,7 +209,7 @@ + return (arg & RT_MASK) << RT_SH; + } + +-static __init u32 build_rd(u32 arg) ++static __cpuinit u32 build_rd(u32 arg) + { + if (arg & ~RD_MASK) + printk(KERN_WARNING "TLB synthesizer field overflow\n"); +@@ -217,7 +217,7 @@ + return (arg & RD_MASK) << RD_SH; + } + +-static __init u32 build_re(u32 arg) ++static __cpuinit u32 build_re(u32 arg) + { + if (arg & ~RE_MASK) + printk(KERN_WARNING "TLB synthesizer field overflow\n"); +@@ -225,7 +225,7 @@ + return (arg & RE_MASK) << RE_SH; + } + +-static __init u32 build_simm(s32 arg) ++static __cpuinit u32 build_simm(s32 arg) + { + if (arg > 0x7fff || arg < -0x8000) + printk(KERN_WARNING "TLB synthesizer field overflow\n"); +@@ -233,7 +233,7 @@ + return arg & 0xffff; + } + +-static __init u32 build_uimm(u32 arg) ++static __cpuinit u32 build_uimm(u32 arg) + { + if (arg & ~IMM_MASK) + printk(KERN_WARNING "TLB synthesizer field overflow\n"); +@@ -241,7 +241,7 @@ + return arg & IMM_MASK; + } + +-static __init u32 build_bimm(s32 arg) ++static __cpuinit u32 build_bimm(s32 arg) + { + if (arg > 0x1ffff || arg < -0x20000) + printk(KERN_WARNING "TLB synthesizer field overflow\n"); +@@ -252,7 +252,7 @@ + return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff); + } + +-static __init u32 build_jimm(u32 arg) ++static __cpuinit u32 build_jimm(u32 arg) + { + if (arg & ~((JIMM_MASK) << 2)) + printk(KERN_WARNING "TLB synthesizer field overflow\n"); +@@ -260,7 +260,7 @@ + return (arg >> 2) & JIMM_MASK; + } + +-static __init u32 build_func(u32 arg) ++static __cpuinit u32 build_func(u32 arg) + { + if (arg & ~FUNC_MASK) + printk(KERN_WARNING "TLB synthesizer field overflow\n"); +@@ -268,7 +268,7 @@ + return arg & FUNC_MASK; + } + +-static __init u32 build_set(u32 arg) ++static __cpuinit u32 build_set(u32 arg) + { + if (arg & ~SET_MASK) + printk(KERN_WARNING "TLB synthesizer field overflow\n"); +@@ -280,7 +280,7 @@ + * The order of opcode arguments is implicitly left to right, + * starting with RS and ending with FUNC or IMM. + */ +-static void __init build_insn(u32 **buf, enum opcode opc, ...) ++static void __cpuinit build_insn(u32 **buf, enum opcode opc, ...) + { + struct insn *ip = NULL; + unsigned int i; +@@ -315,69 +315,69 @@ + } + + #define I_u1u2u3(op) \ +- static inline void __init i##op(u32 **buf, unsigned int a, \ ++ static inline void __cpuinit i##op(u32 **buf, unsigned int a, \ + unsigned int b, unsigned int c) \ + { \ + build_insn(buf, insn##op, a, b, c); \ + } + + #define I_u2u1u3(op) \ +- static inline void __init i##op(u32 **buf, unsigned int a, \ ++ static inline void __cpuinit i##op(u32 **buf, unsigned int a, \ + unsigned int b, unsigned int c) \ + { \ + build_insn(buf, insn##op, b, a, c); \ + } + + #define I_u3u1u2(op) \ +- static inline void __init i##op(u32 **buf, unsigned int a, \ ++ static inline void __cpuinit i##op(u32 **buf, unsigned int a, \ + unsigned int b, unsigned int c) \ + { \ + build_insn(buf, insn##op, b, c, a); \ + } + + #define I_u1u2s3(op) \ +- static inline void __init i##op(u32 **buf, unsigned int a, \ ++ static inline void __cpuinit i##op(u32 **buf, unsigned int a, \ + unsigned int b, signed int c) \ + { \ + build_insn(buf, insn##op, a, b, c); \ + } + + #define I_u2s3u1(op) \ +- static inline void __init i##op(u32 **buf, unsigned int a, \ ++ static inline void __cpuinit i##op(u32 **buf, unsigned int a, \ + signed int b, unsigned int c) \ + { \ + build_insn(buf, insn##op, c, a, b); \ + } + + #define I_u2u1s3(op) \ +- static inline void __init i##op(u32 **buf, unsigned int a, \ ++ static inline void __cpuinit i##op(u32 **buf, unsigned int a, \ + unsigned int b, signed int c) \ + { \ + build_insn(buf, insn##op, b, a, c); \ + } + + #define I_u1u2(op) \ +- static inline void __init i##op(u32 **buf, unsigned int a, \ ++ static inline void __cpuinit i##op(u32 **buf, unsigned int a, \ + unsigned int b) \ + { \ + build_insn(buf, insn##op, a, b); \ + } + + #define I_u1s2(op) \ +- static inline void __init i##op(u32 **buf, unsigned int a, \ ++ static inline void __cpuinit i##op(u32 **buf, unsigned int a, \ + signed int b) \ + { \ + build_insn(buf, insn##op, a, b); \ + } + + #define I_u1(op) \ +- static inline void __init i##op(u32 **buf, unsigned int a) \ ++ static inline void __cpuinit i##op(u32 **buf, unsigned int a) \ + { \ + build_insn(buf, insn##op, a); \ + } + + #define I_0(op) \ +- static inline void __init i##op(u32 **buf) \ ++ static inline void __cpuinit i##op(u32 **buf) \ + { \ + build_insn(buf, insn##op); \ + } +@@ -457,7 +457,7 @@ + enum label_id lab; + }; + +-static __init void build_label(struct label **lab, u32 *addr, ++static __cpuinit void build_label(struct label **lab, u32 *addr, + enum label_id l) + { + (*lab)->addr = addr; +@@ -526,34 +526,34 @@ + #define i_ehb(buf) i_sll(buf, 0, 0, 3) + + #ifdef CONFIG_64BIT +-static __init int __maybe_unused in_compat_space_p(long addr) ++static __cpuinit int __maybe_unused in_compat_space_p(long addr) + { + /* Is this address in 32bit compat space? */ + return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L); + } + +-static __init int __maybe_unused rel_highest(long val) ++static __cpuinit int __maybe_unused rel_highest(long val) + { + return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000; + } + +-static __init int __maybe_unused rel_higher(long val) ++static __cpuinit int __maybe_unused rel_higher(long val) + { + return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000; + } + #endif + +-static __init int rel_hi(long val) ++static __cpuinit int rel_hi(long val) + { + return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000; + } + +-static __init int rel_lo(long val) ++static __cpuinit int rel_lo(long val) + { + return ((val & 0xffff) ^ 0x8000) - 0x8000; + } + +-static __init void i_LA_mostly(u32 **buf, unsigned int rs, long addr) ++static __cpuinit void i_LA_mostly(u32 **buf, unsigned int rs, long addr) + { + #ifdef CONFIG_64BIT + if (!in_compat_space_p(addr)) { +@@ -571,7 +571,7 @@ + i_lui(buf, rs, rel_hi(addr)); + } + +-static __init void __maybe_unused i_LA(u32 **buf, unsigned int rs, ++static __cpuinit void __maybe_unused i_LA(u32 **buf, unsigned int rs, + long addr) + { + i_LA_mostly(buf, rs, addr); +@@ -589,7 +589,7 @@ + enum label_id lab; + }; + +-static __init void r_mips_pc16(struct reloc **rel, u32 *addr, ++static __cpuinit void r_mips_pc16(struct reloc **rel, u32 *addr, + enum label_id l) + { + (*rel)->addr = addr; +@@ -614,7 +614,7 @@ + } + } + +-static __init void resolve_relocs(struct reloc *rel, struct label *lab) ++static __cpuinit void resolve_relocs(struct reloc *rel, struct label *lab) + { + struct label *l; + +@@ -624,7 +624,7 @@ + __resolve_relocs(rel, l); + } + +-static __init void move_relocs(struct reloc *rel, u32 *first, u32 *end, ++static __cpuinit void move_relocs(struct reloc *rel, u32 *first, u32 *end, + long off) + { + for (; rel->lab != label_invalid; rel++) +@@ -632,7 +632,7 @@ + rel->addr += off; + } + +-static __init void move_labels(struct label *lab, u32 *first, u32 *end, ++static __cpuinit void move_labels(struct label *lab, u32 *first, u32 *end, + long off) + { + for (; lab->lab != label_invalid; lab++) +@@ -640,7 +640,7 @@ + lab->addr += off; + } + +-static __init void copy_handler(struct reloc *rel, struct label *lab, ++static __cpuinit void copy_handler(struct reloc *rel, struct label *lab, + u32 *first, u32 *end, u32 *target) + { + long off = (long)(target - first); +@@ -651,7 +651,7 @@ + move_labels(lab, first, end, off); + } + +-static __init int __maybe_unused insn_has_bdelay(struct reloc *rel, ++static __cpuinit int __maybe_unused insn_has_bdelay(struct reloc *rel, + u32 *addr) + { + for (; rel->lab != label_invalid; rel++) { +@@ -665,49 +665,49 @@ + } + + /* convenience functions for labeled branches */ +-static void __init __maybe_unused ++static void __cpuinit __maybe_unused + il_bltz(u32 **p, struct reloc **r, unsigned int reg, enum label_id l) + { + r_mips_pc16(r, *p, l); + i_bltz(p, reg, 0); + } + +-static void __init __maybe_unused il_b(u32 **p, struct reloc **r, ++static void __cpuinit __maybe_unused il_b(u32 **p, struct reloc **r, + enum label_id l) + { + r_mips_pc16(r, *p, l); + i_b(p, 0); + } + +-static void __init il_beqz(u32 **p, struct reloc **r, unsigned int reg, ++static void __cpuinit il_beqz(u32 **p, struct reloc **r, unsigned int reg, + enum label_id l) + { + r_mips_pc16(r, *p, l); + i_beqz(p, reg, 0); + } + +-static void __init __maybe_unused ++static void __cpuinit __maybe_unused + il_beqzl(u32 **p, struct reloc **r, unsigned int reg, enum label_id l) + { + r_mips_pc16(r, *p, l); + i_beqzl(p, reg, 0); + } + +-static void __init il_bnez(u32 **p, struct reloc **r, unsigned int reg, ++static void __cpuinit il_bnez(u32 **p, struct reloc **r, unsigned int reg, + enum label_id l) + { + r_mips_pc16(r, *p, l); + i_bnez(p, reg, 0); + } + +-static void __init il_bgezl(u32 **p, struct reloc **r, unsigned int reg, ++static void __cpuinit il_bgezl(u32 **p, struct reloc **r, unsigned int reg, + enum label_id l) + { + r_mips_pc16(r, *p, l); + i_bgezl(p, reg, 0); + } + +-static void __init __maybe_unused ++static void __cpuinit __maybe_unused + il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l) + { + r_mips_pc16(r, *p, l); +@@ -743,16 +743,16 @@ + * We deliberately chose a buffer size of 128, so we won't scribble + * over anything important on overflow before we panic. + */ +-static __initdata u32 tlb_handler[128]; ++static __cpuinitdata u32 tlb_handler[128]; + + /* simply assume worst case size for labels and relocs */ +-static __initdata struct label labels[128]; +-static __initdata struct reloc relocs[128]; ++static __cpuinitdata struct label labels[128]; ++static __cpuinitdata struct reloc relocs[128]; + + /* + * The R3000 TLB handler is simple. + */ +-static void __init build_r3000_tlb_refill_handler(void) ++static void __cpuinit build_r3000_tlb_refill_handler(void) + { + long pgdc = (long)pgd_current; + u32 *p; +@@ -801,7 +801,7 @@ + * other one.To keep things simple, we first assume linear space, + * then we relocate it to the final handler layout as needed. + */ +-static __initdata u32 final_handler[64]; ++static __cpuinitdata u32 final_handler[64]; + + /* + * Hazards +@@ -825,11 +825,12 @@ + * + * As if we MIPS hackers wouldn't know how to nop pipelines happy ... + */ +-static __init void __maybe_unused build_tlb_probe_entry(u32 **p) ++static __cpuinit void __maybe_unused build_tlb_probe_entry(u32 **p) + { + switch (current_cpu_type()) { +- /* Found by experiment: R4600 v2.0 needs this, too. */ ++ /* Found by experiment: R4600 v2.0/R4700 needs this, too. */ + case CPU_R4600: ++ case CPU_R4700: + case CPU_R5000: + case CPU_R5000A: + case CPU_NEVADA: +@@ -849,7 +850,7 @@ + */ + enum tlb_write_entry { tlb_random, tlb_indexed }; + +-static __init void build_tlb_write_entry(u32 **p, struct label **l, ++static __cpuinit void build_tlb_write_entry(u32 **p, struct label **l, + struct reloc **r, + enum tlb_write_entry wmode) + { +@@ -993,7 +994,7 @@ + * TMP and PTR are scratch. + * TMP will be clobbered, PTR will hold the pmd entry. + */ +-static __init void ++static __cpuinit void + build_get_pmde64(u32 **p, struct label **l, struct reloc **r, + unsigned int tmp, unsigned int ptr) + { +@@ -1054,7 +1055,7 @@ + * BVADDR is the faulting address, PTR is scratch. + * PTR will hold the pgd for vmalloc. + */ +-static __init void ++static __cpuinit void + build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r, + unsigned int bvaddr, unsigned int ptr) + { +@@ -1118,7 +1119,7 @@ + * TMP and PTR are scratch. + * TMP will be clobbered, PTR will hold the pgd entry. + */ +-static __init void __maybe_unused ++static __cpuinit void __maybe_unused + build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr) + { + long pgdc = (long)pgd_current; +@@ -1153,7 +1154,7 @@ + + #endif /* !CONFIG_64BIT */ + +-static __init void build_adjust_context(u32 **p, unsigned int ctx) ++static __cpuinit void build_adjust_context(u32 **p, unsigned int ctx) + { + unsigned int shift = 4 - (PTE_T_LOG2 + 1) + PAGE_SHIFT - 12; + unsigned int mask = (PTRS_PER_PTE / 2 - 1) << (PTE_T_LOG2 + 1); +@@ -1179,7 +1180,8 @@ + i_andi(p, ctx, ctx, mask); + } + +-static __init void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr) ++static __cpuinit void build_get_ptep(u32 **p, unsigned int tmp, ++ unsigned int ptr) + { + /* + * Bug workaround for the Nevada. It seems as if under certain +@@ -1204,7 +1206,7 @@ + i_ADDU(p, ptr, ptr, tmp); /* add in offset */ + } + +-static __init void build_update_entries(u32 **p, unsigned int tmp, ++static __cpuinit void build_update_entries(u32 **p, unsigned int tmp, + unsigned int ptep) + { + /* +@@ -1247,7 +1249,7 @@ + #endif + } + +-static void __init build_r4000_tlb_refill_handler(void) ++static void __cpuinit build_r4000_tlb_refill_handler(void) + { + u32 *p = tlb_handler; + struct label *l = labels; +@@ -1394,7 +1396,7 @@ + u32 __tlb_handler_align handle_tlbs[FASTPATH_SIZE]; + u32 __tlb_handler_align handle_tlbm[FASTPATH_SIZE]; + +-static void __init ++static void __cpuinit + iPTE_LW(u32 **p, struct label **l, unsigned int pte, unsigned int ptr) + { + #ifdef CONFIG_SMP +@@ -1414,7 +1416,7 @@ + #endif + } + +-static void __init ++static void __cpuinit + iPTE_SW(u32 **p, struct reloc **r, unsigned int pte, unsigned int ptr, + unsigned int mode) + { +@@ -1474,7 +1476,7 @@ + * the page table where this PTE is located, PTE will be re-loaded + * with it's original value. + */ +-static void __init ++static void __cpuinit + build_pte_present(u32 **p, struct label **l, struct reloc **r, + unsigned int pte, unsigned int ptr, enum label_id lid) + { +@@ -1485,7 +1487,7 @@ + } + + /* Make PTE valid, store result in PTR. */ +-static void __init ++static void __cpuinit + build_make_valid(u32 **p, struct reloc **r, unsigned int pte, + unsigned int ptr) + { +@@ -1498,7 +1500,7 @@ + * Check if PTE can be written to, if not branch to LABEL. Regardless + * restore PTE with value from PTR when done. + */ +-static void __init ++static void __cpuinit + build_pte_writable(u32 **p, struct label **l, struct reloc **r, + unsigned int pte, unsigned int ptr, enum label_id lid) + { +@@ -1511,7 +1513,7 @@ + /* Make PTE writable, update software status bits as well, then store + * at PTR. + */ +-static void __init ++static void __cpuinit + build_make_write(u32 **p, struct reloc **r, unsigned int pte, + unsigned int ptr) + { +@@ -1525,7 +1527,7 @@ + * Check if PTE can be modified, if not branch to LABEL. Regardless + * restore PTE with value from PTR when done. + */ +-static void __init ++static void __cpuinit + build_pte_modifiable(u32 **p, struct label **l, struct reloc **r, + unsigned int pte, unsigned int ptr, enum label_id lid) + { +@@ -1542,7 +1544,7 @@ + * This places the pte into ENTRYLO0 and writes it with tlbwi. + * Then it returns. + */ +-static void __init ++static void __cpuinit + build_r3000_pte_reload_tlbwi(u32 **p, unsigned int pte, unsigned int tmp) + { + i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */ +@@ -1558,7 +1560,7 @@ + * may have the probe fail bit set as a result of a trap on a + * kseg2 access, i.e. without refill. Then it returns. + */ +-static void __init ++static void __cpuinit + build_r3000_tlb_reload_write(u32 **p, struct label **l, struct reloc **r, + unsigned int pte, unsigned int tmp) + { +@@ -1575,7 +1577,7 @@ + i_rfe(p); /* branch delay */ + } + +-static void __init ++static void __cpuinit + build_r3000_tlbchange_handler_head(u32 **p, unsigned int pte, + unsigned int ptr) + { +@@ -1595,7 +1597,7 @@ + i_tlbp(p); /* load delay */ + } + +-static void __init build_r3000_tlb_load_handler(void) ++static void __cpuinit build_r3000_tlb_load_handler(void) + { + u32 *p = handle_tlbl; + struct label *l = labels; +@@ -1630,7 +1632,7 @@ + pr_debug("\t.set pop\n"); + } + +-static void __init build_r3000_tlb_store_handler(void) ++static void __cpuinit build_r3000_tlb_store_handler(void) + { + u32 *p = handle_tlbs; + struct label *l = labels; +@@ -1665,7 +1667,7 @@ + pr_debug("\t.set pop\n"); + } + +-static void __init build_r3000_tlb_modify_handler(void) ++static void __cpuinit build_r3000_tlb_modify_handler(void) + { + u32 *p = handle_tlbm; + struct label *l = labels; +@@ -1703,7 +1705,7 @@ + /* + * R4000 style TLB load/store/modify handlers. + */ +-static void __init ++static void __cpuinit + build_r4000_tlbchange_handler_head(u32 **p, struct label **l, + struct reloc **r, unsigned int pte, + unsigned int ptr) +@@ -1728,7 +1730,7 @@ + build_tlb_probe_entry(p); + } + +-static void __init ++static void __cpuinit + build_r4000_tlbchange_handler_tail(u32 **p, struct label **l, + struct reloc **r, unsigned int tmp, + unsigned int ptr) +@@ -1745,7 +1747,7 @@ + #endif + } + +-static void __init build_r4000_tlb_load_handler(void) ++static void __cpuinit build_r4000_tlb_load_handler(void) + { + u32 *p = handle_tlbl; + struct label *l = labels; +@@ -1790,7 +1792,7 @@ + pr_debug("\t.set pop\n"); + } + +-static void __init build_r4000_tlb_store_handler(void) ++static void __cpuinit build_r4000_tlb_store_handler(void) + { + u32 *p = handle_tlbs; + struct label *l = labels; +@@ -1826,7 +1828,7 @@ + pr_debug("\t.set pop\n"); + } + +-static void __init build_r4000_tlb_modify_handler(void) ++static void __cpuinit build_r4000_tlb_modify_handler(void) + { + u32 *p = handle_tlbm; + struct label *l = labels; +@@ -1863,7 +1865,7 @@ + pr_debug("\t.set pop\n"); + } + +-void __init build_tlb_refill_handler(void) ++void __cpuinit build_tlb_refill_handler(void) + { + /* + * The refill handler is generated per-CPU, multi-node systems +@@ -1909,7 +1911,7 @@ + } + } + +-void __init flush_tlb_handlers(void) ++void __cpuinit flush_tlb_handlers(void) + { + flush_icache_range((unsigned long)handle_tlbl, + (unsigned long)handle_tlbl + sizeof(handle_tlbl)); +diff -Nurd linux-2.6.24/arch/mips/mm/tlb-r3k.c mer-smartq-kernel/arch/mips/mm/tlb-r3k.c +--- linux-2.6.24/arch/mips/mm/tlb-r3k.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/tlb-r3k.c 2009-11-17 12:13:29.000000000 +0100 +@@ -246,10 +246,6 @@ + old_pagemask = read_c0_pagemask(); + w = read_c0_wired(); + write_c0_wired(w + 1); +- if (read_c0_wired() != w + 1) { +- printk("[tlbwired] No WIRED reg?\n"); +- return; +- } + write_c0_index(w << 8); + write_c0_pagemask(pagemask); + write_c0_entryhi(entryhi); +@@ -281,7 +277,7 @@ + } + } + +-void __init tlb_init(void) ++void __cpuinit tlb_init(void) + { + local_flush_tlb_all(); + +diff -Nurd linux-2.6.24/arch/mips/mm/tlb-r4k.c mer-smartq-kernel/arch/mips/mm/tlb-r4k.c +--- linux-2.6.24/arch/mips/mm/tlb-r4k.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/tlb-r4k.c 2009-11-17 12:13:29.000000000 +0100 +@@ -388,7 +388,7 @@ + * lifetime of the system + */ + +-static int temp_tlb_entry __initdata; ++static int temp_tlb_entry __cpuinitdata; + + __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, + unsigned long entryhi, unsigned long pagemask) +@@ -427,7 +427,7 @@ + return ret; + } + +-static void __init probe_tlb(unsigned long config) ++static void __cpuinit probe_tlb(unsigned long config) + { + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int reg; +@@ -455,7 +455,7 @@ + c->tlbsize = ((reg >> 25) & 0x3f) + 1; + } + +-static int __initdata ntlb = 0; ++static int __cpuinitdata ntlb = 0; + static int __init set_ntlb(char *str) + { + get_option(&str, &ntlb); +@@ -464,7 +464,7 @@ + + __setup("ntlb=", set_ntlb); + +-void __init tlb_init(void) ++void __cpuinit tlb_init(void) + { + unsigned int config = read_c0_config(); + +@@ -473,12 +473,15 @@ + * - On R4600 1.7 the tlbp never hits for pages smaller than + * the value in the c0_pagemask register. + * - The entire mm handling assumes the c0_pagemask register to +- * be set for 4kb pages. ++ * be set to fixed-size pages. + */ + probe_tlb(config); + write_c0_pagemask(PM_DEFAULT_MASK); + write_c0_wired(0); +- write_c0_framemask(0); ++ if (current_cpu_type() == CPU_R10000 || ++ current_cpu_type() == CPU_R12000 || ++ current_cpu_type() == CPU_R14000) ++ write_c0_framemask(0); + temp_tlb_entry = current_cpu_data.tlbsize - 1; + + /* From this point on the ARC firmware is dead. */ +diff -Nurd linux-2.6.24/arch/mips/mm/tlb-r8k.c mer-smartq-kernel/arch/mips/mm/tlb-r8k.c +--- linux-2.6.24/arch/mips/mm/tlb-r8k.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/mm/tlb-r8k.c 2009-11-17 12:13:29.000000000 +0100 +@@ -214,14 +214,14 @@ + local_irq_restore(flags); + } + +-static void __init probe_tlb(unsigned long config) ++static void __cpuinit probe_tlb(unsigned long config) + { + struct cpuinfo_mips *c = ¤t_cpu_data; + + c->tlbsize = 3 * 128; /* 3 sets each 128 entries */ + } + +-void __init tlb_init(void) ++void __cpuinit tlb_init(void) + { + unsigned int config = read_c0_config(); + unsigned long status; +diff -Nurd linux-2.6.24/arch/mips/pci/pci-bcm1480.c mer-smartq-kernel/arch/mips/pci/pci-bcm1480.c +--- linux-2.6.24/arch/mips/pci/pci-bcm1480.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/pci/pci-bcm1480.c 2009-11-17 12:13:29.000000000 +0100 +@@ -185,8 +185,8 @@ + + static struct resource bcm1480_io_resource = { + .name = "BCM1480 PCI I/O", +- .start = 0x2c000000UL, +- .end = 0x2dffffffUL, ++ .start = A_BCM1480_PHYS_PCI_IO_MATCH_BYTES, ++ .end = A_BCM1480_PHYS_PCI_IO_MATCH_BYTES + 0x1ffffffUL, + .flags = IORESOURCE_IO, + }; + +@@ -194,6 +194,7 @@ + .pci_ops = &bcm1480_pci_ops, + .mem_resource = &bcm1480_mem_resource, + .io_resource = &bcm1480_io_resource, ++ .io_offset = A_BCM1480_PHYS_PCI_IO_MATCH_BYTES, + }; + + +@@ -249,8 +250,10 @@ + * XXX ehs: Should this happen in PCI Device mode? + */ + +- set_io_port_base((unsigned long) +- ioremap(A_BCM1480_PHYS_PCI_IO_MATCH_BYTES, 65536)); ++ bcm1480_controller.io_map_base = (unsigned long) ++ ioremap(A_BCM1480_PHYS_PCI_IO_MATCH_BYTES, 65536); ++ bcm1480_controller.io_map_base -= bcm1480_controller.io_offset; ++ set_io_port_base(bcm1480_controller.io_map_base); + isa_slot_offset = (unsigned long) + ioremap(A_BCM1480_PHYS_PCI_MEM_MATCH_BYTES, 1024*1024); + +diff -Nurd linux-2.6.24/arch/mips/pci/pci-bcm1480ht.c mer-smartq-kernel/arch/mips/pci/pci-bcm1480ht.c +--- linux-2.6.24/arch/mips/pci/pci-bcm1480ht.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/pci/pci-bcm1480ht.c 2009-11-17 12:13:29.000000000 +0100 +@@ -180,8 +180,8 @@ + + static struct resource bcm1480ht_io_resource = { + .name = "BCM1480 HT I/O", +- .start = 0x00000000UL, +- .end = 0x01ffffffUL, ++ .start = A_BCM1480_PHYS_HT_IO_MATCH_BYTES, ++ .end = A_BCM1480_PHYS_HT_IO_MATCH_BYTES + 0x01ffffffUL, + .flags = IORESOURCE_IO, + }; + +@@ -191,29 +191,22 @@ + .io_resource = &bcm1480ht_io_resource, + .index = 1, + .get_busno = bcm1480ht_pcibios_get_busno, ++ .io_offset = A_BCM1480_PHYS_HT_IO_MATCH_BYTES, + }; + + static int __init bcm1480ht_pcibios_init(void) + { +- uint32_t cmdreg; +- + ht_cfg_space = ioremap(A_BCM1480_PHYS_HT_CFG_MATCH_BITS, 16*1024*1024); + +- /* +- * See if the PCI bus has been configured by the firmware. +- */ +- cmdreg = READCFG32(CFGOFFSET(0, PCI_DEVFN(PCI_BRIDGE_DEVICE, 0), +- PCI_COMMAND)); +- if (!(cmdreg & PCI_COMMAND_MASTER)) { +- printk("HT: Skipping HT probe. Bus is not initialized.\n"); +- iounmap(ht_cfg_space); +- return 1; /* XXX */ +- } ++ /* CFE doesn't always init all HT paths, so we always scan */ + bcm1480ht_bus_status |= PCI_BUS_ENABLED; + + ht_eoi_space = (unsigned long) + ioremap(A_BCM1480_PHYS_HT_SPECIAL_MATCH_BYTES, + 4 * 1024 * 1024); ++ bcm1480ht_controller.io_map_base = (unsigned long) ++ ioremap(A_BCM1480_PHYS_HT_IO_MATCH_BYTES, 65536); ++ bcm1480ht_controller.io_map_base -= bcm1480ht_controller.io_offset; + + register_pci_controller(&bcm1480ht_controller); + +diff -Nurd linux-2.6.24/arch/mips/pci/pci.c mer-smartq-kernel/arch/mips/pci/pci.c +--- linux-2.6.24/arch/mips/pci/pci.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/pci/pci.c 2009-11-17 12:13:29.000000000 +0100 +@@ -177,6 +177,11 @@ + continue; + + r = &dev->resource[idx]; ++ if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) ++ continue; ++ if ((idx == PCI_ROM_RESOURCE) && ++ (!(r->flags & IORESOURCE_ROM_ENABLE))) ++ continue; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev)); + return -EINVAL; +@@ -186,8 +191,6 @@ + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } +- if (dev->resource[PCI_ROM_RESOURCE].start) +- cmd |= PCI_COMMAND_MEMORY; + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); +@@ -254,7 +257,7 @@ + } + } + +-void pcibios_fixup_bus(struct pci_bus *bus) ++void __devinit pcibios_fixup_bus(struct pci_bus *bus) + { + /* Propagate hose info into the subordinate devices. */ + +diff -Nurd linux-2.6.24/arch/mips/pci/pci-ip27.c mer-smartq-kernel/arch/mips/pci/pci-ip27.c +--- linux-2.6.24/arch/mips/pci/pci-ip27.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/pci/pci-ip27.c 2009-11-17 12:13:29.000000000 +0100 +@@ -40,7 +40,7 @@ + + extern struct pci_ops bridge_pci_ops; + +-int __init bridge_probe(nasid_t nasid, int widget_id, int masterwid) ++int __cpuinit bridge_probe(nasid_t nasid, int widget_id, int masterwid) + { + unsigned long offset = NODE_OFFSET(nasid); + struct bridge_controller *bc; +@@ -136,25 +136,47 @@ + */ + int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) + { ++ return 0; ++} ++ ++/* Most MIPS systems have straight-forward swizzling needs. */ ++static inline u8 bridge_swizzle(u8 pin, u8 slot) ++{ ++ return (((pin - 1) + slot) % 4) + 1; ++} ++ ++static inline struct pci_dev *bridge_root_dev(struct pci_dev *dev) ++{ ++ while (dev->bus->parent) { ++ /* Move up the chain of bridges. */ ++ dev = dev->bus->self; ++ } ++ ++ return dev; ++} ++ ++/* Do platform specific device initialization at pci_enable_device() time */ ++int pcibios_plat_dev_init(struct pci_dev *dev) ++{ + struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus); +- int irq = bc->pci_int[slot]; ++ struct pci_dev *rdev = bridge_root_dev(dev); ++ int slot = PCI_SLOT(rdev->devfn); ++ int irq; + ++ irq = bc->pci_int[slot]; + if (irq == -1) { +- irq = bc->pci_int[slot] = request_bridge_irq(bc); ++ irq = request_bridge_irq(bc); + if (irq < 0) +- panic("Can't allocate interrupt for PCI device %s\n", +- pci_name(dev)); ++ return irq; ++ ++ bc->pci_int[slot] = irq; + } + + irq_to_bridge[irq] = bc; + irq_to_slot[irq] = slot; + +- return irq; +-} ++ dev->irq = irq; + +-/* Do platform specific device initialization at pci_enable_device() time */ +-int pcibios_plat_dev_init(struct pci_dev *dev) +-{ + return 0; + } + +diff -Nurd linux-2.6.24/arch/mips/pmc-sierra/yosemite/smp.c mer-smartq-kernel/arch/mips/pmc-sierra/yosemite/smp.c +--- linux-2.6.24/arch/mips/pmc-sierra/yosemite/smp.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/pmc-sierra/yosemite/smp.c 2009-11-17 12:13:29.000000000 +0100 +@@ -7,10 +7,10 @@ + + #define LAUNCHSTACK_SIZE 256 + +-static __initdata DEFINE_SPINLOCK(launch_lock); ++static __cpuinitdata DEFINE_SPINLOCK(launch_lock); + +-static unsigned long secondary_sp __initdata; +-static unsigned long secondary_gp __initdata; ++static unsigned long secondary_sp __cpuinitdata; ++static unsigned long secondary_gp __cpuinitdata; + + static unsigned char launchstack[LAUNCHSTACK_SIZE] __initdata + __attribute__((aligned(2 * sizeof(long)))); +diff -Nurd linux-2.6.24/arch/mips/sgi-ip22/ip22-int.c mer-smartq-kernel/arch/mips/sgi-ip22/ip22-int.c +--- linux-2.6.24/arch/mips/sgi-ip22/ip22-int.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/sgi-ip22/ip22-int.c 2009-11-17 12:13:29.000000000 +0100 +@@ -68,7 +68,7 @@ + sgint->imask1 |= (1 << (irq - SGINT_LOCAL1)); + } + +-void disable_local1_irq(unsigned int irq) ++static void disable_local1_irq(unsigned int irq) + { + sgint->imask1 &= ~(1 << (irq - SGINT_LOCAL1)); + } +@@ -87,7 +87,7 @@ + sgint->cmeimask0 |= (1 << (irq - SGINT_LOCAL2)); + } + +-void disable_local2_irq(unsigned int irq) ++static void disable_local2_irq(unsigned int irq) + { + sgint->cmeimask0 &= ~(1 << (irq - SGINT_LOCAL2)); + if (!sgint->cmeimask0) +@@ -108,7 +108,7 @@ + sgint->cmeimask1 |= (1 << (irq - SGINT_LOCAL3)); + } + +-void disable_local3_irq(unsigned int irq) ++static void disable_local3_irq(unsigned int irq) + { + sgint->cmeimask1 &= ~(1 << (irq - SGINT_LOCAL3)); + if (!sgint->cmeimask1) +@@ -344,6 +344,6 @@ + + #ifdef CONFIG_EISA + if (ip22_is_fullhouse()) /* Only Indigo-2 has EISA stuff */ +- ip22_eisa_init(); ++ ip22_eisa_init(); + #endif + } +diff -Nurd linux-2.6.24/arch/mips/sgi-ip22/ip22-platform.c mer-smartq-kernel/arch/mips/sgi-ip22/ip22-platform.c +--- linux-2.6.24/arch/mips/sgi-ip22/ip22-platform.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/sgi-ip22/ip22-platform.c 2009-11-17 12:13:29.000000000 +0100 +@@ -150,7 +150,7 @@ + return res; + + /* Second HPC is missing? */ +- if (!ip22_is_fullhouse() || ++ if (ip22_is_fullhouse() || + get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1])) + return 0; + +diff -Nurd linux-2.6.24/arch/mips/sgi-ip27/ip27-init.c mer-smartq-kernel/arch/mips/sgi-ip27/ip27-init.c +--- linux-2.6.24/arch/mips/sgi-ip27/ip27-init.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/sgi-ip27/ip27-init.c 2009-11-17 12:13:29.000000000 +0100 +@@ -54,7 +54,7 @@ + + extern void xtalk_probe_node(cnodeid_t nid); + +-static void __init per_hub_init(cnodeid_t cnode) ++static void __cpuinit per_hub_init(cnodeid_t cnode) + { + struct hub_data *hub = hub_data(cnode); + nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); +diff -Nurd linux-2.6.24/arch/mips/sgi-ip27/ip27-timer.c mer-smartq-kernel/arch/mips/sgi-ip27/ip27-timer.c +--- linux-2.6.24/arch/mips/sgi-ip27/ip27-timer.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/sgi-ip27/ip27-timer.c 2009-11-17 12:13:29.000000000 +0100 +@@ -158,7 +158,7 @@ + } + } + +-unsigned int rt_timer_irq; ++int rt_timer_irq; + + static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id) + { +@@ -219,7 +219,7 @@ + + static void __init hub_rt_clock_event_global_init(void) + { +- unsigned int irq; ++ int irq; + + do { + smp_wmb(); +@@ -285,7 +285,7 @@ + set_c0_status(SRB_TIMOCLK); + } + +-void __init hub_rtc_init(cnodeid_t cnode) ++void __cpuinit hub_rtc_init(cnodeid_t cnode) + { + /* + * We only need to initialize the current node. +diff -Nurd linux-2.6.24/arch/mips/sgi-ip27/ip27-xtalk.c mer-smartq-kernel/arch/mips/sgi-ip27/ip27-xtalk.c +--- linux-2.6.24/arch/mips/sgi-ip27/ip27-xtalk.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/sgi-ip27/ip27-xtalk.c 2009-11-17 12:13:29.000000000 +0100 +@@ -22,7 +22,7 @@ + + extern int bridge_probe(nasid_t nasid, int widget, int masterwid); + +-static int __init probe_one_port(nasid_t nasid, int widget, int masterwid) ++static int __cpuinit probe_one_port(nasid_t nasid, int widget, int masterwid) + { + widgetreg_t widget_id; + xwidget_part_num_t partnum; +@@ -46,7 +46,7 @@ + return 0; + } + +-static int __init xbow_probe(nasid_t nasid) ++static int __cpuinit xbow_probe(nasid_t nasid) + { + lboard_t *brd; + klxbow_t *xbow_p; +@@ -99,7 +99,7 @@ + return 0; + } + +-void __init xtalk_probe_node(cnodeid_t nid) ++void __cpuinit xtalk_probe_node(cnodeid_t nid) + { + volatile u64 hubreg; + nasid_t nasid; +diff -Nurd linux-2.6.24/arch/mips/sgi-ip32/ip32-irq.c mer-smartq-kernel/arch/mips/sgi-ip32/ip32-irq.c +--- linux-2.6.24/arch/mips/sgi-ip32/ip32-irq.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/sgi-ip32/ip32-irq.c 2009-11-17 12:13:29.000000000 +0100 +@@ -425,6 +425,11 @@ + BUILD_BUG_ON(MACEISA_SERIAL2_RDMAOR_IRQ - MACEISA_AUDIO_SW_IRQ != 31); + + crime_int = crime->istat & crime_mask; ++ ++ /* crime sometime delivers spurious interrupts, ignore them */ ++ if (unlikely(crime_int == 0)) ++ return; ++ + irq = MACE_VID_IN1_IRQ + __ffs(crime_int); + + if (crime_int & CRIME_MACEISA_INT_MASK) { +diff -Nurd linux-2.6.24/arch/mips/sibyte/bcm1480/irq.c mer-smartq-kernel/arch/mips/sibyte/bcm1480/irq.c +--- linux-2.6.24/arch/mips/sibyte/bcm1480/irq.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/sibyte/bcm1480/irq.c 2009-11-17 12:13:29.000000000 +0100 +@@ -25,6 +25,7 @@ + #include <linux/kernel_stat.h> + + #include <asm/errno.h> ++#include <asm/gdb-stub.h> + #include <asm/irq_regs.h> + #include <asm/signal.h> + #include <asm/system.h> +diff -Nurd linux-2.6.24/arch/mips/sibyte/sb1250/irq.c mer-smartq-kernel/arch/mips/sibyte/sb1250/irq.c +--- linux-2.6.24/arch/mips/sibyte/sb1250/irq.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/sibyte/sb1250/irq.c 2009-11-17 12:13:29.000000000 +0100 +@@ -26,6 +26,7 @@ + #include <linux/kernel_stat.h> + + #include <asm/errno.h> ++#include <asm/gdb-stub.h> + #include <asm/signal.h> + #include <asm/system.h> + #include <asm/time.h> +diff -Nurd linux-2.6.24/arch/mips/vr41xx/common/irq.c mer-smartq-kernel/arch/mips/vr41xx/common/irq.c +--- linux-2.6.24/arch/mips/vr41xx/common/irq.c 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/arch/mips/vr41xx/common/irq.c 2009-11-17 12:13:29.000000000 +0100 +@@ -72,6 +72,7 @@ + cascade = irq_cascade + irq; + if (cascade->get_irq != NULL) { + unsigned int source_irq = irq; ++ int ret; + desc = irq_desc + source_irq; + if (desc->chip->mask_ack) + desc->chip->mask_ack(source_irq); +@@ -79,8 +80,9 @@ + desc->chip->mask(source_irq); + desc->chip->ack(source_irq); + } +- irq = cascade->get_irq(irq); +- if (irq < 0) ++ ret = cascade->get_irq(irq); ++ irq = ret; ++ if (ret < 0) + atomic_inc(&irq_err_count); + else + irq_dispatch(irq); +diff -Nurd linux-2.6.24/drivers/net/Kconfig mer-smartq-kernel/drivers/net/Kconfig +--- linux-2.6.24/drivers/net/Kconfig 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/drivers/net/Kconfig 2009-11-17 18:05:55.000000000 +0100 +@@ -2348,6 +2348,13 @@ + Some boards that use the Discovery chipset are the Momenco + Ocelot C and Jaguar ATX and Pegasos II. + ++config TITAN_GE ++ bool "PMC-Sierra TITAN Gigabit Ethernet Support" ++ depends on PMC_YOSEMITE ++ help ++ This enables support for the the integrated ethernet of ++ PMC-Sierra's Titan SoC. ++ + config QLA3XXX + tristate "QLogic QLA3XXX Network Driver Support" + depends on PCI +diff -Nurd linux-2.6.24/drivers/net/Makefile mer-smartq-kernel/drivers/net/Makefile +--- linux-2.6.24/drivers/net/Makefile 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/drivers/net/Makefile 2009-11-17 12:13:31.000000000 +0100 +@@ -124,6 +124,8 @@ + obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o + obj-$(CONFIG_QLA3XXX) += qla3xxx.o + ++obj-$(CONFIG_TITAN_GE) += titan_mdio.o titan_ge.o ++ + obj-$(CONFIG_PPP) += ppp_generic.o + obj-$(CONFIG_PPP_ASYNC) += ppp_async.o + obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o +diff -Nurd linux-2.6.24/drivers/net/titan_ge.c mer-smartq-kernel/drivers/net/titan_ge.c +--- linux-2.6.24/drivers/net/titan_ge.c 1970-01-01 01:00:00.000000000 +0100 ++++ mer-smartq-kernel/drivers/net/titan_ge.c 2009-11-17 12:13:31.000000000 +0100 +@@ -0,0 +1,2069 @@ ++/* ++ * drivers/net/titan_ge.c - Driver for Titan ethernet ports ++ * ++ * Copyright (C) 2003 PMC-Sierra Inc. ++ * Author : Manish Lachwani (lachwani@pmc-sierra.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * The MAC unit of the Titan consists of the following: ++ * ++ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO ++ * -> FIFO is where the incoming and outgoing data is placed ++ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes ++ * the data into the FIFO for Rx ++ * -> TMAC is the outgoing MAC interface and RMAC is the incoming. ++ * -> AFX is the address filtering block ++ * -> GMII block to communicate with the PHY ++ * ++ * Rx will look like the following: ++ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory ++ * ++ * Tx will look like the following: ++ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII ++ * ++ * The Titan driver has support for the following performance features: ++ * -> Rx side checksumming ++ * -> Jumbo Frames ++ * -> Interrupt Coalscing ++ * -> Rx NAPI ++ * -> SKB Recycling ++ * -> Transmit/Receive descriptors in SRAM ++ * -> Fast routing for IP forwarding ++ */ ++ ++#include <linux/dma-mapping.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/ioport.h> ++#include <linux/interrupt.h> ++#include <linux/slab.h> ++#include <linux/string.h> ++#include <linux/errno.h> ++#include <linux/ip.h> ++#include <linux/init.h> ++#include <linux/in.h> ++#include <linux/platform_device.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/mii.h> ++#include <linux/delay.h> ++#include <linux/skbuff.h> ++#include <linux/prefetch.h> ++ ++/* For MII specifc registers, titan_mdio.h should be included */ ++#include <net/ip.h> ++ ++#include <asm/bitops.h> ++#include <asm/io.h> ++#include <asm/types.h> ++#include <asm/pgtable.h> ++#include <asm/system.h> ++#include <asm/titan_dep.h> ++ ++#include "titan_ge.h" ++#include "titan_mdio.h" ++ ++/* Static Function Declarations */ ++static int titan_ge_eth_open(struct net_device *); ++static void titan_ge_eth_stop(struct net_device *); ++static struct net_device_stats *titan_ge_get_stats(struct net_device *); ++static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int, ++ unsigned long, unsigned long, ++ unsigned long); ++static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int, ++ unsigned long, unsigned long); ++ ++static int titan_ge_open(struct net_device *); ++static int titan_ge_start_xmit(struct sk_buff *, struct net_device *); ++static int titan_ge_stop(struct net_device *); ++ ++static unsigned long titan_ge_tx_coal(unsigned long, int); ++ ++static void titan_ge_port_reset(unsigned int); ++static int titan_ge_free_tx_queue(titan_ge_port_info *); ++static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *); ++static int titan_ge_port_start(struct net_device *, titan_ge_port_info *); ++ ++static int titan_ge_return_tx_desc(titan_ge_port_info *, int); ++ ++/* ++ * Some configuration for the FIFO and the XDMA channel needs ++ * to be done only once for all the ports. This flag controls ++ * that ++ */ ++static unsigned long config_done; ++ ++/* ++ * One time out of memory flag ++ */ ++static unsigned int oom_flag; ++ ++static int titan_ge_poll(struct net_device *netdev, int *budget); ++ ++static int titan_ge_receive_queue(struct net_device *, unsigned int); ++ ++static struct platform_device *titan_ge_device[3]; ++ ++/* MAC Address */ ++extern unsigned char titan_ge_mac_addr_base[6]; ++ ++unsigned long titan_ge_base; ++static unsigned long titan_ge_sram; ++ ++static char titan_string[] = "titan"; ++ ++/* ++ * The Titan GE has two alignment requirements: ++ * -> skb->data to be cacheline aligned (32 byte) ++ * -> IP header alignment to 16 bytes ++ * ++ * The latter is not implemented. So, that results in an extra copy on ++ * the Rx. This is a big performance hog. For the former case, the ++ * dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size ++ * requested is calculated: ++ * ++ * Ethernet Frame Size : 1518 ++ * Ethernet Header : 14 ++ * Future Titan change for IP header alignment : 2 ++ * ++ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes. For IP header ++ * alignment, we use skb_reserve(). ++ */ ++ ++#define ALIGNED_RX_SKB_ADDR(addr) \ ++ ((((unsigned long)(addr) + (64UL - 1UL)) \ ++ & ~(64UL - 1UL)) - (unsigned long)(addr)) ++ ++#define titan_ge_alloc_skb(__length, __gfp_flags) \ ++({ struct sk_buff *__skb; \ ++ __skb = alloc_skb((__length) + 64, (__gfp_flags)); \ ++ if(__skb) { \ ++ int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \ ++ if(__offset) \ ++ skb_reserve(__skb, __offset); \ ++ } \ ++ __skb; \ ++}) ++ ++/* ++ * Configure the GMII block of the Titan based on what the PHY tells us ++ */ ++static void titan_ge_gmii_config(int port_num) ++{ ++ unsigned int reg_data = 0, phy_reg; ++ int err; ++ ++ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); ++ ++ if (err == TITAN_GE_MDIO_ERROR) { ++ printk(KERN_ERR ++ "Could not read PHY control register 0x11 \n"); ++ printk(KERN_ERR ++ "Setting speed to 1000 Mbps and Duplex to Full \n"); ++ ++ return; ++ } ++ ++ err = titan_ge_mdio_write(port_num, TITAN_GE_MDIO_PHY_IE, 0); ++ ++ if (phy_reg & 0x8000) { ++ if (phy_reg & 0x2000) { ++ /* Full Duplex and 1000 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x201); ++ } else { ++ /* Half Duplex and 1000 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x2201); ++ } ++ } ++ if (phy_reg & 0x4000) { ++ if (phy_reg & 0x2000) { ++ /* Full Duplex and 100 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x100); ++ } else { ++ /* Half Duplex and 100 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x2100); ++ } ++ } ++ reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL + ++ (port_num << 12)); ++ reg_data |= 0x3; ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL + ++ (port_num << 12)), reg_data); ++} ++ ++/* ++ * Enable the TMAC if it is not ++ */ ++static void titan_ge_enable_tx(unsigned int port_num) ++{ ++ unsigned long reg_data; ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); ++ if (!(reg_data & 0x8000)) { ++ printk("TMAC disabled for port %d!! \n", port_num); ++ ++ reg_data |= 0x0001; /* Enable TMAC */ ++ reg_data |= 0x4000; /* CRC Check Enable */ ++ reg_data |= 0x2000; /* Padding enable */ ++ reg_data |= 0x0800; /* CRC Add enable */ ++ reg_data |= 0x0080; /* PAUSE frame */ ++ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ } ++} ++ ++/* ++ * Tx Timeout function ++ */ ++static void titan_ge_tx_timeout(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ printk(KERN_INFO "%s: TX timeout ", netdev->name); ++ printk(KERN_INFO "Resetting card \n"); ++ ++ /* Do the reset outside of interrupt context */ ++ schedule_work(&titan_ge_eth->tx_timeout_task); ++} ++ ++/* ++ * Update the AFX tables for UC and MC for slice 0 only ++ */ ++static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth) ++{ ++ int port = titan_ge_eth->port_num; ++ unsigned int i; ++ volatile unsigned long reg_data = 0; ++ u8 p_addr[6]; ++ ++ memcpy(p_addr, titan_ge_eth->port_mac_addr, 6); ++ ++ /* Set the MAC address here for TMAC and RMAC */ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ ++ TITAN_GE_WRITE((0x112c | (port << 12)), 0x1); ++ /* Configure the eight address filters */ ++ for (i = 0; i < 8; i++) { ++ /* Select each of the eight filters */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 + ++ (port << 12)), i); ++ ++ /* Configure the match */ ++ reg_data = 0x9; /* Forward Enable Bit */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 + ++ (port << 12)), reg_data); ++ ++ /* Finally, AFX Exact Match Address Registers */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ ++ /* VLAN id set to 0 */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID + ++ (port << 12)), 0); ++ } ++} ++ ++/* ++ * Actual Routine to reset the adapter when the timeout occurred ++ */ ++static void titan_ge_tx_timeout_task(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ int port = titan_ge_eth->port_num; ++ ++ printk("Titan GE: Transmit timed out. Resetting ... \n"); ++ ++ /* Dump debug info */ ++ printk(KERN_ERR "TRTG cause : %x \n", ++ TITAN_GE_READ(0x100c + (port << 12))); ++ ++ /* Fix this for the other ports */ ++ printk(KERN_ERR "FIFO cause : %x \n", TITAN_GE_READ(0x482c)); ++ printk(KERN_ERR "IE cause : %x \n", TITAN_GE_READ(0x0040)); ++ printk(KERN_ERR "XDMA GDI ERROR : %x \n", ++ TITAN_GE_READ(0x5008 + (port << 8))); ++ printk(KERN_ERR "CHANNEL ERROR: %x \n", ++ TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT ++ + (port << 8))); ++ ++ netif_device_detach(netdev); ++ titan_ge_port_reset(titan_ge_eth->port_num); ++ titan_ge_port_start(netdev, titan_ge_eth); ++ netif_device_attach(netdev); ++} ++ ++/* ++ * Change the MTU of the Ethernet Device ++ */ ++static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned long flags; ++ ++ if ((new_mtu > 9500) || (new_mtu < 64)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ ++ netdev->mtu = new_mtu; ++ ++ /* Now we have to reopen the interface so that SKBs with the new ++ * size will be allocated */ ++ ++ if (netif_running(netdev)) { ++ titan_ge_eth_stop(netdev); ++ ++ if (titan_ge_eth_open(netdev) != TITAN_OK) { ++ printk(KERN_ERR ++ "%s: Fatal error on opening device\n", ++ netdev->name); ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ return -1; ++ } ++ } ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ return 0; ++} ++ ++/* ++ * Titan Gbe Interrupt Handler. All the three ports send interrupt to one line ++ * only. Once an interrupt is triggered, figure out the port and then check ++ * the channel. ++ */ ++static irqreturn_t titan_ge_int_handler(int irq, void *dev_id) ++{ ++ struct net_device *netdev = (struct net_device *) dev_id; ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int reg_data; ++ unsigned int eth_int_cause_error = 0, is; ++ unsigned long eth_int_cause1; ++ int err = 0; ++#ifdef CONFIG_SMP ++ unsigned long eth_int_cause2; ++#endif ++ ++ /* Ack the CPU interrupt */ ++ switch (port_num) { ++ case 0: ++ is = OCD_READ(RM9000x2_OCD_INTP0STATUS1); ++ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR1, is); ++ ++#ifdef CONFIG_SMP ++ is = OCD_READ(RM9000x2_OCD_INTP1STATUS1); ++ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR1, is); ++#endif ++ break; ++ ++ case 1: ++ is = OCD_READ(RM9000x2_OCD_INTP0STATUS0); ++ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR0, is); ++ ++#ifdef CONFIG_SMP ++ is = OCD_READ(RM9000x2_OCD_INTP1STATUS0); ++ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR0, is); ++#endif ++ break; ++ ++ case 2: ++ is = OCD_READ(RM9000x2_OCD_INTP0STATUS4); ++ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR4, is); ++ ++#ifdef CONFIG_SMP ++ is = OCD_READ(RM9000x2_OCD_INTP1STATUS4); ++ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR4, is); ++#endif ++ } ++ ++ eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); ++#ifdef CONFIG_SMP ++ eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B); ++#endif ++ ++ /* Spurious interrupt */ ++#ifdef CONFIG_SMP ++ if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) { ++#else ++ if (eth_int_cause1 == 0) { ++#endif ++ eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT + ++ (port_num << 8)); ++ ++ if (eth_int_cause_error == 0) ++ return IRQ_NONE; ++ } ++ ++ /* Handle Tx first. No need to ack interrupts */ ++#ifdef CONFIG_SMP ++ if ( (eth_int_cause1 & 0x20202) || ++ (eth_int_cause2 & 0x20202) ) ++#else ++ if (eth_int_cause1 & 0x20202) ++#endif ++ titan_ge_free_tx_queue(titan_ge_eth); ++ ++ /* Handle the Rx next */ ++#ifdef CONFIG_SMP ++ if ( (eth_int_cause1 & 0x10101) || ++ (eth_int_cause2 & 0x10101)) { ++#else ++ if (eth_int_cause1 & 0x10101) { ++#endif ++ if (netif_rx_schedule_prep(netdev)) { ++ unsigned int ack; ++ ++ ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); ++ /* Disable Tx and Rx both */ ++ if (port_num == 0) ++ ack &= ~(0x3); ++ if (port_num == 1) ++ ack &= ~(0x300); ++ ++ if (port_num == 2) ++ ack &= ~(0x30000); ++ ++ /* Interrupts have been disabled */ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack); ++ ++ __netif_rx_schedule(netdev); ++ } ++ } ++ ++ /* Handle error interrupts */ ++ if (eth_int_cause_error && (eth_int_cause_error != 0x2)) { ++ printk(KERN_ERR ++ "XDMA Channel Error : %x on port %d\n", ++ eth_int_cause_error, port_num); ++ ++ printk(KERN_ERR ++ "XDMA GDI Hardware error : %x on port %d\n", ++ TITAN_GE_READ(0x5008 + (port_num << 8)), port_num); ++ ++ printk(KERN_ERR ++ "XDMA currently has %d Rx descriptors \n", ++ TITAN_GE_READ(0x5048 + (port_num << 8))); ++ ++ printk(KERN_ERR ++ "XDMA currently has prefetcted %d Rx descriptors \n", ++ TITAN_GE_READ(0x505c + (port_num << 8))); ++ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + ++ (port_num << 8)), eth_int_cause_error); ++ } ++ ++ /* ++ * PHY interrupt to inform abt the changes. Reading the ++ * PHY Status register will clear the interrupt ++ */ ++ if ((!(eth_int_cause1 & 0x30303)) && ++ (eth_int_cause_error == 0)) { ++ err = ++ titan_ge_mdio_read(port_num, ++ TITAN_GE_MDIO_PHY_IS, ®_data); ++ ++ if (reg_data & 0x0400) { ++ /* Link status change */ ++ titan_ge_mdio_read(port_num, ++ TITAN_GE_MDIO_PHY_STATUS, ®_data); ++ if (!(reg_data & 0x0400)) { ++ /* Link is down */ ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ } else { ++ /* Link is up */ ++ netif_carrier_on(netdev); ++ netif_wake_queue(netdev); ++ ++ /* Enable the queue */ ++ titan_ge_enable_tx(port_num); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Multicast and Promiscuous mode set. The ++ * set_multi entry point is called whenever the ++ * multicast address list or the network interface ++ * flags are updated. ++ */ ++static void titan_ge_set_multi(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned long reg_data; ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + ++ (port_num << 12)); ++ ++ if (netdev->flags & IFF_PROMISC) { ++ reg_data |= 0x2; ++ } ++ else if (netdev->flags & IFF_ALLMULTI) { ++ reg_data |= 0x01; ++ reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */ ++ } ++ else { ++ reg_data = 0x2; ++ } ++ ++ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + ++ (port_num << 12)), reg_data); ++ if (reg_data & 0x01) { ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW + ++ (port_num << 12)), 0xffff); ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW + ++ (port_num << 12)), 0xffff); ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI + ++ (port_num << 12)), 0xffff); ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI + ++ (port_num << 12)), 0xffff); ++ } ++} ++ ++/* ++ * Open the network device ++ */ ++static int titan_ge_open(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int irq = TITAN_ETH_PORT_IRQ - port_num; ++ int retval; ++ ++ retval = request_irq(irq, titan_ge_int_handler, ++ SA_INTERRUPT | SA_SAMPLE_RANDOM , netdev->name, netdev); ++ ++ if (retval != 0) { ++ printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n"); ++ return -1; ++ } ++ ++ netdev->irq = irq; ++ printk(KERN_INFO "Assigned IRQ %d to port %d\n", irq, port_num); ++ ++ spin_lock_irq(&(titan_ge_eth->lock)); ++ ++ if (titan_ge_eth_open(netdev) != TITAN_OK) { ++ spin_unlock_irq(&(titan_ge_eth->lock)); ++ printk("%s: Error opening interface \n", netdev->name); ++ free_irq(netdev->irq, netdev); ++ return -EBUSY; ++ } ++ ++ spin_unlock_irq(&(titan_ge_eth->lock)); ++ ++ return 0; ++} ++ ++/* ++ * Allocate the SKBs for the Rx ring. Also used ++ * for refilling the queue ++ */ ++static int titan_ge_rx_task(struct net_device *netdev, ++ titan_ge_port_info *titan_ge_port) ++{ ++ struct device *device = &titan_ge_device[titan_ge_port->port_num]->dev; ++ volatile titan_ge_rx_desc *rx_desc; ++ struct sk_buff *skb; ++ int rx_used_desc; ++ int count = 0; ++ ++ while (titan_ge_port->rx_ring_skbs < titan_ge_port->rx_ring_size) { ++ ++ /* First try to get the skb from the recycler */ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC); ++#else ++ skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC); ++#endif ++ if (unlikely(!skb)) { ++ /* OOM, set the flag */ ++ printk("OOM \n"); ++ oom_flag = 1; ++ break; ++ } ++ count++; ++ skb->dev = netdev; ++ ++ titan_ge_port->rx_ring_skbs++; ++ ++ rx_used_desc = titan_ge_port->rx_used_desc_q; ++ rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]); ++ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ rx_desc->buffer_addr = dma_map_single(device, skb->data, ++ TITAN_GE_JUMBO_BUFSIZE - 2, DMA_FROM_DEVICE); ++#else ++ rx_desc->buffer_addr = dma_map_single(device, skb->data, ++ TITAN_GE_STD_BUFSIZE - 2, DMA_FROM_DEVICE); ++#endif ++ ++ titan_ge_port->rx_skb[rx_used_desc] = skb; ++ rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED; ++ ++ titan_ge_port->rx_used_desc_q = ++ (rx_used_desc + 1) % TITAN_GE_RX_QUEUE; ++ } ++ ++ return count; ++} ++ ++/* ++ * Actual init of the Tital GE port. There is one register for ++ * the channel configuration ++ */ ++static void titan_port_init(struct net_device *netdev, ++ titan_ge_port_info * titan_ge_eth) ++{ ++ unsigned long reg_data; ++ ++ titan_ge_port_reset(titan_ge_eth->port_num); ++ ++ /* First reset the TMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data |= 0x80000000; ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++ ++ udelay(30); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data &= ~(0xc0000000); ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++ ++ /* Now reset the RMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data |= 0x00080000; ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++ ++ udelay(30); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data &= ~(0x000c0000); ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++} ++ ++/* ++ * Start the port. All the hardware specific configuration ++ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX ++ * go here ++ */ ++static int titan_ge_port_start(struct net_device *netdev, ++ titan_ge_port_info * titan_port) ++{ ++ volatile unsigned long reg_data, reg_data1; ++ int port_num = titan_port->port_num; ++ int count = 0; ++ unsigned long reg_data_1; ++ ++ if (config_done == 0) { ++ reg_data = TITAN_GE_READ(0x0004); ++ reg_data |= 0x100; ++ TITAN_GE_WRITE(0x0004, reg_data); ++ ++ reg_data &= ~(0x100); ++ TITAN_GE_WRITE(0x0004, reg_data); ++ ++ /* Turn on GMII/MII mode and turn off TBI mode */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1); ++ reg_data |= 0x00000700; ++ reg_data &= ~(0x00800000); /* Fencing */ ++ ++ TITAN_GE_WRITE(0x000c, 0x00001100); ++ ++ TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data); ++ ++ /* Set the CPU Resource Limit register */ ++ TITAN_GE_WRITE(0x00f8, 0x8); ++ ++ /* Be conservative when using the BIU buffers */ ++ TITAN_GE_WRITE(0x0068, 0x4); ++ } ++ ++ titan_port->tx_threshold = 0; ++ titan_port->rx_threshold = 0; ++ ++ /* We need to write the descriptors for Tx and Rx */ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)), ++ (unsigned long) titan_port->tx_dma); ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)), ++ (unsigned long) titan_port->rx_dma); ++ ++ if (config_done == 0) { ++ /* Step 1: XDMA config */ ++ reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG); ++ reg_data &= ~(0x80000000); /* clear reset */ ++ reg_data |= 0x1 << 29; /* sparse tx descriptor spacing */ ++ reg_data |= 0x1 << 28; /* sparse rx descriptor spacing */ ++ reg_data |= (0x1 << 23) | (0x1 << 24); /* Descriptor Coherency */ ++ reg_data |= (0x1 << 21) | (0x1 << 22); /* Data Coherency */ ++ TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data); ++ } ++ ++ /* IR register for the XDMA */ ++ reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)); ++ reg_data |= 0x80068000; /* No Rx_OOD */ ++ TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data); ++ ++ /* Start the Tx and Rx XDMA controller */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)); ++ reg_data &= 0x4fffffff; /* Clear tx reset */ ++ reg_data &= 0xfff4ffff; /* Clear rx reset */ ++ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ reg_data |= 0xa0 | 0x30030000; ++#else ++ reg_data |= 0x40 | 0x20030000; ++#endif ++ ++#ifndef CONFIG_SMP ++ reg_data &= ~(0x10); ++ reg_data |= 0x0f; /* All of the packet */ ++#endif ++ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data); ++ ++ /* Rx desc count */ ++ count = titan_ge_rx_task(netdev, titan_port); ++ TITAN_GE_WRITE((0x5048 + (port_num << 8)), count); ++ count = TITAN_GE_READ(0x5048 + (port_num << 8)); ++ ++ udelay(30); ++ ++ /* ++ * Step 2: Configure the SDQPF, i.e. FIFO ++ */ ++ if (config_done == 0) { ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); ++ reg_data = 0x1; ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); ++ reg_data &= ~(0x1); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); ++ reg_data = 0x1; ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); ++ reg_data &= ~(0x1); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); ++ } ++ /* ++ * Enable RX FIFO 0, 4 and 8 ++ */ ++ if (port_num == 0) { ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10); ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4844); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x4844, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); ++ ++ reg_data |= (0xff << 10); ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4944); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x4944, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); ++ ++ } ++ ++ if (port_num == 1) { ++ reg_data = TITAN_GE_READ(0x4870); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10) | (0xff + 1); ++ ++ TITAN_GE_WRITE(0x4870, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4874); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x4874, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x4870, reg_data); ++ ++ reg_data = TITAN_GE_READ(0x494c); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(0x494c, reg_data); ++ reg_data |= (0xff << 10) | (0xff + 1); ++ TITAN_GE_WRITE(0x494c, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4950); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x4950, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x494c, reg_data); ++ } ++ ++ /* ++ * Titan 1.2 revision does support port #2 ++ */ ++ if (port_num == 2) { ++ /* ++ * Put the descriptors in the SRAM ++ */ ++ reg_data = TITAN_GE_READ(0x48a0); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x48a4); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x48a4, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ ++ reg_data = TITAN_GE_READ(0x4958); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ TITAN_GE_WRITE(0x4958, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x495c); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x495c, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ } ++ ++ if (port_num == 2) { ++ reg_data = TITAN_GE_READ(0x48a0); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x48a4); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x48a4, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ ++ reg_data = TITAN_GE_READ(0x4958); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ TITAN_GE_WRITE(0x4958, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x495c); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x495c, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ } ++ ++ /* ++ * Step 3: TRTG block enable ++ */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12)); ++ ++ /* ++ * This is the 1.2 revision of the chip. It has fix for the ++ * IP header alignment. Now, the IP header begins at an ++ * aligned address and this wont need an extra copy in the ++ * driver. This performance drawback existed in the previous ++ * versions of the silicon ++ */ ++ reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12)); ++ reg_data_1 |= 0x40000000; ++ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); ++ ++ reg_data_1 |= 0x04000000; ++ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); ++ ++ mdelay(5); ++ ++ reg_data_1 &= ~(0x04000000); ++ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); ++ ++ mdelay(5); ++ ++ reg_data |= 0x0001; ++ TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data); ++ ++ /* ++ * Step 4: Start the Tx activity ++ */ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197); ++#ifdef TITAN_GE_JUMBO_FRAMES ++ TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000); ++#endif ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); ++ reg_data |= 0x0001; /* Enable TMAC */ ++ reg_data |= 0x6c70; /* PAUSE also set */ ++ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data); ++ ++ udelay(30); ++ ++ /* Destination Address drop bit */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)); ++ reg_data |= 0x218; /* DA_DROP bit and pause */ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data); ++ ++ TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3); ++ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000); ++#endif ++ /* Start the Rx activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); ++ reg_data |= 0x0001; /* RMAC Enable */ ++ reg_data |= 0x0010; /* CRC Check enable */ ++ reg_data |= 0x0040; /* Min Frame check enable */ ++ reg_data |= 0x4400; /* Max Frame check enable */ ++ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); ++ ++ udelay(30); ++ ++ /* ++ * Enable the Interrupts for Tx and Rx ++ */ ++ reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); ++ ++ if (port_num == 0) { ++ reg_data1 |= 0x3; ++#ifdef CONFIG_SMP ++ TITAN_GE_WRITE(0x0038, 0x003); ++#else ++ TITAN_GE_WRITE(0x0038, 0x303); ++#endif ++ } ++ ++ if (port_num == 1) { ++ reg_data1 |= 0x300; ++ } ++ ++ if (port_num == 2) ++ reg_data1 |= 0x30000; ++ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1); ++ TITAN_GE_WRITE(0x003c, 0x300); ++ ++ if (config_done == 0) { ++ TITAN_GE_WRITE(0x0024, 0x04000024); /* IRQ vector */ ++ TITAN_GE_WRITE(0x0020, 0x000fb000); /* INTMSG base */ ++ } ++ ++ /* Priority */ ++ reg_data = TITAN_GE_READ(0x1038 + (port_num << 12)); ++ reg_data &= ~(0x00f00000); ++ TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data); ++ ++ /* Step 5: GMII config */ ++ titan_ge_gmii_config(port_num); ++ ++ if (config_done == 0) { ++ TITAN_GE_WRITE(0x1a80, 0); ++ config_done = 1; ++ } ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Function to queue the packet for the Ethernet device ++ */ ++static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth, ++ struct sk_buff * skb) ++{ ++ struct device *device = &titan_ge_device[titan_ge_eth->port_num]->dev; ++ unsigned int curr_desc = titan_ge_eth->tx_curr_desc_q; ++ volatile titan_ge_tx_desc *tx_curr; ++ int port_num = titan_ge_eth->port_num; ++ ++ tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]); ++ tx_curr->buffer_addr = ++ dma_map_single(device, skb->data, skb_headlen(skb), ++ DMA_TO_DEVICE); ++ ++ titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb; ++ tx_curr->buffer_len = skb_headlen(skb); ++ ++ /* Last descriptor enables interrupt and changes ownership */ ++ tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5); ++ ++ /* Kick the XDMA to start the transfer from memory to the FIFO */ ++ TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1); ++ ++ /* Current descriptor updated */ ++ titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE; ++ ++ /* Prefetch the next descriptor */ ++ prefetch((const void *) ++ &titan_ge_eth->tx_desc_area[titan_ge_eth->tx_curr_desc_q]); ++} ++ ++/* ++ * Actually does the open of the Ethernet device ++ */ ++static int titan_ge_eth_open(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ struct device *device = &titan_ge_device[port_num]->dev; ++ unsigned long reg_data; ++ unsigned int phy_reg; ++ int err = 0; ++ ++ /* Stop the Rx activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); ++ reg_data &= ~(0x00000001); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); ++ ++ /* Clear the port interrupts */ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + (port_num << 8)), 0x0); ++ ++ if (config_done == 0) { ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0); ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0); ++ } ++ ++ /* Set the MAC Address */ ++ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); ++ ++ if (config_done == 0) ++ titan_port_init(netdev, titan_ge_eth); ++ ++ titan_ge_update_afx(titan_ge_eth); ++ ++ /* Allocate the Tx ring now */ ++ titan_ge_eth->tx_ring_skbs = 0; ++ titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE; ++ ++ /* Allocate space in the SRAM for the descriptors */ ++ titan_ge_eth->tx_desc_area = (titan_ge_tx_desc *) ++ (titan_ge_sram + TITAN_TX_RING_BYTES * port_num); ++ titan_ge_eth->tx_dma = TITAN_SRAM_BASE + TITAN_TX_RING_BYTES * port_num; ++ ++ if (!titan_ge_eth->tx_desc_area) { ++ printk(KERN_ERR ++ "%s: Cannot allocate Tx Ring (size %d bytes) for port %d\n", ++ netdev->name, TITAN_TX_RING_BYTES, port_num); ++ return -ENOMEM; ++ } ++ ++ memset(titan_ge_eth->tx_desc_area, 0, titan_ge_eth->tx_desc_area_size); ++ ++ /* Now initialize the Tx descriptor ring */ ++ titan_ge_init_tx_desc_ring(titan_ge_eth, ++ titan_ge_eth->tx_ring_size, ++ (unsigned long) titan_ge_eth->tx_desc_area, ++ (unsigned long) titan_ge_eth->tx_dma); ++ ++ /* Allocate the Rx ring now */ ++ titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE; ++ titan_ge_eth->rx_ring_skbs = 0; ++ ++ titan_ge_eth->rx_desc_area = ++ (titan_ge_rx_desc *)(titan_ge_sram + 0x1000 + TITAN_RX_RING_BYTES * port_num); ++ ++ titan_ge_eth->rx_dma = TITAN_SRAM_BASE + 0x1000 + TITAN_RX_RING_BYTES * port_num; ++ ++ if (!titan_ge_eth->rx_desc_area) { ++ printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n", ++ netdev->name, TITAN_RX_RING_BYTES); ++ ++ printk(KERN_ERR "%s: Freeing previously allocated TX queues...", ++ netdev->name); ++ ++ dma_free_coherent(device, titan_ge_eth->tx_desc_area_size, ++ (void *) titan_ge_eth->tx_desc_area, ++ titan_ge_eth->tx_dma); ++ ++ return -ENOMEM; ++ } ++ ++ memset(titan_ge_eth->rx_desc_area, 0, titan_ge_eth->rx_desc_area_size); ++ ++ /* Now initialize the Rx ring */ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ if ((titan_ge_init_rx_desc_ring ++ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE, ++ (unsigned long) titan_ge_eth->rx_desc_area, 0, ++ (unsigned long) titan_ge_eth->rx_dma)) == 0) ++#else ++ if ((titan_ge_init_rx_desc_ring ++ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE, ++ (unsigned long) titan_ge_eth->rx_desc_area, 0, ++ (unsigned long) titan_ge_eth->rx_dma)) == 0) ++#endif ++ panic("%s: Error initializing RX Ring\n", netdev->name); ++ ++ /* Fill the Rx ring with the SKBs */ ++ titan_ge_port_start(netdev, titan_ge_eth); ++ ++ /* ++ * Check if Interrupt Coalscing needs to be turned on. The ++ * values specified in the register is multiplied by ++ * (8 x 64 nanoseconds) to determine when an interrupt should ++ * be sent to the CPU. ++ */ ++ ++ if (TITAN_GE_TX_COAL) { ++ titan_ge_eth->tx_int_coal = ++ titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num); ++ } ++ ++ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); ++ if (err == TITAN_GE_MDIO_ERROR) { ++ printk(KERN_ERR ++ "Could not read PHY control register 0x11 \n"); ++ return TITAN_ERROR; ++ } ++ if (!(phy_reg & 0x0400)) { ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ return TITAN_ERROR; ++ } else { ++ netif_carrier_on(netdev); ++ netif_start_queue(netdev); ++ } ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Queue the packet for Tx. Currently no support for zero copy, ++ * checksum offload and Scatter Gather. The chip does support ++ * Scatter Gather only. But, that wont help here since zero copy ++ * requires support for Tx checksumming also. ++ */ ++int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned long flags; ++ struct net_device_stats *stats; ++//printk("titan_ge_start_xmit\n"); ++ ++ stats = &titan_ge_eth->stats; ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ ++ if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <= ++ (skb_shinfo(skb)->nr_frags + 1)) { ++ netif_stop_queue(netdev); ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ printk(KERN_ERR "Tx OOD \n"); ++ return 1; ++ } ++ ++ titan_ge_tx_queue(titan_ge_eth, skb); ++ titan_ge_eth->tx_ring_skbs++; ++ ++ if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) { ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ titan_ge_free_tx_queue(titan_ge_eth); ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ } ++ ++ stats->tx_bytes += skb->len; ++ stats->tx_packets++; ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ ++ netdev->trans_start = jiffies; ++ ++ return 0; ++} ++ ++/* ++ * Actually does the Rx. Rx side checksumming supported. ++ */ ++static int titan_ge_rx(struct net_device *netdev, int port_num, ++ titan_ge_port_info * titan_ge_port, ++ titan_ge_packet * packet) ++{ ++ int rx_curr_desc, rx_used_desc; ++ volatile titan_ge_rx_desc *rx_desc; ++ ++ rx_curr_desc = titan_ge_port->rx_curr_desc_q; ++ rx_used_desc = titan_ge_port->rx_used_desc_q; ++ ++ if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc) ++ return TITAN_ERROR; ++ ++ rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]); ++ ++ if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED) ++ return TITAN_ERROR; ++ ++ packet->skb = titan_ge_port->rx_skb[rx_curr_desc]; ++ packet->len = (rx_desc->cmd_sts & 0x7fff); ++ ++ /* ++ * At this point, we dont know if the checksumming ++ * actually helps relieve CPU. So, keep it for ++ * port 0 only ++ */ ++ packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16); ++ packet->cmd_sts = rx_desc->cmd_sts; ++ ++ titan_ge_port->rx_curr_desc_q = (rx_curr_desc + 1) % TITAN_GE_RX_QUEUE; ++ ++ /* Prefetch the next descriptor */ ++ prefetch((const void *) ++ &titan_ge_port->rx_desc_area[titan_ge_port->rx_curr_desc_q + 1]); ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Free the Tx queue of the used SKBs ++ */ ++static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth) ++{ ++ unsigned long flags; ++ ++ /* Take the lock */ ++ spin_lock_irqsave(&(titan_ge_eth->lock), flags); ++ ++ while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0) ++ if (titan_ge_eth->tx_ring_skbs != 1) ++ titan_ge_eth->tx_ring_skbs--; ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Threshold beyond which we do the cleaning of ++ * Tx queue and new allocation for the Rx ++ * queue ++ */ ++#define TX_THRESHOLD 4 ++#define RX_THRESHOLD 10 ++ ++/* ++ * Receive the packets and send it to the kernel. ++ */ ++static int titan_ge_receive_queue(struct net_device *netdev, unsigned int max) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ titan_ge_packet packet; ++ struct net_device_stats *stats; ++ struct sk_buff *skb; ++ unsigned long received_packets = 0; ++ unsigned int ack; ++ ++ stats = &titan_ge_eth->stats; ++ ++ while ((--max) ++ && (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) { ++ skb = (struct sk_buff *) packet.skb; ++ ++ titan_ge_eth->rx_ring_skbs--; ++ ++ if (--titan_ge_eth->rx_work_limit < 0) ++ break; ++ received_packets++; ++ ++ stats->rx_packets++; ++ stats->rx_bytes += packet.len; ++ ++ if ((packet.cmd_sts & TITAN_GE_RX_PERR) || ++ (packet.cmd_sts & TITAN_GE_RX_OVERFLOW_ERROR) || ++ (packet.cmd_sts & TITAN_GE_RX_TRUNC) || ++ (packet.cmd_sts & TITAN_GE_RX_CRC_ERROR)) { ++ stats->rx_dropped++; ++ dev_kfree_skb_any(skb); ++ ++ continue; ++ } ++ /* ++ * Either support fast path or slow path. Decision ++ * making can really slow down the performance. The ++ * idea is to cut down the number of checks and improve ++ * the fastpath. ++ */ ++ ++ skb_put(skb, packet.len - 2); ++ ++ /* ++ * Increment data pointer by two since thats where ++ * the MAC starts ++ */ ++ skb_reserve(skb, 2); ++ skb->protocol = eth_type_trans(skb, netdev); ++ netif_receive_skb(skb); ++ ++ if (titan_ge_eth->rx_threshold > RX_THRESHOLD) { ++ ack = titan_ge_rx_task(netdev, titan_ge_eth); ++ TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack); ++ titan_ge_eth->rx_threshold = 0; ++ } else ++ titan_ge_eth->rx_threshold++; ++ ++ if (titan_ge_eth->tx_threshold > TX_THRESHOLD) { ++ titan_ge_eth->tx_threshold = 0; ++ titan_ge_free_tx_queue(titan_ge_eth); ++ } ++ else ++ titan_ge_eth->tx_threshold++; ++ ++ } ++ return received_packets; ++} ++ ++ ++/* ++ * Enable the Rx side interrupts ++ */ ++static void titan_ge_enable_int(unsigned int port_num, ++ titan_ge_port_info *titan_ge_eth, ++ struct net_device *netdev) ++{ ++ unsigned long reg_data = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); ++ ++ if (port_num == 0) ++ reg_data |= 0x3; ++ if (port_num == 1) ++ reg_data |= 0x300; ++ if (port_num == 2) ++ reg_data |= 0x30000; ++ ++ /* Re-enable interrupts */ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data); ++} ++ ++/* ++ * Main function to handle the polling for Rx side NAPI. ++ * Receive interrupts have been disabled at this point. ++ * The poll schedules the transmit followed by receive. ++ */ ++static int titan_ge_poll(struct net_device *netdev, int *budget) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ int port_num = titan_ge_eth->port_num; ++ int work_done = 0; ++ unsigned long flags, status; ++ ++ titan_ge_eth->rx_work_limit = *budget; ++ if (titan_ge_eth->rx_work_limit > netdev->quota) ++ titan_ge_eth->rx_work_limit = netdev->quota; ++ ++ do { ++ /* Do the transmit cleaning work here */ ++ titan_ge_free_tx_queue(titan_ge_eth); ++ ++ /* Ack the Rx interrupts */ ++ if (port_num == 0) ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3); ++ if (port_num == 1) ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300); ++ if (port_num == 2) ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000); ++ ++ work_done += titan_ge_receive_queue(netdev, 0); ++ ++ /* Out of quota and there is work to be done */ ++ if (titan_ge_eth->rx_work_limit < 0) ++ goto not_done; ++ ++ /* Receive alloc_skb could lead to OOM */ ++ if (oom_flag == 1) { ++ oom_flag = 0; ++ goto oom; ++ } ++ ++ status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); ++ } while (status & 0x30300); ++ ++ /* If we are here, then no more interrupts to process */ ++ goto done; ++ ++not_done: ++ *budget -= work_done; ++ netdev->quota -= work_done; ++ return 1; ++ ++oom: ++ printk(KERN_ERR "OOM \n"); ++ netif_rx_complete(netdev); ++ return 0; ++ ++done: ++ /* ++ * No more packets on the poll list. Turn the interrupts ++ * back on and we should be able to catch the new ++ * packets in the interrupt handler ++ */ ++ if (!work_done) ++ work_done = 1; ++ ++ *budget -= work_done; ++ netdev->quota -= work_done; ++ ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ ++ /* Remove us from the poll list */ ++ netif_rx_complete(netdev); ++ ++ /* Re-enable interrupts */ ++ titan_ge_enable_int(port_num, titan_ge_eth, netdev); ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ ++ return 0; ++} ++ ++/* ++ * Close the network device ++ */ ++int titan_ge_stop(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ spin_lock_irq(&(titan_ge_eth->lock)); ++ titan_ge_eth_stop(netdev); ++ free_irq(netdev->irq, netdev); ++ spin_unlock_irq(&titan_ge_eth->lock); ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Free the Tx ring ++ */ ++static void titan_ge_free_tx_rings(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int curr; ++ unsigned long reg_data; ++ ++ /* Stop the Tx DMA */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)); ++ reg_data |= 0xc0000000; ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)), reg_data); ++ ++ /* Disable the TMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x00000001); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ for (curr = 0; ++ (titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE); ++ curr++) { ++ if (titan_ge_eth->tx_skb[curr]) { ++ dev_kfree_skb(titan_ge_eth->tx_skb[curr]); ++ titan_ge_eth->tx_ring_skbs--; ++ } ++ } ++ ++ if (titan_ge_eth->tx_ring_skbs != 0) ++ printk ++ ("%s: Error on Tx descriptor free - could not free %d" ++ " descriptors\n", netdev->name, ++ titan_ge_eth->tx_ring_skbs); ++ ++#ifndef TITAN_RX_RING_IN_SRAM ++ dma_free_coherent(&titan_ge_device[port_num]->dev, ++ titan_ge_eth->tx_desc_area_size, ++ (void *) titan_ge_eth->tx_desc_area, ++ titan_ge_eth->tx_dma); ++#endif ++} ++ ++/* ++ * Free the Rx ring ++ */ ++static void titan_ge_free_rx_rings(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int curr; ++ unsigned long reg_data; ++ ++ /* Stop the Rx DMA */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)); ++ reg_data |= 0x000c0000; ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)), reg_data); ++ ++ /* Disable the RMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x00000001); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ for (curr = 0; ++ titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE); ++ curr++) { ++ if (titan_ge_eth->rx_skb[curr]) { ++ dev_kfree_skb(titan_ge_eth->rx_skb[curr]); ++ titan_ge_eth->rx_ring_skbs--; ++ } ++ } ++ ++ if (titan_ge_eth->rx_ring_skbs != 0) ++ printk(KERN_ERR ++ "%s: Error in freeing Rx Ring. %d skb's still" ++ " stuck in RX Ring - ignoring them\n", netdev->name, ++ titan_ge_eth->rx_ring_skbs); ++ ++#ifndef TITAN_RX_RING_IN_SRAM ++ dma_free_coherent(&titan_ge_device[port_num]->dev, ++ titan_ge_eth->rx_desc_area_size, ++ (void *) titan_ge_eth->rx_desc_area, ++ titan_ge_eth->rx_dma); ++#endif ++} ++ ++/* ++ * Actually does the stop of the Ethernet device ++ */ ++static void titan_ge_eth_stop(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ netif_stop_queue(netdev); ++ ++ titan_ge_port_reset(titan_ge_eth->port_num); ++ ++ titan_ge_free_tx_rings(netdev); ++ titan_ge_free_rx_rings(netdev); ++ ++ /* Disable the Tx and Rx Interrupts for all channels */ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, 0x0); ++} ++ ++/* ++ * Update the MAC address. Note that we have to write the ++ * address in three station registers, 16 bits each. And this ++ * has to be done for TMAC and RMAC ++ */ ++static void titan_ge_update_mac_address(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ u8 p_addr[6]; ++ ++ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); ++ memcpy(p_addr, netdev->dev_addr, 6); ++ ++ /* Update the Address Filtering Match tables */ ++ titan_ge_update_afx(titan_ge_eth); ++ ++ printk("Station MAC : %d %d %d %d %d %d \n", ++ p_addr[5], p_addr[4], p_addr[3], ++ p_addr[2], p_addr[1], p_addr[0]); ++ ++ /* Set the MAC address here for TMAC and RMAC */ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++} ++ ++/* ++ * Set the MAC address of the Ethernet device ++ */ ++static int titan_ge_set_mac_address(struct net_device *dev, void *addr) ++{ ++ titan_ge_port_info *tp = netdev_priv(dev); ++ struct sockaddr *sa = addr; ++ ++ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); ++ ++ spin_lock_irq(&tp->lock); ++ titan_ge_update_mac_address(dev); ++ spin_unlock_irq(&tp->lock); ++ ++ return 0; ++} ++ ++/* ++ * Get the Ethernet device stats ++ */ ++static struct net_device_stats *titan_ge_get_stats(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ return &titan_ge_eth->stats; ++} ++ ++/* ++ * Initialize the Rx descriptor ring for the Titan Ge ++ */ ++static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port, ++ int rx_desc_num, ++ int rx_buff_size, ++ unsigned long rx_desc_base_addr, ++ unsigned long rx_buff_base_addr, ++ unsigned long rx_dma) ++{ ++ volatile titan_ge_rx_desc *rx_desc; ++ unsigned long buffer_addr; ++ int index; ++ unsigned long titan_ge_rx_desc_bus = rx_dma; ++ ++ buffer_addr = rx_buff_base_addr; ++ rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr; ++ ++ /* Check alignment */ ++ if (rx_buff_base_addr & 0xF) ++ return 0; ++ ++ /* Check Rx buffer size */ ++ if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER)) ++ return 0; ++ ++ /* 64-bit alignment ++ if ((rx_buff_base_addr + rx_buff_size) & 0x7) ++ return 0; */ ++ ++ /* Initialize the Rx desc ring */ ++ for (index = 0; index < rx_desc_num; index++) { ++ titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc); ++ rx_desc[index].cmd_sts = 0; ++ rx_desc[index].buffer_addr = buffer_addr; ++ titan_eth_port->rx_skb[index] = NULL; ++ buffer_addr += rx_buff_size; ++ } ++ ++ titan_eth_port->rx_curr_desc_q = 0; ++ titan_eth_port->rx_used_desc_q = 0; ++ ++ titan_eth_port->rx_desc_area = (titan_ge_rx_desc *) rx_desc_base_addr; ++ titan_eth_port->rx_desc_area_size = ++ rx_desc_num * sizeof(titan_ge_rx_desc); ++ ++ titan_eth_port->rx_dma = rx_dma; ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Initialize the Tx descriptor ring. Descriptors in the SRAM ++ */ ++static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port, ++ int tx_desc_num, ++ unsigned long tx_desc_base_addr, ++ unsigned long tx_dma) ++{ ++ titan_ge_tx_desc *tx_desc; ++ int index; ++ unsigned long titan_ge_tx_desc_bus = tx_dma; ++ ++ if (tx_desc_base_addr & 0xF) ++ return 0; ++ ++ tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr; ++ ++ for (index = 0; index < tx_desc_num; index++) { ++ titan_ge_port->tx_dma_array[index] = ++ (dma_addr_t) titan_ge_tx_desc_bus; ++ titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc); ++ tx_desc[index].cmd_sts = 0x0000; ++ tx_desc[index].buffer_len = 0; ++ tx_desc[index].buffer_addr = 0x00000000; ++ titan_ge_port->tx_skb[index] = NULL; ++ } ++ ++ titan_ge_port->tx_curr_desc_q = 0; ++ titan_ge_port->tx_used_desc_q = 0; ++ ++ titan_ge_port->tx_desc_area = (titan_ge_tx_desc *) tx_desc_base_addr; ++ titan_ge_port->tx_desc_area_size = ++ tx_desc_num * sizeof(titan_ge_tx_desc); ++ ++ titan_ge_port->tx_dma = tx_dma; ++ return TITAN_OK; ++} ++ ++/* ++ * Initialize the device as an Ethernet device ++ */ ++static int __init titan_ge_probe(struct device *device) ++{ ++ titan_ge_port_info *titan_ge_eth; ++ struct net_device *netdev; ++ int port = to_platform_device(device)->id; ++ int err; ++ ++ netdev = alloc_etherdev(sizeof(titan_ge_port_info)); ++ if (!netdev) { ++ err = -ENODEV; ++ goto out; ++ } ++ ++ netdev->open = titan_ge_open; ++ netdev->stop = titan_ge_stop; ++ netdev->hard_start_xmit = titan_ge_start_xmit; ++ netdev->get_stats = titan_ge_get_stats; ++ netdev->set_multicast_list = titan_ge_set_multi; ++ netdev->set_mac_address = titan_ge_set_mac_address; ++ ++ /* Tx timeout */ ++ netdev->tx_timeout = titan_ge_tx_timeout; ++ netdev->watchdog_timeo = 2 * HZ; ++ ++ /* Set these to very high values */ ++ netdev->poll = titan_ge_poll; ++ netdev->weight = 64; ++ ++ netdev->tx_queue_len = TITAN_GE_TX_QUEUE; ++ netif_carrier_off(netdev); ++ netdev->base_addr = 0; ++ ++ netdev->change_mtu = titan_ge_change_mtu; ++ ++ titan_ge_eth = netdev_priv(netdev); ++ /* Allocation of memory for the driver structures */ ++ ++ titan_ge_eth->port_num = port; ++ ++ /* Configure the Tx timeout handler */ ++ INIT_WORK(&titan_ge_eth->tx_timeout_task, ++ (void (*)(void *)) titan_ge_tx_timeout_task, netdev); ++ ++ spin_lock_init(&titan_ge_eth->lock); ++ ++ /* set MAC addresses */ ++ memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6); ++ netdev->dev_addr[5] += port; ++ ++ err = register_netdev(netdev); ++ ++ if (err) ++ goto out_free_netdev; ++ ++ printk(KERN_NOTICE ++ "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", ++ netdev->name, port, netdev->dev_addr[0], ++ netdev->dev_addr[1], netdev->dev_addr[2], ++ netdev->dev_addr[3], netdev->dev_addr[4], ++ netdev->dev_addr[5]); ++ ++ printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n"); ++ ++ return 0; ++ ++out_free_netdev: ++ kfree(netdev); ++ ++out: ++ return err; ++} ++ ++static void __devexit titan_device_remove(struct device *device) ++{ ++} ++ ++/* ++ * Reset the Ethernet port ++ */ ++static void titan_ge_port_reset(unsigned int port_num) ++{ ++ unsigned int reg_data; ++ ++ /* Stop the Tx port activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x0001); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ /* Stop the Rx port activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x0001); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ return; ++} ++ ++/* ++ * Return the Tx desc after use by the XDMA ++ */ ++static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port) ++{ ++ int tx_desc_used; ++ struct sk_buff *skb; ++ ++ tx_desc_used = titan_ge_eth->tx_used_desc_q; ++ ++ /* return right away */ ++ if (tx_desc_used == titan_ge_eth->tx_curr_desc_q) ++ return TITAN_ERROR; ++ ++ /* Now the critical stuff */ ++ skb = titan_ge_eth->tx_skb[tx_desc_used]; ++ ++ dev_kfree_skb_any(skb); ++ ++ titan_ge_eth->tx_skb[tx_desc_used] = NULL; ++ titan_ge_eth->tx_used_desc_q = ++ (tx_desc_used + 1) % TITAN_GE_TX_QUEUE; ++ ++ return 0; ++} ++ ++/* ++ * Coalescing for the Tx path ++ */ ++static unsigned long titan_ge_tx_coal(unsigned long delay, int port) ++{ ++ unsigned long rx_delay; ++ ++ rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING); ++ delay = (delay << 16) | rx_delay; ++ ++ TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay); ++ TITAN_GE_WRITE(0x5038, delay); ++ ++ return delay; ++} ++ ++static struct device_driver titan_soc_driver = { ++ .name = titan_string, ++ .bus = &platform_bus_type, ++ .probe = titan_ge_probe, ++ .remove = __devexit_p(titan_device_remove), ++}; ++ ++static void titan_platform_release (struct device *device) ++{ ++ struct platform_device *pldev; ++ ++ /* free device */ ++ pldev = to_platform_device (device); ++ kfree (pldev); ++} ++ ++/* ++ * Register the Titan GE with the kernel ++ */ ++static int __init titan_ge_init_module(void) ++{ ++ struct platform_device *pldev; ++ unsigned int version, device; ++ int i; ++ ++ printk(KERN_NOTICE ++ "PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n"); ++ ++ titan_ge_base = (unsigned long) ioremap(TITAN_GE_BASE, TITAN_GE_SIZE); ++ if (!titan_ge_base) { ++ printk("Mapping Titan GE failed\n"); ++ goto out; ++ } ++ ++ device = TITAN_GE_READ(TITAN_GE_DEVICE_ID); ++ version = (device & 0x000f0000) >> 16; ++ device &= 0x0000ffff; ++ ++ printk(KERN_NOTICE "Device Id : %x, Version : %x \n", device, version); ++ ++#ifdef TITAN_RX_RING_IN_SRAM ++ titan_ge_sram = (unsigned long) ioremap(TITAN_SRAM_BASE, ++ TITAN_SRAM_SIZE); ++ if (!titan_ge_sram) { ++ printk("Mapping Titan SRAM failed\n"); ++ goto out_unmap_ge; ++ } ++#endif ++ ++ if (driver_register(&titan_soc_driver)) { ++ printk(KERN_ERR "Driver registration failed\n"); ++ goto out_unmap_sram; ++ } ++ ++ for (i = 0; i < 3; i++) { ++ titan_ge_device[i] = NULL; ++ ++ if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) ++ continue; ++ ++ memset (pldev, 0, sizeof (*pldev)); ++ pldev->name = titan_string; ++ pldev->id = i; ++ pldev->dev.release = titan_platform_release; ++ titan_ge_device[i] = pldev; ++ ++ if (platform_device_register (pldev)) { ++ kfree (pldev); ++ titan_ge_device[i] = NULL; ++ continue; ++ } ++ ++ if (!pldev->dev.driver) { ++ /* ++ * The driver was not bound to this device, there was ++ * no hardware at this address. Unregister it, as the ++ * release fuction will take care of freeing the ++ * allocated structure ++ */ ++ titan_ge_device[i] = NULL; ++ platform_device_unregister (pldev); ++ } ++ } ++ ++ return 0; ++ ++out_unmap_sram: ++ iounmap((void *)titan_ge_sram); ++ ++out_unmap_ge: ++ iounmap((void *)titan_ge_base); ++ ++out: ++ return -ENOMEM; ++} ++ ++/* ++ * Unregister the Titan GE from the kernel ++ */ ++static void __exit titan_ge_cleanup_module(void) ++{ ++ int i; ++ ++ driver_unregister(&titan_soc_driver); ++ ++ for (i = 0; i < 3; i++) { ++ if (titan_ge_device[i]) { ++ platform_device_unregister (titan_ge_device[i]); ++ titan_ge_device[i] = NULL; ++ } ++ } ++ ++ iounmap((void *)titan_ge_sram); ++ iounmap((void *)titan_ge_base); ++} ++ ++MODULE_AUTHOR("Manish Lachwani <lachwani@pmc-sierra.com>"); ++MODULE_DESCRIPTION("Titan GE Ethernet driver"); ++MODULE_LICENSE("GPL"); ++ ++module_init(titan_ge_init_module); ++module_exit(titan_ge_cleanup_module); +diff -Nurd linux-2.6.24/drivers/net/titan_ge.h mer-smartq-kernel/drivers/net/titan_ge.h +--- linux-2.6.24/drivers/net/titan_ge.h 1970-01-01 01:00:00.000000000 +0100 ++++ mer-smartq-kernel/drivers/net/titan_ge.h 2009-11-17 12:13:31.000000000 +0100 +@@ -0,0 +1,415 @@ ++#ifndef _TITAN_GE_H_ ++#define _TITAN_GE_H_ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/spinlock.h> ++#include <asm/byteorder.h> ++ ++/* ++ * These functions should be later moved to a more generic location since there ++ * will be others accessing it also ++ */ ++ ++/* ++ * This is the way it works: LKB5 Base is at 0x0128. TITAN_BASE is defined in ++ * include/asm/titan_dep.h. TITAN_GE_BASE is the value in the TITAN_GE_LKB5 ++ * register. ++ */ ++ ++#define TITAN_GE_BASE 0xfe000000UL ++#define TITAN_GE_SIZE 0x10000UL ++ ++extern unsigned long titan_ge_base; ++ ++#define TITAN_GE_WRITE(offset, data) \ ++ *(volatile u32 *)(titan_ge_base + (offset)) = (data) ++ ++#define TITAN_GE_READ(offset) *(volatile u32 *)(titan_ge_base + (offset)) ++ ++#ifndef msec_delay ++#define msec_delay(x) do { if(in_interrupt()) { \ ++ /* Don't mdelay in interrupt context! */ \ ++ BUG(); \ ++ } else { \ ++ set_current_state(TASK_UNINTERRUPTIBLE); \ ++ schedule_timeout((x * HZ)/1000); \ ++ } } while(0) ++#endif ++ ++#define TITAN_GE_PORT_0 ++ ++#define TITAN_SRAM_BASE ((OCD_READ(RM9000x2_OCD_LKB13) & ~1) << 4) ++#define TITAN_SRAM_SIZE 0x2000UL ++ ++/* ++ * We may need these constants ++ */ ++#define TITAN_BIT0 0x00000001 ++#define TITAN_BIT1 0x00000002 ++#define TITAN_BIT2 0x00000004 ++#define TITAN_BIT3 0x00000008 ++#define TITAN_BIT4 0x00000010 ++#define TITAN_BIT5 0x00000020 ++#define TITAN_BIT6 0x00000040 ++#define TITAN_BIT7 0x00000080 ++#define TITAN_BIT8 0x00000100 ++#define TITAN_BIT9 0x00000200 ++#define TITAN_BIT10 0x00000400 ++#define TITAN_BIT11 0x00000800 ++#define TITAN_BIT12 0x00001000 ++#define TITAN_BIT13 0x00002000 ++#define TITAN_BIT14 0x00004000 ++#define TITAN_BIT15 0x00008000 ++#define TITAN_BIT16 0x00010000 ++#define TITAN_BIT17 0x00020000 ++#define TITAN_BIT18 0x00040000 ++#define TITAN_BIT19 0x00080000 ++#define TITAN_BIT20 0x00100000 ++#define TITAN_BIT21 0x00200000 ++#define TITAN_BIT22 0x00400000 ++#define TITAN_BIT23 0x00800000 ++#define TITAN_BIT24 0x01000000 ++#define TITAN_BIT25 0x02000000 ++#define TITAN_BIT26 0x04000000 ++#define TITAN_BIT27 0x08000000 ++#define TITAN_BIT28 0x10000000 ++#define TITAN_BIT29 0x20000000 ++#define TITAN_BIT30 0x40000000 ++#define TITAN_BIT31 0x80000000 ++ ++/* Flow Control */ ++#define TITAN_GE_FC_NONE 0x0 ++#define TITAN_GE_FC_FULL 0x1 ++#define TITAN_GE_FC_TX_PAUSE 0x2 ++#define TITAN_GE_FC_RX_PAUSE 0x3 ++ ++/* Duplex Settings */ ++#define TITAN_GE_FULL_DUPLEX 0x1 ++#define TITAN_GE_HALF_DUPLEX 0x2 ++ ++/* Speed settings */ ++#define TITAN_GE_SPEED_1000 0x1 ++#define TITAN_GE_SPEED_100 0x2 ++#define TITAN_GE_SPEED_10 0x3 ++ ++/* Debugging info only */ ++#undef TITAN_DEBUG ++ ++/* Keep the rings in the Titan's SSRAM */ ++#define TITAN_RX_RING_IN_SRAM ++ ++#ifdef CONFIG_64BIT ++#define TITAN_GE_IE_MASK 0xfffffffffb001b64 ++#define TITAN_GE_IE_STATUS 0xfffffffffb001b60 ++#else ++#define TITAN_GE_IE_MASK 0xfb001b64 ++#define TITAN_GE_IE_STATUS 0xfb001b60 ++#endif ++ ++/* Support for Jumbo Frames */ ++#undef TITAN_GE_JUMBO_FRAMES ++ ++/* Rx buffer size */ ++#ifdef TITAN_GE_JUMBO_FRAMES ++#define TITAN_GE_JUMBO_BUFSIZE 9080 ++#else ++#define TITAN_GE_STD_BUFSIZE 1580 ++#endif ++ ++/* ++ * Tx and Rx Interrupt Coalescing parameter. These values are ++ * for 1 Ghz processor. Rx coalescing can be taken care of ++ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing ++ * is not adaptive. Hence, these values need to be adjusted ++ * based on load, CPU speed etc. ++ */ ++#define TITAN_GE_RX_COAL 150 ++#define TITAN_GE_TX_COAL 300 ++ ++#if defined(__BIG_ENDIAN) ++ ++/* Define the Rx descriptor */ ++typedef struct eth_rx_desc { ++ u32 reserved; /* Unused */ ++ u32 buffer_addr; /* CPU buffer address */ ++ u32 cmd_sts; /* Command and Status */ ++ u32 buffer; /* XDMA buffer address */ ++} titan_ge_rx_desc; ++ ++/* Define the Tx descriptor */ ++typedef struct eth_tx_desc { ++ u16 cmd_sts; /* Command, Status and Buffer count */ ++ u16 buffer_len; /* Length of the buffer */ ++ u32 buffer_addr; /* Physical address of the buffer */ ++} titan_ge_tx_desc; ++ ++#elif defined(__LITTLE_ENDIAN) ++ ++/* Define the Rx descriptor */ ++typedef struct eth_rx_desc { ++ u32 buffer_addr; /* CPU buffer address */ ++ u32 reserved; /* Unused */ ++ u32 buffer; /* XDMA buffer address */ ++ u32 cmd_sts; /* Command and Status */ ++} titan_ge_rx_desc; ++ ++/* Define the Tx descriptor */ ++typedef struct eth_tx_desc { ++ u32 buffer_addr; /* Physical address of the buffer */ ++ u16 buffer_len; /* Length of the buffer */ ++ u16 cmd_sts; /* Command, Status and Buffer count */ ++} titan_ge_tx_desc; ++#endif ++ ++/* Default Tx Queue Size */ ++#define TITAN_GE_TX_QUEUE 128 ++#define TITAN_TX_RING_BYTES (TITAN_GE_TX_QUEUE * sizeof(struct eth_tx_desc)) ++ ++/* Default Rx Queue Size */ ++#define TITAN_GE_RX_QUEUE 64 ++#define TITAN_RX_RING_BYTES (TITAN_GE_RX_QUEUE * sizeof(struct eth_rx_desc)) ++ ++/* Packet Structure */ ++typedef struct _pkt_info { ++ unsigned int len; ++ unsigned int cmd_sts; ++ unsigned int buffer; ++ struct sk_buff *skb; ++ unsigned int checksum; ++} titan_ge_packet; ++ ++ ++#define PHYS_CNT 3 ++ ++/* Titan Port specific data structure */ ++typedef struct _eth_port_ctrl { ++ unsigned int port_num; ++ u8 port_mac_addr[6]; ++ ++ /* Rx descriptor pointers */ ++ int rx_curr_desc_q, rx_used_desc_q; ++ ++ /* Tx descriptor pointers */ ++ int tx_curr_desc_q, tx_used_desc_q; ++ ++ /* Rx descriptor area */ ++ volatile titan_ge_rx_desc *rx_desc_area; ++ unsigned int rx_desc_area_size; ++ struct sk_buff* rx_skb[TITAN_GE_RX_QUEUE]; ++ ++ /* Tx Descriptor area */ ++ volatile titan_ge_tx_desc *tx_desc_area; ++ unsigned int tx_desc_area_size; ++ struct sk_buff* tx_skb[TITAN_GE_TX_QUEUE]; ++ ++ /* Timeout task */ ++ struct work_struct tx_timeout_task; ++ ++ /* DMA structures and handles */ ++ dma_addr_t tx_dma; ++ dma_addr_t rx_dma; ++ dma_addr_t tx_dma_array[TITAN_GE_TX_QUEUE]; ++ ++ /* Device lock */ ++ spinlock_t lock; ++ ++ unsigned int tx_ring_skbs; ++ unsigned int rx_ring_size; ++ unsigned int tx_ring_size; ++ unsigned int rx_ring_skbs; ++ ++ struct net_device_stats stats; ++ ++ /* Tx and Rx coalescing */ ++ unsigned long rx_int_coal; ++ unsigned long tx_int_coal; ++ ++ /* Threshold for replenishing the Rx and Tx rings */ ++ unsigned int tx_threshold; ++ unsigned int rx_threshold; ++ ++ /* NAPI work limit */ ++ unsigned int rx_work_limit; ++} titan_ge_port_info; ++ ++/* Titan specific constants */ ++#define TITAN_ETH_PORT_IRQ 3 ++ ++/* Max Rx buffer */ ++#define TITAN_GE_MAX_RX_BUFFER 65536 ++ ++/* Tx and Rx Error */ ++#define TITAN_GE_ERROR ++ ++/* Rx Descriptor Command and Status */ ++ ++#define TITAN_GE_RX_CRC_ERROR TITAN_BIT27 /* crc error */ ++#define TITAN_GE_RX_OVERFLOW_ERROR TITAN_BIT15 /* overflow */ ++#define TITAN_GE_RX_BUFFER_OWNED TITAN_BIT21 /* buffer ownership */ ++#define TITAN_GE_RX_STP TITAN_BIT31 /* start of packet */ ++#define TITAN_GE_RX_BAM TITAN_BIT30 /* broadcast address match */ ++#define TITAN_GE_RX_PAM TITAN_BIT28 /* physical address match */ ++#define TITAN_GE_RX_LAFM TITAN_BIT29 /* logical address filter match */ ++#define TITAN_GE_RX_VLAN TITAN_BIT26 /* virtual lans */ ++#define TITAN_GE_RX_PERR TITAN_BIT19 /* packet error */ ++#define TITAN_GE_RX_TRUNC TITAN_BIT20 /* packet size greater than 32 buffers */ ++ ++/* Tx Descriptor Command */ ++#define TITAN_GE_TX_BUFFER_OWNED TITAN_BIT5 /* buffer ownership */ ++#define TITAN_GE_TX_ENABLE_INTERRUPT TITAN_BIT15 /* Interrupt Enable */ ++ ++/* Return Status */ ++#define TITAN_OK 0x1 /* Good Status */ ++#define TITAN_ERROR 0x2 /* Error Status */ ++ ++/* MIB specific register offset */ ++#define TITAN_GE_MSTATX_STATS_BASE_LOW 0x0800 /* MSTATX COUNTL[15:0] */ ++#define TITAN_GE_MSTATX_STATS_BASE_MID 0x0804 /* MSTATX COUNTM[15:0] */ ++#define TITAN_GE_MSTATX_STATS_BASE_HI 0x0808 /* MSTATX COUNTH[7:0] */ ++#define TITAN_GE_MSTATX_CONTROL 0x0828 /* MSTATX Control */ ++#define TITAN_GE_MSTATX_VARIABLE_SELECT 0x082C /* MSTATX Variable Select */ ++ ++/* MIB counter offsets, add to the TITAN_GE_MSTATX_STATS_BASE_XXX */ ++#define TITAN_GE_MSTATX_RXFRAMESOK 0x0040 ++#define TITAN_GE_MSTATX_RXOCTETSOK 0x0050 ++#define TITAN_GE_MSTATX_RXFRAMES 0x0060 ++#define TITAN_GE_MSTATX_RXOCTETS 0x0070 ++#define TITAN_GE_MSTATX_RXUNICASTFRAMESOK 0x0080 ++#define TITAN_GE_MSTATX_RXBROADCASTFRAMESOK 0x0090 ++#define TITAN_GE_MSTATX_RXMULTICASTFRAMESOK 0x00A0 ++#define TITAN_GE_MSTATX_RXTAGGEDFRAMESOK 0x00B0 ++#define TITAN_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK 0x00C0 ++#define TITAN_GE_MSTATX_RXMACCONTROLFRAMESOK 0x00D0 ++#define TITAN_GE_MSTATX_RXFCSERROR 0x00E0 ++#define TITAN_GE_MSTATX_RXALIGNMENTERROR 0x00F0 ++#define TITAN_GE_MSTATX_RXSYMBOLERROR 0x0100 ++#define TITAN_GE_MSTATX_RXLAYER1ERROR 0x0110 ++#define TITAN_GE_MSTATX_RXINRANGELENGTHERROR 0x0120 ++#define TITAN_GE_MSTATX_RXLONGLENGTHERROR 0x0130 ++#define TITAN_GE_MSTATX_RXLONGLENGTHCRCERROR 0x0140 ++#define TITAN_GE_MSTATX_RXSHORTLENGTHERROR 0x0150 ++#define TITAN_GE_MSTATX_RXSHORTLLENGTHCRCERROR 0x0160 ++#define TITAN_GE_MSTATX_RXFRAMES64OCTETS 0x0170 ++#define TITAN_GE_MSTATX_RXFRAMES65TO127OCTETS 0x0180 ++#define TITAN_GE_MSTATX_RXFRAMES128TO255OCTETS 0x0190 ++#define TITAN_GE_MSTATX_RXFRAMES256TO511OCTETS 0x01A0 ++#define TITAN_GE_MSTATX_RXFRAMES512TO1023OCTETS 0x01B0 ++#define TITAN_GE_MSTATX_RXFRAMES1024TO1518OCTETS 0x01C0 ++#define TITAN_GE_MSTATX_RXFRAMES1519TOMAXSIZE 0x01D0 ++#define TITAN_GE_MSTATX_RXSTATIONADDRESSFILTERED 0x01E0 ++#define TITAN_GE_MSTATX_RXVARIABLE 0x01F0 ++#define TITAN_GE_MSTATX_GENERICADDRESSFILTERED 0x0200 ++#define TITAN_GE_MSTATX_UNICASTFILTERED 0x0210 ++#define TITAN_GE_MSTATX_MULTICASTFILTERED 0x0220 ++#define TITAN_GE_MSTATX_BROADCASTFILTERED 0x0230 ++#define TITAN_GE_MSTATX_HASHFILTERED 0x0240 ++#define TITAN_GE_MSTATX_TXFRAMESOK 0x0250 ++#define TITAN_GE_MSTATX_TXOCTETSOK 0x0260 ++#define TITAN_GE_MSTATX_TXOCTETS 0x0270 ++#define TITAN_GE_MSTATX_TXTAGGEDFRAMESOK 0x0280 ++#define TITAN_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK 0x0290 ++#define TITAN_GE_MSTATX_TXFCSERROR 0x02A0 ++#define TITAN_GE_MSTATX_TXSHORTLENGTHERROR 0x02B0 ++#define TITAN_GE_MSTATX_TXLONGLENGTHERROR 0x02C0 ++#define TITAN_GE_MSTATX_TXSYSTEMERROR 0x02D0 ++#define TITAN_GE_MSTATX_TXMACERROR 0x02E0 ++#define TITAN_GE_MSTATX_TXCARRIERSENSEERROR 0x02F0 ++#define TITAN_GE_MSTATX_TXSQETESTERROR 0x0300 ++#define TITAN_GE_MSTATX_TXUNICASTFRAMESOK 0x0310 ++#define TITAN_GE_MSTATX_TXBROADCASTFRAMESOK 0x0320 ++#define TITAN_GE_MSTATX_TXMULTICASTFRAMESOK 0x0330 ++#define TITAN_GE_MSTATX_TXUNICASTFRAMESATTEMPTED 0x0340 ++#define TITAN_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED 0x0350 ++#define TITAN_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED 0x0360 ++#define TITAN_GE_MSTATX_TXFRAMES64OCTETS 0x0370 ++#define TITAN_GE_MSTATX_TXFRAMES65TO127OCTETS 0x0380 ++#define TITAN_GE_MSTATX_TXFRAMES128TO255OCTETS 0x0390 ++#define TITAN_GE_MSTATX_TXFRAMES256TO511OCTETS 0x03A0 ++#define TITAN_GE_MSTATX_TXFRAMES512TO1023OCTETS 0x03B0 ++#define TITAN_GE_MSTATX_TXFRAMES1024TO1518OCTETS 0x03C0 ++#define TITAN_GE_MSTATX_TXFRAMES1519TOMAXSIZE 0x03D0 ++#define TITAN_GE_MSTATX_TXVARIABLE 0x03E0 ++#define TITAN_GE_MSTATX_RXSYSTEMERROR 0x03F0 ++#define TITAN_GE_MSTATX_SINGLECOLLISION 0x0400 ++#define TITAN_GE_MSTATX_MULTIPLECOLLISION 0x0410 ++#define TITAN_GE_MSTATX_DEFERREDXMISSIONS 0x0420 ++#define TITAN_GE_MSTATX_LATECOLLISIONS 0x0430 ++#define TITAN_GE_MSTATX_ABORTEDDUETOXSCOLLS 0x0440 ++ ++/* Interrupt specific defines */ ++#define TITAN_GE_DEVICE_ID 0x0000 /* Device ID */ ++#define TITAN_GE_RESET 0x0004 /* Reset reg */ ++#define TITAN_GE_TSB_CTRL_0 0x000C /* TSB Control reg 0 */ ++#define TITAN_GE_TSB_CTRL_1 0x0010 /* TSB Control reg 1 */ ++#define TITAN_GE_INTR_GRP0_STATUS 0x0040 /* General Interrupt Group 0 Status */ ++#define TITAN_GE_INTR_XDMA_CORE_A 0x0048 /* XDMA Channel Interrupt Status, Core A*/ ++#define TITAN_GE_INTR_XDMA_CORE_B 0x004C /* XDMA Channel Interrupt Status, Core B*/ ++#define TITAN_GE_INTR_XDMA_IE 0x0058 /* XDMA Channel Interrupt Enable */ ++#define TITAN_GE_SDQPF_ECC_INTR 0x480C /* SDQPF ECC Interrupt Status */ ++#define TITAN_GE_SDQPF_RXFIFO_CTL 0x4828 /* SDQPF RxFifo Control and Interrupt Enb*/ ++#define TITAN_GE_SDQPF_RXFIFO_INTR 0x482C /* SDQPF RxFifo Interrupt Status */ ++#define TITAN_GE_SDQPF_TXFIFO_CTL 0x4928 /* SDQPF TxFifo Control and Interrupt Enb*/ ++#define TITAN_GE_SDQPF_TXFIFO_INTR 0x492C /* SDQPF TxFifo Interrupt Status */ ++#define TITAN_GE_SDQPF_RXFIFO_0 0x4840 /* SDQPF RxFIFO Enable */ ++#define TITAN_GE_SDQPF_TXFIFO_0 0x4940 /* SDQPF TxFIFO Enable */ ++#define TITAN_GE_XDMA_CONFIG 0x5000 /* XDMA Global Configuration */ ++#define TITAN_GE_XDMA_INTR_SUMMARY 0x5010 /* XDMA Interrupt Summary */ ++#define TITAN_GE_XDMA_BUFADDRPRE 0x5018 /* XDMA Buffer Address Prefix */ ++#define TITAN_GE_XDMA_DESCADDRPRE 0x501C /* XDMA Descriptor Address Prefix */ ++#define TITAN_GE_XDMA_PORTWEIGHT 0x502C /* XDMA Port Weight Configuration */ ++ ++/* Rx MAC defines */ ++#define TITAN_GE_RMAC_CONFIG_1 0x1200 /* RMAC Configuration 1 */ ++#define TITAN_GE_RMAC_CONFIG_2 0x1204 /* RMAC Configuration 2 */ ++#define TITAN_GE_RMAC_MAX_FRAME_LEN 0x1208 /* RMAC Max Frame Length */ ++#define TITAN_GE_RMAC_STATION_HI 0x120C /* Rx Station Address High */ ++#define TITAN_GE_RMAC_STATION_MID 0x1210 /* Rx Station Address Middle */ ++#define TITAN_GE_RMAC_STATION_LOW 0x1214 /* Rx Station Address Low */ ++#define TITAN_GE_RMAC_LINK_CONFIG 0x1218 /* RMAC Link Configuration */ ++ ++/* Tx MAC defines */ ++#define TITAN_GE_TMAC_CONFIG_1 0x1240 /* TMAC Configuration 1 */ ++#define TITAN_GE_TMAC_CONFIG_2 0x1244 /* TMAC Configuration 2 */ ++#define TITAN_GE_TMAC_IPG 0x1248 /* TMAC Inter-Packet Gap */ ++#define TITAN_GE_TMAC_STATION_HI 0x124C /* Tx Station Address High */ ++#define TITAN_GE_TMAC_STATION_MID 0x1250 /* Tx Station Address Middle */ ++#define TITAN_GE_TMAC_STATION_LOW 0x1254 /* Tx Station Address Low */ ++#define TITAN_GE_TMAC_MAX_FRAME_LEN 0x1258 /* TMAC Max Frame Length */ ++#define TITAN_GE_TMAC_MIN_FRAME_LEN 0x125C /* TMAC Min Frame Length */ ++#define TITAN_GE_TMAC_PAUSE_FRAME_TIME 0x1260 /* TMAC Pause Frame Time */ ++#define TITAN_GE_TMAC_PAUSE_FRAME_INTERVAL 0x1264 /* TMAC Pause Frame Interval */ ++ ++/* GMII register */ ++#define TITAN_GE_GMII_INTERRUPT_STATUS 0x1348 /* GMII Interrupt Status */ ++#define TITAN_GE_GMII_CONFIG_GENERAL 0x134C /* GMII Configuration General */ ++#define TITAN_GE_GMII_CONFIG_MODE 0x1350 /* GMII Configuration Mode */ ++ ++/* Tx and Rx XDMA defines */ ++#define TITAN_GE_INT_COALESCING 0x5030 /* Interrupt Coalescing */ ++#define TITAN_GE_CHANNEL0_CONFIG 0x5040 /* Channel 0 XDMA config */ ++#define TITAN_GE_CHANNEL0_INTERRUPT 0x504c /* Channel 0 Interrupt Status */ ++#define TITAN_GE_GDI_INTERRUPT_ENABLE 0x5050 /* IE for the GDI Errors */ ++#define TITAN_GE_CHANNEL0_PACKET 0x5060 /* Channel 0 Packet count */ ++#define TITAN_GE_CHANNEL0_BYTE 0x5064 /* Channel 0 Byte count */ ++#define TITAN_GE_CHANNEL0_TX_DESC 0x5054 /* Channel 0 Tx first desc */ ++#define TITAN_GE_CHANNEL0_RX_DESC 0x5058 /* Channel 0 Rx first desc */ ++ ++/* AFX (Address Filter Exact) register offsets for Slice 0 */ ++#define TITAN_GE_AFX_EXACT_MATCH_LOW 0x1100 /* AFX Exact Match Address Low*/ ++#define TITAN_GE_AFX_EXACT_MATCH_MID 0x1104 /* AFX Exact Match Address Mid*/ ++#define TITAN_GE_AFX_EXACT_MATCH_HIGH 0x1108 /* AFX Exact Match Address Hi */ ++#define TITAN_GE_AFX_EXACT_MATCH_VID 0x110C /* AFX Exact Match VID */ ++#define TITAN_GE_AFX_MULTICAST_HASH_LOW 0x1110 /* AFX Multicast HASH Low */ ++#define TITAN_GE_AFX_MULTICAST_HASH_MIDLOW 0x1114 /* AFX Multicast HASH MidLow */ ++#define TITAN_GE_AFX_MULTICAST_HASH_MIDHI 0x1118 /* AFX Multicast HASH MidHi */ ++#define TITAN_GE_AFX_MULTICAST_HASH_HI 0x111C /* AFX Multicast HASH Hi */ ++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 0x1120 /* AFX Address Filter Ctrl 0 */ ++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 0x1124 /* AFX Address Filter Ctrl 1 */ ++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 0x1128 /* AFX Address Filter Ctrl 2 */ ++ ++/* Traffic Groomer block */ ++#define TITAN_GE_TRTG_CONFIG 0x1000 /* TRTG Config */ ++ ++#endif /* _TITAN_GE_H_ */ ++ +diff -Nurd linux-2.6.24/drivers/net/titan_mdio.c mer-smartq-kernel/drivers/net/titan_mdio.c +--- linux-2.6.24/drivers/net/titan_mdio.c 1970-01-01 01:00:00.000000000 +0100 ++++ mer-smartq-kernel/drivers/net/titan_mdio.c 2009-11-17 12:13:31.000000000 +0100 +@@ -0,0 +1,217 @@ ++/* ++ * drivers/net/titan_mdio.c - Driver for Titan ethernet ports ++ * ++ * Copyright (C) 2003 PMC-Sierra Inc. ++ * Author : Manish Lachwani (lachwani@pmc-sierra.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY ++ * on the Titan. No support for the TBI as yet. ++ * ++ */ ++ ++#include "titan_mdio.h" ++ ++#define MDIO_DEBUG ++ ++/* ++ * Local constants ++ */ ++#define MAX_CLKA 1023 ++#define MAX_PHY_DEV 31 ++#define MAX_PHY_REG 31 ++#define WRITEADDRS_OPCODE 0x0 ++#define READ_OPCODE 0x2 ++#define WRITE_OPCODE 0x1 ++#define MAX_MDIO_POLL 100 ++ ++/* ++ * Titan MDIO and SCMB registers ++ */ ++#define TITAN_GE_SCMB_CONTROL 0x01c0 /* SCMB Control */ ++#define TITAN_GE_SCMB_CLKA 0x01c4 /* SCMB Clock A */ ++#define TITAN_GE_MDIO_COMMAND 0x01d0 /* MDIO Command */ ++#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS 0x01d4 /* MDIO Device and Port addrs */ ++#define TITAN_GE_MDIO_DATA 0x01d8 /* MDIO Data */ ++#define TITAN_GE_MDIO_INTERRUPTS 0x01dC /* MDIO Interrupts */ ++ ++/* ++ * Function to poll the MDIO ++ */ ++static int titan_ge_mdio_poll(void) ++{ ++ int i, val; ++ ++ for (i = 0; i < MAX_MDIO_POLL; i++) { ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ ++ if (!(val & 0x8000)) ++ return TITAN_GE_MDIO_GOOD; ++ } ++ ++ return TITAN_GE_MDIO_ERROR; ++} ++ ++ ++/* ++ * Initialize and configure the MDIO ++ */ ++int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio) ++{ ++ unsigned long val; ++ ++ /* Reset the SCMB and program into MDIO mode*/ ++ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000); ++ ++ /* CLK A */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA); ++ val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val); ++ ++ /* Preamble Suppresion */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ /* MDIO mode */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ ++/* ++ * Set the PHY address in indirect mode ++ */ ++int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr) ++{ ++ volatile unsigned long val; ++ ++ /* Setup the PHY device */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); ++ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ /* Write the new address */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ ++/* ++ * Read the MDIO register. This is what the individual parametes mean: ++ * ++ * dev_addr : PHY ID ++ * reg_addr : register offset ++ * ++ * See the spec for the Titan MAC. We operate in the Direct Mode. ++ */ ++ ++#define MAX_RETRIES 2 ++ ++int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata) ++{ ++ volatile unsigned long val; ++ int retries = 0; ++ ++ /* Setup the PHY device */ ++ ++again: ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); ++ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); ++ val |= 0x4000; ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ udelay(30); ++ ++ /* Issue the read command */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ udelay(30); ++ ++ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) ++ return TITAN_GE_MDIO_ERROR; ++ ++ *pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA); ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); ++ ++ udelay(30); ++ ++ if (val & 0x2) { ++ if (retries == MAX_RETRIES) ++ return TITAN_GE_MDIO_ERROR; ++ else { ++ retries++; ++ goto again; ++ } ++ } ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ ++/* ++ * Write to the MDIO register ++ * ++ * dev_addr : PHY ID ++ * reg_addr : register that needs to be written to ++ * ++ */ ++int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data) ++{ ++ volatile unsigned long val; ++ ++ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) ++ return TITAN_GE_MDIO_ERROR; ++ ++ /* Setup the PHY device */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); ++ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); ++ val |= 0x4000; ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ udelay(30); ++ ++ /* Setup the data to write */ ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data); ++ ++ udelay(30); ++ ++ /* Issue the write command */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ udelay(30); ++ ++ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) ++ return TITAN_GE_MDIO_ERROR; ++ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); ++ if (val & 0x2) ++ return TITAN_GE_MDIO_ERROR; ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ +diff -Nurd linux-2.6.24/drivers/net/titan_mdio.h mer-smartq-kernel/drivers/net/titan_mdio.h +--- linux-2.6.24/drivers/net/titan_mdio.h 1970-01-01 01:00:00.000000000 +0100 ++++ mer-smartq-kernel/drivers/net/titan_mdio.h 2009-11-17 12:13:31.000000000 +0100 +@@ -0,0 +1,56 @@ ++/* ++ * MDIO used to interact with the PHY when using GMII/MII ++ */ ++#ifndef _TITAN_MDIO_H ++#define _TITAN_MDIO_H ++ ++#include <linux/netdevice.h> ++#include <linux/workqueue.h> ++#include <linux/delay.h> ++#include "titan_ge.h" ++ ++ ++#define TITAN_GE_MDIO_ERROR (-9000) ++#define TITAN_GE_MDIO_GOOD 0 ++ ++#define TITAN_GE_MDIO_BASE titan_ge_base ++ ++#define TITAN_GE_MDIO_READ(offset) \ ++ *(volatile u32 *)(titan_ge_base + (offset)) ++ ++#define TITAN_GE_MDIO_WRITE(offset, data) \ ++ *(volatile u32 *)(titan_ge_base + (offset)) = (data) ++ ++ ++/* GMII specific registers */ ++#define TITAN_GE_MARVEL_PHY_ID 0x00 ++#define TITAN_PHY_AUTONEG_ADV 0x04 ++#define TITAN_PHY_LP_ABILITY 0x05 ++#define TITAN_GE_MDIO_MII_CTRL 0x09 ++#define TITAN_GE_MDIO_MII_EXTENDED 0x0f ++#define TITAN_GE_MDIO_PHY_CTRL 0x10 ++#define TITAN_GE_MDIO_PHY_STATUS 0x11 ++#define TITAN_GE_MDIO_PHY_IE 0x12 ++#define TITAN_GE_MDIO_PHY_IS 0x13 ++#define TITAN_GE_MDIO_PHY_LED 0x18 ++#define TITAN_GE_MDIO_PHY_LED_OVER 0x19 ++#define PHY_ANEG_TIME_WAIT 45 /* 45 seconds wait time */ ++ ++/* ++ * MDIO Config Structure ++ */ ++typedef struct { ++ unsigned int clka; ++ int mdio_spre; ++ int mdio_mode; ++} titan_ge_mdio_config; ++ ++/* ++ * Function Prototypes ++ */ ++int titan_ge_mdio_setup(titan_ge_mdio_config *); ++int titan_ge_mdio_inaddrs(int, int); ++int titan_ge_mdio_read(int, int, unsigned int *); ++int titan_ge_mdio_write(int, int, unsigned int); ++ ++#endif /* _TITAN_MDIO_H */ +diff -Nurd linux-2.6.24/drivers/scsi/NCR53C9x.h mer-smartq-kernel/drivers/scsi/NCR53C9x.h +--- linux-2.6.24/drivers/scsi/NCR53C9x.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/drivers/scsi/NCR53C9x.h 2009-11-17 12:13:32.000000000 +0100 +@@ -144,12 +144,7 @@ + + #ifndef MULTIPLE_PAD_SIZES + +-#ifdef CONFIG_CPU_HAS_WB +-#include <asm/wbflush.h> +-#define esp_write(__reg, __val) do{(__reg) = (__val); wbflush();} while(0) +-#else +-#define esp_write(__reg, __val) ((__reg) = (__val)) +-#endif ++#define esp_write(__reg, __val) do{(__reg) = (__val); iob();} while(0) + #define esp_read(__reg) (__reg) + + struct ESP_regs { +diff -Nurd linux-2.6.24/include/asm-mips/asmmacro.h mer-smartq-kernel/include/asm-mips/asmmacro.h +--- linux-2.6.24/include/asm-mips/asmmacro.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/asmmacro.h 2009-11-17 12:13:38.000000000 +0100 +@@ -35,6 +35,16 @@ + mtc0 \reg, CP0_TCSTATUS + _ehb + .endm ++#elif defined(CONFIG_CPU_MIPSR2) ++ .macro local_irq_enable reg=t0 ++ ei ++ irq_enable_hazard ++ .endm ++ ++ .macro local_irq_disable reg=t0 ++ di ++ irq_disable_hazard ++ .endm + #else + .macro local_irq_enable reg=t0 + mfc0 \reg, CP0_STATUS +diff -Nurd linux-2.6.24/include/asm-mips/atomic.h mer-smartq-kernel/include/asm-mips/atomic.h +--- linux-2.6.24/include/asm-mips/atomic.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/atomic.h 2009-11-17 12:13:38.000000000 +0100 +@@ -283,10 +283,10 @@ + " beqz %0, 2f \n" + " subu %0, %1, %3 \n" + " .set reorder \n" +- "1: \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" ++ "1: \n" + " .set mips0 \n" + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) +@@ -664,10 +664,10 @@ + " beqz %0, 2f \n" + " dsubu %0, %1, %3 \n" + " .set reorder \n" +- "1: \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" ++ "1: \n" + " .set mips0 \n" + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) +diff -Nurd linux-2.6.24/include/asm-mips/byteorder.h mer-smartq-kernel/include/asm-mips/byteorder.h +--- linux-2.6.24/include/asm-mips/byteorder.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/byteorder.h 2009-11-17 12:13:38.000000000 +0100 +@@ -43,9 +43,8 @@ + static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x) + { + __asm__( +- " dsbh %0, %1 \n" +- " dshd %0, %0 \n" +- " drotr %0, %0, 32 \n" ++ " dsbh %0, %1\n" ++ " dshd %0, %0" + : "=r" (x) + : "r" (x)); + +diff -Nurd linux-2.6.24/include/asm-mips/cacheflush.h mer-smartq-kernel/include/asm-mips/cacheflush.h +--- linux-2.6.24/include/asm-mips/cacheflush.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/cacheflush.h 2009-11-17 12:13:38.000000000 +0100 +@@ -63,8 +63,22 @@ + } + + extern void (*flush_icache_range)(unsigned long start, unsigned long end); +-#define flush_cache_vmap(start, end) flush_cache_all() +-#define flush_cache_vunmap(start, end) flush_cache_all() ++ ++extern void (*__flush_cache_vmap)(void); ++ ++static inline void flush_cache_vmap(unsigned long start, unsigned long end) ++{ ++ if (cpu_has_dc_aliases) ++ __flush_cache_vmap(); ++} ++ ++extern void (*__flush_cache_vunmap)(void); ++ ++static inline void flush_cache_vunmap(unsigned long start, unsigned long end) ++{ ++ if (cpu_has_dc_aliases) ++ __flush_cache_vunmap(); ++} + + extern void copy_to_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, void *dst, const void *src, +@@ -93,7 +107,7 @@ + clear_bit(PG_dcache_dirty, &(page)->flags) + + /* Run kernel code uncached, useful for cache probing functions. */ +-unsigned long __init run_uncached(void *func); ++unsigned long run_uncached(void *func); + + extern void *kmap_coherent(struct page *page, unsigned long addr); + extern void kunmap_coherent(void); +diff -Nurd linux-2.6.24/include/asm-mips/cevt-r4k.h mer-smartq-kernel/include/asm-mips/cevt-r4k.h +--- linux-2.6.24/include/asm-mips/cevt-r4k.h 1970-01-01 01:00:00.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/cevt-r4k.h 2009-11-17 12:13:38.000000000 +0100 +@@ -0,0 +1,46 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2008 Kevin D. Kissell ++ */ ++ ++/* ++ * Definitions used for common event timer implementation ++ * for MIPS 4K-type processors and their MIPS MT variants. ++ * Avoids unsightly extern declarations in C files. ++ */ ++#ifndef __ASM_CEVT_R4K_H ++#define __ASM_CEVT_R4K_H ++ ++DECLARE_PER_CPU(struct clock_event_device, mips_clockevent_device); ++ ++void mips_event_handler(struct clock_event_device *dev); ++int c0_compare_int_usable(void); ++void mips_set_clock_mode(enum clock_event_mode, struct clock_event_device *); ++irqreturn_t c0_compare_interrupt(int, void *); ++ ++extern struct irqaction c0_compare_irqaction; ++extern int cp0_timer_irq_installed; ++ ++/* ++ * Possibly handle a performance counter interrupt. ++ * Return true if the timer interrupt should not be checked ++ */ ++ ++static inline int handle_perf_irq(int r2) ++{ ++ /* ++ * The performance counter overflow interrupt may be shared with the ++ * timer interrupt (cp0_perfcount_irq < 0). If it is and a ++ * performance counter has overflowed (perf_irq() == IRQ_HANDLED) ++ * and we can't reliably determine if a counter interrupt has also ++ * happened (!r2) then don't check for a timer interrupt. ++ */ ++ return (cp0_perfcount_irq < 0) && ++ perf_irq() == IRQ_HANDLED && ++ !r2; ++} ++ ++#endif /* __ASM_CEVT_R4K_H */ +diff -Nurd linux-2.6.24/include/asm-mips/elf.h mer-smartq-kernel/include/asm-mips/elf.h +--- linux-2.6.24/include/asm-mips/elf.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/elf.h 2009-11-17 12:13:38.000000000 +0100 +@@ -232,7 +232,7 @@ + */ + #ifdef __MIPSEB__ + #define ELF_DATA ELFDATA2MSB +-#elif __MIPSEL__ ++#elif defined(__MIPSEL__) + #define ELF_DATA ELFDATA2LSB + #endif + #define ELF_ARCH EM_MIPS +diff -Nurd linux-2.6.24/include/asm-mips/gdb-stub.h mer-smartq-kernel/include/asm-mips/gdb-stub.h +--- linux-2.6.24/include/asm-mips/gdb-stub.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/gdb-stub.h 2009-11-17 12:13:38.000000000 +0100 +@@ -4,148 +4,33 @@ + * for more details. + * + * Copyright (C) 1995 Andreas Busse +- * Copyright (C) 2003 Ralf Baechle ++ * Copyright (C) 2003, 2008 Ralf Baechle (ralf@linux-mips.org) ++ * Copyright (C) 2008 Wind River Systems, Inc. ++ * written by Ralf Baechle + */ + #ifndef _ASM_GDB_STUB_H + #define _ASM_GDB_STUB_H + +- + /* +- * important register numbers ++ * GDB interface constants. + */ +- +-#define REG_EPC 37 +-#define REG_FP 72 +-#define REG_SP 29 ++#define REG_EPC 37 ++#define REG_FP 72 ++#define REG_SP 29 + + /* + * Stack layout for the GDB exception handler + * Derived from the stack layout described in asm-mips/stackframe.h +- * +- * The first PTRSIZE*6 bytes are argument save space for C subroutines. +- */ +-#define NUMREGS 90 +- +-#define GDB_FR_REG0 (PTRSIZE*6) /* 0 */ +-#define GDB_FR_REG1 ((GDB_FR_REG0) + LONGSIZE) /* 1 */ +-#define GDB_FR_REG2 ((GDB_FR_REG1) + LONGSIZE) /* 2 */ +-#define GDB_FR_REG3 ((GDB_FR_REG2) + LONGSIZE) /* 3 */ +-#define GDB_FR_REG4 ((GDB_FR_REG3) + LONGSIZE) /* 4 */ +-#define GDB_FR_REG5 ((GDB_FR_REG4) + LONGSIZE) /* 5 */ +-#define GDB_FR_REG6 ((GDB_FR_REG5) + LONGSIZE) /* 6 */ +-#define GDB_FR_REG7 ((GDB_FR_REG6) + LONGSIZE) /* 7 */ +-#define GDB_FR_REG8 ((GDB_FR_REG7) + LONGSIZE) /* 8 */ +-#define GDB_FR_REG9 ((GDB_FR_REG8) + LONGSIZE) /* 9 */ +-#define GDB_FR_REG10 ((GDB_FR_REG9) + LONGSIZE) /* 10 */ +-#define GDB_FR_REG11 ((GDB_FR_REG10) + LONGSIZE) /* 11 */ +-#define GDB_FR_REG12 ((GDB_FR_REG11) + LONGSIZE) /* 12 */ +-#define GDB_FR_REG13 ((GDB_FR_REG12) + LONGSIZE) /* 13 */ +-#define GDB_FR_REG14 ((GDB_FR_REG13) + LONGSIZE) /* 14 */ +-#define GDB_FR_REG15 ((GDB_FR_REG14) + LONGSIZE) /* 15 */ +-#define GDB_FR_REG16 ((GDB_FR_REG15) + LONGSIZE) /* 16 */ +-#define GDB_FR_REG17 ((GDB_FR_REG16) + LONGSIZE) /* 17 */ +-#define GDB_FR_REG18 ((GDB_FR_REG17) + LONGSIZE) /* 18 */ +-#define GDB_FR_REG19 ((GDB_FR_REG18) + LONGSIZE) /* 19 */ +-#define GDB_FR_REG20 ((GDB_FR_REG19) + LONGSIZE) /* 20 */ +-#define GDB_FR_REG21 ((GDB_FR_REG20) + LONGSIZE) /* 21 */ +-#define GDB_FR_REG22 ((GDB_FR_REG21) + LONGSIZE) /* 22 */ +-#define GDB_FR_REG23 ((GDB_FR_REG22) + LONGSIZE) /* 23 */ +-#define GDB_FR_REG24 ((GDB_FR_REG23) + LONGSIZE) /* 24 */ +-#define GDB_FR_REG25 ((GDB_FR_REG24) + LONGSIZE) /* 25 */ +-#define GDB_FR_REG26 ((GDB_FR_REG25) + LONGSIZE) /* 26 */ +-#define GDB_FR_REG27 ((GDB_FR_REG26) + LONGSIZE) /* 27 */ +-#define GDB_FR_REG28 ((GDB_FR_REG27) + LONGSIZE) /* 28 */ +-#define GDB_FR_REG29 ((GDB_FR_REG28) + LONGSIZE) /* 29 */ +-#define GDB_FR_REG30 ((GDB_FR_REG29) + LONGSIZE) /* 30 */ +-#define GDB_FR_REG31 ((GDB_FR_REG30) + LONGSIZE) /* 31 */ +- +-/* +- * Saved special registers +- */ +-#define GDB_FR_STATUS ((GDB_FR_REG31) + LONGSIZE) /* 32 */ +-#define GDB_FR_LO ((GDB_FR_STATUS) + LONGSIZE) /* 33 */ +-#define GDB_FR_HI ((GDB_FR_LO) + LONGSIZE) /* 34 */ +-#define GDB_FR_BADVADDR ((GDB_FR_HI) + LONGSIZE) /* 35 */ +-#define GDB_FR_CAUSE ((GDB_FR_BADVADDR) + LONGSIZE) /* 36 */ +-#define GDB_FR_EPC ((GDB_FR_CAUSE) + LONGSIZE) /* 37 */ +- +-/* +- * Saved floating point registers +- */ +-#define GDB_FR_FPR0 ((GDB_FR_EPC) + LONGSIZE) /* 38 */ +-#define GDB_FR_FPR1 ((GDB_FR_FPR0) + LONGSIZE) /* 39 */ +-#define GDB_FR_FPR2 ((GDB_FR_FPR1) + LONGSIZE) /* 40 */ +-#define GDB_FR_FPR3 ((GDB_FR_FPR2) + LONGSIZE) /* 41 */ +-#define GDB_FR_FPR4 ((GDB_FR_FPR3) + LONGSIZE) /* 42 */ +-#define GDB_FR_FPR5 ((GDB_FR_FPR4) + LONGSIZE) /* 43 */ +-#define GDB_FR_FPR6 ((GDB_FR_FPR5) + LONGSIZE) /* 44 */ +-#define GDB_FR_FPR7 ((GDB_FR_FPR6) + LONGSIZE) /* 45 */ +-#define GDB_FR_FPR8 ((GDB_FR_FPR7) + LONGSIZE) /* 46 */ +-#define GDB_FR_FPR9 ((GDB_FR_FPR8) + LONGSIZE) /* 47 */ +-#define GDB_FR_FPR10 ((GDB_FR_FPR9) + LONGSIZE) /* 48 */ +-#define GDB_FR_FPR11 ((GDB_FR_FPR10) + LONGSIZE) /* 49 */ +-#define GDB_FR_FPR12 ((GDB_FR_FPR11) + LONGSIZE) /* 50 */ +-#define GDB_FR_FPR13 ((GDB_FR_FPR12) + LONGSIZE) /* 51 */ +-#define GDB_FR_FPR14 ((GDB_FR_FPR13) + LONGSIZE) /* 52 */ +-#define GDB_FR_FPR15 ((GDB_FR_FPR14) + LONGSIZE) /* 53 */ +-#define GDB_FR_FPR16 ((GDB_FR_FPR15) + LONGSIZE) /* 54 */ +-#define GDB_FR_FPR17 ((GDB_FR_FPR16) + LONGSIZE) /* 55 */ +-#define GDB_FR_FPR18 ((GDB_FR_FPR17) + LONGSIZE) /* 56 */ +-#define GDB_FR_FPR19 ((GDB_FR_FPR18) + LONGSIZE) /* 57 */ +-#define GDB_FR_FPR20 ((GDB_FR_FPR19) + LONGSIZE) /* 58 */ +-#define GDB_FR_FPR21 ((GDB_FR_FPR20) + LONGSIZE) /* 59 */ +-#define GDB_FR_FPR22 ((GDB_FR_FPR21) + LONGSIZE) /* 60 */ +-#define GDB_FR_FPR23 ((GDB_FR_FPR22) + LONGSIZE) /* 61 */ +-#define GDB_FR_FPR24 ((GDB_FR_FPR23) + LONGSIZE) /* 62 */ +-#define GDB_FR_FPR25 ((GDB_FR_FPR24) + LONGSIZE) /* 63 */ +-#define GDB_FR_FPR26 ((GDB_FR_FPR25) + LONGSIZE) /* 64 */ +-#define GDB_FR_FPR27 ((GDB_FR_FPR26) + LONGSIZE) /* 65 */ +-#define GDB_FR_FPR28 ((GDB_FR_FPR27) + LONGSIZE) /* 66 */ +-#define GDB_FR_FPR29 ((GDB_FR_FPR28) + LONGSIZE) /* 67 */ +-#define GDB_FR_FPR30 ((GDB_FR_FPR29) + LONGSIZE) /* 68 */ +-#define GDB_FR_FPR31 ((GDB_FR_FPR30) + LONGSIZE) /* 69 */ +- +-#define GDB_FR_FSR ((GDB_FR_FPR31) + LONGSIZE) /* 70 */ +-#define GDB_FR_FIR ((GDB_FR_FSR) + LONGSIZE) /* 71 */ +-#define GDB_FR_FRP ((GDB_FR_FIR) + LONGSIZE) /* 72 */ +- +-#define GDB_FR_DUMMY ((GDB_FR_FRP) + LONGSIZE) /* 73, unused ??? */ +- +-/* +- * Again, CP0 registers +- */ +-#define GDB_FR_CP0_INDEX ((GDB_FR_DUMMY) + LONGSIZE) /* 74 */ +-#define GDB_FR_CP0_RANDOM ((GDB_FR_CP0_INDEX) + LONGSIZE) /* 75 */ +-#define GDB_FR_CP0_ENTRYLO0 ((GDB_FR_CP0_RANDOM) + LONGSIZE)/* 76 */ +-#define GDB_FR_CP0_ENTRYLO1 ((GDB_FR_CP0_ENTRYLO0) + LONGSIZE)/* 77 */ +-#define GDB_FR_CP0_CONTEXT ((GDB_FR_CP0_ENTRYLO1) + LONGSIZE)/* 78 */ +-#define GDB_FR_CP0_PAGEMASK ((GDB_FR_CP0_CONTEXT) + LONGSIZE)/* 79 */ +-#define GDB_FR_CP0_WIRED ((GDB_FR_CP0_PAGEMASK) + LONGSIZE)/* 80 */ +-#define GDB_FR_CP0_REG7 ((GDB_FR_CP0_WIRED) + LONGSIZE) /* 81 */ +-#define GDB_FR_CP0_REG8 ((GDB_FR_CP0_REG7) + LONGSIZE) /* 82 */ +-#define GDB_FR_CP0_REG9 ((GDB_FR_CP0_REG8) + LONGSIZE) /* 83 */ +-#define GDB_FR_CP0_ENTRYHI ((GDB_FR_CP0_REG9) + LONGSIZE) /* 84 */ +-#define GDB_FR_CP0_REG11 ((GDB_FR_CP0_ENTRYHI) + LONGSIZE)/* 85 */ +-#define GDB_FR_CP0_REG12 ((GDB_FR_CP0_REG11) + LONGSIZE) /* 86 */ +-#define GDB_FR_CP0_REG13 ((GDB_FR_CP0_REG12) + LONGSIZE) /* 87 */ +-#define GDB_FR_CP0_REG14 ((GDB_FR_CP0_REG13) + LONGSIZE) /* 88 */ +-#define GDB_FR_CP0_PRID ((GDB_FR_CP0_REG14) + LONGSIZE) /* 89 */ +- +-#define GDB_FR_SIZE ((((GDB_FR_CP0_PRID) + LONGSIZE) + (PTRSIZE-1)) & ~(PTRSIZE-1)) +- +-#ifndef __ASSEMBLY__ +- +-/* +- * This is the same as above, but for the high-level +- * part of the GDB stub. + */ + + struct gdb_regs { ++#ifdef CONFIG_32BIT + /* + * Pad bytes for argument save space on the stack + * 24/48 Bytes for 32/64 bit code + */ + unsigned long pad0[6]; ++#endif + + /* + * saved main processor registers +@@ -159,8 +44,11 @@ + * Saved special registers + */ + long cp0_status; +- long lo; + long hi; ++ long lo; ++#ifdef CONFIG_CPU_HAS_SMARTMIPS ++ long acx ++#endif + long cp0_badvaddr; + long cp0_cause; + long cp0_epc; +@@ -183,7 +71,7 @@ + long dummy; /* unused */ + + /* +- * saved cp0 registers ++ * Saved cp0 registers + */ + long cp0_index; + long cp0_random; +@@ -203,13 +91,8 @@ + long cp0_prid; + }; + +-/* +- * Prototypes +- */ +- + extern int kgdb_enabled; +-void set_debug_traps(void); +-void set_async_breakpoint(unsigned long *epc); ++extern void set_debug_traps(void); ++extern void set_async_breakpoint(unsigned long *epc); + +-#endif /* !__ASSEMBLY__ */ + #endif /* _ASM_GDB_STUB_H */ +diff -Nurd linux-2.6.24/include/asm-mips/irqflags.h mer-smartq-kernel/include/asm-mips/irqflags.h +--- linux-2.6.24/include/asm-mips/irqflags.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/irqflags.h 2009-11-17 12:13:38.000000000 +0100 +@@ -38,8 +38,17 @@ + " .set pop \n" + " .endm"); + ++extern void smtc_ipi_replay(void); ++ + static inline void raw_local_irq_enable(void) + { ++#ifdef CONFIG_MIPS_MT_SMTC ++ /* ++ * SMTC kernel needs to do a software replay of queued ++ * IPIs, at the cost of call overhead on each local_irq_enable() ++ */ ++ smtc_ipi_replay(); ++#endif + __asm__ __volatile__( + "raw_local_irq_enable" + : /* no outputs */ +@@ -47,6 +56,7 @@ + : "memory"); + } + ++ + /* + * For cli() we have to insert nops to make sure that the new value + * has actually arrived in the status register before the end of this +@@ -185,15 +195,14 @@ + " .set pop \n" + " .endm \n"); + +-extern void smtc_ipi_replay(void); + + static inline void raw_local_irq_restore(unsigned long flags) + { + unsigned long __tmp1; + +-#ifdef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY ++#ifdef CONFIG_MIPS_MT_SMTC + /* +- * CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY does prompt replay of deferred ++ * SMTC kernel needs to do a software replay of queued + * IPIs, at the cost of branch and call overhead on each + * local_irq_restore() + */ +@@ -208,6 +217,17 @@ + : "memory"); + } + ++static inline void __raw_local_irq_restore(unsigned long flags) ++{ ++ unsigned long __tmp1; ++ ++ __asm__ __volatile__( ++ "raw_local_irq_restore\t%0" ++ : "=r" (__tmp1) ++ : "0" (flags) ++ : "memory"); ++} ++ + static inline int raw_irqs_disabled_flags(unsigned long flags) + { + #ifdef CONFIG_MIPS_MT_SMTC +diff -Nurd linux-2.6.24/include/asm-mips/lasat/serial.h mer-smartq-kernel/include/asm-mips/lasat/serial.h +--- linux-2.6.24/include/asm-mips/lasat/serial.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/lasat/serial.h 2009-11-17 12:13:38.000000000 +0100 +@@ -4,10 +4,10 @@ + #define LASAT_BASE_BAUD_100 (7372800 / 16) + #define LASAT_UART_REGS_BASE_100 0x1c8b0000 + #define LASAT_UART_REGS_SHIFT_100 2 +-#define LASATINT_UART_100 8 ++#define LASATINT_UART_100 16 + + /* * LASAT 200 boards serial configuration */ + #define LASAT_BASE_BAUD_200 (100000000 / 16 / 12) + #define LASAT_UART_REGS_BASE_200 (Vrc5074_PHYS_BASE + 0x0300) + #define LASAT_UART_REGS_SHIFT_200 3 +-#define LASATINT_UART_200 13 ++#define LASATINT_UART_200 21 +diff -Nurd linux-2.6.24/include/asm-mips/mach-au1x00/au1000.h mer-smartq-kernel/include/asm-mips/mach-au1x00/au1000.h +--- linux-2.6.24/include/asm-mips/mach-au1x00/au1000.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/mach-au1x00/au1000.h 2009-11-17 12:13:38.000000000 +0100 +@@ -1786,6 +1786,7 @@ + char *cpu_name; + unsigned char cpu_od; /* Set Config[OD] */ + unsigned char cpu_bclk; /* Enable BCLK switching */ ++ unsigned char cpu_pll_wo; /* sys_cpupll reg. write-only */ + }; + + extern struct cpu_spec cpu_specs[]; +diff -Nurd linux-2.6.24/include/asm-mips/mach-ip27/cpu-feature-overrides.h mer-smartq-kernel/include/asm-mips/mach-ip27/cpu-feature-overrides.h +--- linux-2.6.24/include/asm-mips/mach-ip27/cpu-feature-overrides.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/mach-ip27/cpu-feature-overrides.h 2009-11-17 12:13:38.000000000 +0100 +@@ -34,7 +34,11 @@ + #define cpu_has_64bits 1 + + #define cpu_has_4kex 1 ++#define cpu_has_3k_cache 0 ++#define cpu_has_6k_cache 0 + #define cpu_has_4k_cache 1 ++#define cpu_has_8k_cache 0 ++#define cpu_has_tx39_cache 0 + + #define cpu_has_inclusive_pcaches 1 + +diff -Nurd linux-2.6.24/include/asm-mips/mach-ip27/dma-coherence.h mer-smartq-kernel/include/asm-mips/mach-ip27/dma-coherence.h +--- linux-2.6.24/include/asm-mips/mach-ip27/dma-coherence.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/mach-ip27/dma-coherence.h 2009-11-17 12:13:38.000000000 +0100 +@@ -35,7 +35,7 @@ + + static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr) + { +- return dma_addr & (0xffUL << 56); ++ return dma_addr & ~(0xffUL << 56); + } + + static inline void plat_unmap_dma_mem(dma_addr_t dma_addr) +diff -Nurd linux-2.6.24/include/asm-mips/mach-jmr3927/ioremap.h mer-smartq-kernel/include/asm-mips/mach-jmr3927/ioremap.h +--- linux-2.6.24/include/asm-mips/mach-jmr3927/ioremap.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/mach-jmr3927/ioremap.h 2009-11-17 12:13:38.000000000 +0100 +@@ -25,7 +25,7 @@ + { + #define TXX9_DIRECTMAP_BASE 0xff000000ul + if (offset >= TXX9_DIRECTMAP_BASE && +- offset < TXX9_DIRECTMAP_BASE + 0xf0000) ++ offset < TXX9_DIRECTMAP_BASE + 0xff0000) + return (void __iomem *)offset; + return NULL; + } +diff -Nurd linux-2.6.24/include/asm-mips/mach-lasat/irq.h mer-smartq-kernel/include/asm-mips/mach-lasat/irq.h +--- linux-2.6.24/include/asm-mips/mach-lasat/irq.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/mach-lasat/irq.h 2009-11-17 12:13:38.000000000 +0100 +@@ -1,7 +1,7 @@ + #ifndef _ASM_MACH_LASAT_IRQ_H + #define _ASM_MACH_LASAT_IRQ_H + +-#define LASAT_CASCADE_IRQ (MIPS_CPU_IRQ_BASE + 0) ++#define LASAT_CASCADE_IRQ (MIPS_CPU_IRQ_BASE + 2) + + #define LASAT_IRQ_BASE 8 + #define LASAT_IRQ_END 23 +diff -Nurd linux-2.6.24/include/asm-mips/mach-pb1x00/pb1200.h mer-smartq-kernel/include/asm-mips/mach-pb1x00/pb1200.h +--- linux-2.6.24/include/asm-mips/mach-pb1x00/pb1200.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/mach-pb1x00/pb1200.h 2009-11-17 12:13:38.000000000 +0100 +@@ -244,7 +244,7 @@ + PB1200_SD1_INSERT_INT, + PB1200_SD1_EJECT_INT, + +- PB1200_INT_END (PB1200_INT_BEGIN + 15) ++ PB1200_INT_END = PB1200_INT_BEGIN + 15 + }; + + /* For drivers/pcmcia/au1000_db1x00.c */ +diff -Nurd linux-2.6.24/include/asm-mips/mach-qemu/cpu-feature-overrides.h mer-smartq-kernel/include/asm-mips/mach-qemu/cpu-feature-overrides.h +--- linux-2.6.24/include/asm-mips/mach-qemu/cpu-feature-overrides.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/mach-qemu/cpu-feature-overrides.h 2009-11-17 12:13:38.000000000 +0100 +@@ -12,7 +12,7 @@ + * QEMU only comes with a hazard-free MIPS32 processor, so things are easy. + */ + #define cpu_has_mips16 0 +-#define cpu_has_divec 0 ++#define cpu_has_divec 1 + #define cpu_has_cache_cdex_p 0 + #define cpu_has_prefetch 0 + #define cpu_has_mcheck 0 +diff -Nurd linux-2.6.24/include/asm-mips/mipsregs.h mer-smartq-kernel/include/asm-mips/mipsregs.h +--- linux-2.6.24/include/asm-mips/mipsregs.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/mipsregs.h 2009-11-17 12:13:38.000000000 +0100 +@@ -1459,7 +1459,7 @@ + { \ + unsigned int res; \ + unsigned int omt; \ +- unsigned int flags; \ ++ unsigned long flags; \ + \ + local_irq_save(flags); \ + omt = __dmt(); \ +@@ -1477,7 +1477,7 @@ + { \ + unsigned int res; \ + unsigned int omt; \ +- unsigned int flags; \ ++ unsigned long flags; \ + \ + local_irq_save(flags); \ + omt = __dmt(); \ +@@ -1495,7 +1495,7 @@ + { \ + unsigned int res; \ + unsigned int omt; \ +- unsigned int flags; \ ++ unsigned long flags; \ + \ + local_irq_save(flags); \ + \ +diff -Nurd linux-2.6.24/include/asm-mips/pgtable-32.h mer-smartq-kernel/include/asm-mips/pgtable-32.h +--- linux-2.6.24/include/asm-mips/pgtable-32.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/pgtable-32.h 2009-11-17 12:13:38.000000000 +0100 +@@ -57,7 +57,7 @@ + #define PMD_ORDER 1 + #define PTE_ORDER 0 + +-#define PTRS_PER_PGD ((PAGE_SIZE << PGD_ORDER) / sizeof(pgd_t)) ++#define PTRS_PER_PGD (USER_PTRS_PER_PGD * 2) + #define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t)) + + #define USER_PTRS_PER_PGD (0x80000000UL/PGDIR_SIZE) +diff -Nurd linux-2.6.24/include/asm-mips/pgtable.h mer-smartq-kernel/include/asm-mips/pgtable.h +--- linux-2.6.24/include/asm-mips/pgtable.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/pgtable.h 2009-11-17 12:13:38.000000000 +0100 +@@ -232,9 +232,10 @@ + static inline pte_t pte_mkyoung(pte_t pte) + { + pte.pte_low |= _PAGE_ACCESSED; +- if (pte.pte_low & _PAGE_READ) ++ if (pte.pte_low & _PAGE_READ) { + pte.pte_low |= _PAGE_SILENT_READ; + pte.pte_high |= _PAGE_SILENT_READ; ++ } + return pte; + } + #else +diff -Nurd linux-2.6.24/include/asm-mips/rtlx.h mer-smartq-kernel/include/asm-mips/rtlx.h +--- linux-2.6.24/include/asm-mips/rtlx.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/rtlx.h 2009-11-17 12:13:38.000000000 +0100 +@@ -3,7 +3,7 @@ + * + */ + +-#ifndef __ASM_RTLX_H ++#ifndef __ASM_RTLX_H_ + #define __ASM_RTLX_H_ + + #include <irq.h> +@@ -29,13 +29,13 @@ + extern unsigned int rtlx_write_poll(int index); + + enum rtlx_state { +- RTLX_STATE_UNUSED, ++ RTLX_STATE_UNUSED = 0, + RTLX_STATE_INITIALISED, + RTLX_STATE_REMOTE_READY, + RTLX_STATE_OPENED + }; + +-#define RTLX_BUFFER_SIZE 1024 ++#define RTLX_BUFFER_SIZE 2048 + + /* each channel supports read and write. + linux (vpe0) reads lx_buffer and writes rt_buffer +diff -Nurd linux-2.6.24/include/asm-mips/smtc.h mer-smartq-kernel/include/asm-mips/smtc.h +--- linux-2.6.24/include/asm-mips/smtc.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/smtc.h 2009-11-17 12:13:38.000000000 +0100 +@@ -6,6 +6,7 @@ + */ + + #include <asm/mips_mt.h> ++#include <asm/smtc_ipi.h> + + /* + * System-wide SMTC status information +@@ -38,13 +39,14 @@ + struct task_struct; + + void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu); +- ++void self_ipi(struct smtc_ipi *); + void smtc_flush_tlb_asid(unsigned long asid); +-extern int mipsmt_build_cpu_map(int startslot); +-extern void mipsmt_prepare_cpus(void); ++extern int smtc_build_cpu_map(int startslot); ++extern void smtc_prepare_cpus(int cpus); + extern void smtc_smp_finish(void); + extern void smtc_boot_secondary(int cpu, struct task_struct *t); + ++ + /* + * Sharing the TLB between multiple VPEs means that the + * "random" index selection function is not allowed to +diff -Nurd linux-2.6.24/include/asm-mips/sn/mapped_kernel.h mer-smartq-kernel/include/asm-mips/sn/mapped_kernel.h +--- linux-2.6.24/include/asm-mips/sn/mapped_kernel.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/sn/mapped_kernel.h 2009-11-17 12:13:38.000000000 +0100 +@@ -5,6 +5,8 @@ + #ifndef __ASM_SN_MAPPED_KERNEL_H + #define __ASM_SN_MAPPED_KERNEL_H + ++#include <linux/mmzone.h> ++ + /* + * Note on how mapped kernels work: the text and data section is + * compiled at cksseg segment (LOADADDR = 0xc001c000), and the +@@ -29,10 +31,8 @@ + #define MAPPED_ADDR_RO_TO_PHYS(x) (x - REP_BASE) + #define MAPPED_ADDR_RW_TO_PHYS(x) (x - REP_BASE - 16777216) + +-#define MAPPED_KERN_RO_PHYSBASE(n) \ +- (PLAT_NODE_DATA(n)->kern_vars.kv_ro_baseaddr) +-#define MAPPED_KERN_RW_PHYSBASE(n) \ +- (PLAT_NODE_DATA(n)->kern_vars.kv_rw_baseaddr) ++#define MAPPED_KERN_RO_PHYSBASE(n) (hub_data(n)->kern_vars.kv_ro_baseaddr) ++#define MAPPED_KERN_RW_PHYSBASE(n) (hub_data(n)->kern_vars.kv_rw_baseaddr) + + #define MAPPED_KERN_RO_TO_PHYS(x) \ + ((unsigned long)MAPPED_ADDR_RO_TO_PHYS(x) | \ +diff -Nurd linux-2.6.24/include/asm-mips/stackframe.h mer-smartq-kernel/include/asm-mips/stackframe.h +--- linux-2.6.24/include/asm-mips/stackframe.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/stackframe.h 2009-11-17 12:13:39.000000000 +0100 +@@ -288,14 +288,31 @@ + #ifdef CONFIG_MIPS_MT_SMTC + .set mips32r2 + /* +- * This may not really be necessary if ints are already +- * inhibited here. ++ * We need to make sure the read-modify-write ++ * of Status below isn't perturbed by an interrupt ++ * or cross-TC access, so we need to do at least a DMT, ++ * protected by an interrupt-inhibit. But setting IXMT ++ * also creates a few-cycle window where an IPI could ++ * be queued and not be detected before potentially ++ * returning to a WAIT or user-mode loop. It must be ++ * replayed. ++ * ++ * We're in the middle of a context switch, and ++ * we can't dispatch it directly without trashing ++ * some registers, so we'll try to detect this unlikely ++ * case and program a software interrupt in the VPE, ++ * as would be done for a cross-VPE IPI. To accomodate ++ * the handling of that case, we're doing a DVPE instead ++ * of just a DMT here to protect against other threads. ++ * This is a lot of cruft to cover a tiny window. ++ * If you can find a better design, implement it! ++ * + */ + mfc0 v0, CP0_TCSTATUS + ori v0, TCSTATUS_IXMT + mtc0 v0, CP0_TCSTATUS + _ehb +- DMT 5 # dmt a1 ++ DVPE 5 # dvpe a1 + jal mips_ihb + #endif /* CONFIG_MIPS_MT_SMTC */ + mfc0 a0, CP0_STATUS +@@ -316,17 +333,50 @@ + */ + LONG_L v1, PT_TCSTATUS(sp) + _ehb +- mfc0 v0, CP0_TCSTATUS ++ mfc0 a0, CP0_TCSTATUS + andi v1, TCSTATUS_IXMT +- /* We know that TCStatua.IXMT should be set from above */ +- xori v0, v0, TCSTATUS_IXMT +- or v0, v0, v1 +- mtc0 v0, CP0_TCSTATUS +- _ehb +- andi a1, a1, VPECONTROL_TE ++ bnez v1, 0f ++ ++/* ++ * We'd like to detect any IPIs queued in the tiny window ++ * above and request an software interrupt to service them ++ * when we ERET. ++ * ++ * Computing the offset into the IPIQ array of the executing ++ * TC's IPI queue in-line would be tedious. We use part of ++ * the TCContext register to hold 16 bits of offset that we ++ * can add in-line to find the queue head. ++ */ ++ mfc0 v0, CP0_TCCONTEXT ++ la a2, IPIQ ++ srl v0, v0, 16 ++ addu a2, a2, v0 ++ LONG_L v0, 0(a2) ++ beqz v0, 0f ++/* ++ * If we have a queue, provoke dispatch within the VPE by setting C_SW1 ++ */ ++ mfc0 v0, CP0_CAUSE ++ ori v0, v0, C_SW1 ++ mtc0 v0, CP0_CAUSE ++0: ++ /* ++ * This test should really never branch but ++ * let's be prudent here. Having atomized ++ * the shared register modifications, we can ++ * now EVPE, and must do so before interrupts ++ * are potentially re-enabled. ++ */ ++ andi a1, a1, MVPCONTROL_EVP + beqz a1, 1f +- emt ++ evpe + 1: ++ /* We know that TCStatua.IXMT should be set from above */ ++ xori a0, a0, TCSTATUS_IXMT ++ or a0, a0, v1 ++ mtc0 a0, CP0_TCSTATUS ++ _ehb ++ + .set mips0 + #endif /* CONFIG_MIPS_MT_SMTC */ + LONG_L v1, PT_EPC(sp) +diff -Nurd linux-2.6.24/include/asm-mips/time.h mer-smartq-kernel/include/asm-mips/time.h +--- linux-2.6.24/include/asm-mips/time.h 2008-01-24 23:58:37.000000000 +0100 ++++ mer-smartq-kernel/include/asm-mips/time.h 2009-11-17 12:13:39.000000000 +0100 +@@ -70,11 +70,12 @@ + /* + * Initialize the count register as a clocksource + */ +-#ifdef CONFIG_CEVT_R4K +-extern void init_mips_clocksource(void); ++#ifdef CONFIG_CSRC_R4K ++extern int init_mips_clocksource(void); + #else +-static inline void init_mips_clocksource(void) ++static inline int init_mips_clocksource(void) + { ++ return 0; + } + #endif + +diff -Nurd linux-2.6.24/Makefile mer-smartq-kernel/Makefile +--- linux-2.6.24/Makefile 2009-11-17 21:04:50.000000000 +0100 ++++ mer-smartq-kernel/Makefile 2009-11-17 18:05:54.000000000 +0100 +@@ -190,7 +190,7 @@ + # Default value for CROSS_COMPILE is not to prefix executables + # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile + export KBUILD_BUILDHOST := $(SUBARCH) +-ARCH ?= $(SUBARCH) ++ARCH ?= mips + CROSS_COMPILE ?= + + # Architecture as present in compile.h |