diff options
Diffstat (limited to 'arch/mips')
119 files changed, 3101 insertions, 1839 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 8724ed3298d..e5a7c5d9636 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -81,7 +81,9 @@ config MIPS_COBALT config MACH_DECSTATION bool "DECstations" select BOOT_ELF32 + select CEVT_DS1287 select CEVT_R4K + select CSRC_IOASIC select CSRC_R4K select CPU_DADDI_WORKAROUNDS if 64BIT select CPU_R4000_WORKAROUNDS if 64BIT @@ -221,6 +223,7 @@ config MIPS_MALTA select DMA_NONCOHERENT select GENERIC_ISA_DMA select IRQ_CPU + select IRQ_GIC select HW_HAS_PCI select I8253 select I8259 @@ -309,12 +312,12 @@ config MACH_VR41XX select GENERIC_HARDIRQS_NO__DO_IRQ config PNX8550_JBS - bool "Philips PNX8550 based JBS board" + bool "NXP PNX8550 based JBS board" select PNX8550 select SYS_SUPPORTS_LITTLE_ENDIAN config PNX8550_STB810 - bool "Philips PNX8550 based STB810 board" + bool "NXP PNX8550 based STB810 board" select PNX8550 select SYS_SUPPORTS_LITTLE_ENDIAN @@ -612,6 +615,7 @@ config TOSHIBA_JMR3927 select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_BIG_ENDIAN select GENERIC_HARDIRQS_NO__DO_IRQ + select GPIO_TXX9 config TOSHIBA_RBTX4927 bool "Toshiba RBTX49[23]7 board" @@ -653,7 +657,7 @@ config TOSHIBA_RBTX4938 select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_KGDB select GENERIC_HARDIRQS_NO__DO_IRQ - select GENERIC_GPIO + select GPIO_TXX9 help This Toshiba board is based on the TX4938 processor. Say Y here to support this machine type @@ -767,6 +771,9 @@ config BOOT_RAW config CEVT_BCM1480 bool +config CEVT_DS1287 + bool + config CEVT_GT641XX bool @@ -782,12 +789,20 @@ config CEVT_TXX9 config CSRC_BCM1480 bool +config CSRC_IOASIC + bool + config CSRC_R4K bool config CSRC_SB1250 bool +config GPIO_TXX9 + select GENERIC_GPIO + select HAVE_GPIO_LIB + bool + config CFE bool @@ -840,6 +855,9 @@ config MIPS_NILE4 config MIPS_DISABLE_OBSOLETE_IDE bool +config SYNC_R4K + bool + config NO_IOPORT def_bool n @@ -909,6 +927,9 @@ config IRQ_TXX9 config IRQ_GT641XX bool +config IRQ_GIC + bool + config MIPS_BOARDS_GEN bool @@ -1811,6 +1832,17 @@ config NR_CPUS performance should round up your number of processors to the next power of two. +config MIPS_CMP + bool "MIPS CMP framework support" + depends on SMP + select SYNC_R4K + select SYS_SUPPORTS_SCHED_SMT + select WEAK_ORDERING + default n + help + This is a placeholder option for the GCMP work. It will need to + be handled differently... + source "kernel/time/Kconfig" # diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index fd7124c1b75..f18cf92650e 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug @@ -73,14 +73,4 @@ config RUNTIME_DEBUG include/asm-mips/debug.h for debuging macros. If unsure, say N. -config MIPS_UNCACHED - bool "Run uncached" - depends on DEBUG_KERNEL && !SMP && !SGI_IP27 - help - If you say Y here there kernel will disable all CPU caches. This will - reduce the system's performance dramatically but can help finding - otherwise hard to track bugs. It can also useful if you're doing - hardware debugging with a logic analyzer and need to see all traffic - on the bus. - endmenu diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 1c62381f5c2..69648d01acc 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -410,21 +410,21 @@ load-$(CONFIG_CASIO_E55) += 0xffffffff80004000 load-$(CONFIG_TANBAC_TB022X) += 0xffffffff80000000 # -# Common Philips PNX8550 +# Common NXP PNX8550 # -core-$(CONFIG_SOC_PNX8550) += arch/mips/philips/pnx8550/common/ +core-$(CONFIG_SOC_PNX8550) += arch/mips/nxp/pnx8550/common/ cflags-$(CONFIG_SOC_PNX8550) += -Iinclude/asm-mips/mach-pnx8550 # -# Philips PNX8550 JBS board +# NXP PNX8550 JBS board # -libs-$(CONFIG_PNX8550_JBS) += arch/mips/philips/pnx8550/jbs/ +libs-$(CONFIG_PNX8550_JBS) += arch/mips/nxp/pnx8550/jbs/ #cflags-$(CONFIG_PNX8550_JBS) += -Iinclude/asm-mips/mach-pnx8550 load-$(CONFIG_PNX8550_JBS) += 0xffffffff80060000 -# Philips PNX8550 STB810 board +# NXP PNX8550 STB810 board # -libs-$(CONFIG_PNX8550_STB810) += arch/mips/philips/pnx8550/stb810/ +libs-$(CONFIG_PNX8550_STB810) += arch/mips/nxp/pnx8550/stb810/ load-$(CONFIG_PNX8550_STB810) += 0xffffffff80060000 # NEC EMMA2RH boards diff --git a/arch/mips/au1000/common/cputable.c b/arch/mips/au1000/common/cputable.c index 5c0d35d6e22..8c93a05d738 100644 --- a/arch/mips/au1000/common/cputable.c +++ b/arch/mips/au1000/common/cputable.c @@ -11,10 +11,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#include <linux/string.h> -#include <linux/sched.h> -#include <linux/threads.h> -#include <linux/init.h> + #include <asm/mach-au1x00/au1000.h> struct cpu_spec* cur_cpu_spec[NR_CPUS]; diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c index 57f17b41098..53377dfc064 100644 --- a/arch/mips/au1000/common/dbdma.c +++ b/arch/mips/au1000/common/dbdma.c @@ -31,18 +31,12 @@ */ #include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/string.h> -#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/module.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1xxx_dbdma.h> -#include <asm/system.h> - #if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) diff --git a/arch/mips/au1000/common/dbg_io.c b/arch/mips/au1000/common/dbg_io.c index 79e0b0a51ac..eae1bb2ca26 100644 --- a/arch/mips/au1000/common/dbg_io.c +++ b/arch/mips/au1000/common/dbg_io.c @@ -1,5 +1,4 @@ -#include <asm/io.h> #include <asm/mach-au1x00/au1000.h> #ifdef CONFIG_KGDB @@ -55,8 +54,7 @@ typedef unsigned int uint32; #define UART16550_READ(y) (au_readl(DEBUG_BASE + y) & 0xff) #define UART16550_WRITE(y, z) (au_writel(z&0xff, DEBUG_BASE + y)) -extern unsigned long get_au1x00_uart_baud_base(void); -extern unsigned long cal_r4koff(void); +extern unsigned long calc_clock(void); void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) { @@ -64,7 +62,7 @@ void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) if (UART16550_READ(UART_MOD_CNTRL) != 0x3) { UART16550_WRITE(UART_MOD_CNTRL, 3); } - cal_r4koff(); + calc_clock(); /* disable interrupts */ UART16550_WRITE(UART_IER, 0); diff --git a/arch/mips/au1000/common/dma.c b/arch/mips/au1000/common/dma.c index c78260d4e83..95f69ea146e 100644 --- a/arch/mips/au1000/common/dma.c +++ b/arch/mips/au1000/common/dma.c @@ -33,12 +33,9 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/sched.h> #include <linux/spinlock.h> -#include <linux/string.h> -#include <linux/delay.h> #include <linux/interrupt.h> -#include <asm/system.h> + #include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1000_dma.h> diff --git a/arch/mips/au1000/common/gpio.c b/arch/mips/au1000/common/gpio.c index 0b658f1db4c..52545258997 100644 --- a/arch/mips/au1000/common/gpio.c +++ b/arch/mips/au1000/common/gpio.c @@ -27,13 +27,8 @@ * others have a second one : GPIO2 */ -#include <linux/init.h> -#include <linux/io.h> -#include <linux/types.h> #include <linux/module.h> -#include <asm/addrspace.h> - #include <asm/mach-au1x00/au1000.h> #include <asm/gpio.h> diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c index 3c7714f057a..f0626992fd7 100644 --- a/arch/mips/au1000/common/irq.c +++ b/arch/mips/au1000/common/irq.c @@ -1,7 +1,6 @@ /* - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com + * Copyright 2001, 2007-2008 MontaVista Software Inc. + * Author: MontaVista Software, Inc. <source@mvista.com> * * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) * @@ -27,7 +26,6 @@ */ #include <linux/bitops.h> #include <linux/init.h> -#include <linux/io.h> #include <linux/interrupt.h> #include <linux/irq.h> @@ -591,7 +589,7 @@ void __init arch_init_irq(void) imp++; } - set_c0_status(ALLINTS); + set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); /* Board specific IRQ initialization. */ diff --git a/arch/mips/au1000/common/pci.c b/arch/mips/au1000/common/pci.c index ce771487567..7e966b31e3e 100644 --- a/arch/mips/au1000/common/pci.c +++ b/arch/mips/au1000/common/pci.c @@ -30,7 +30,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/types.h> + #include <linux/pci.h> #include <linux/kernel.h> #include <linux/init.h> diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c index 39d68126529..31d2a227087 100644 --- a/arch/mips/au1000/common/platform.c +++ b/arch/mips/au1000/common/platform.c @@ -3,18 +3,65 @@ * * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> * + * (C) Copyright Embedded Alley Solutions, Inc 2005 + * Author: Pantelis Antoniou <pantelis@embeddedalley.com> + * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ -#include <linux/device.h> + #include <linux/platform_device.h> -#include <linux/kernel.h> +#include <linux/serial_8250.h> #include <linux/init.h> -#include <linux/resource.h> #include <asm/mach-au1x00/au1xxx.h> +#define PORT(_base, _irq) \ + { \ + .iobase = _base, \ + .membase = (void __iomem *)_base,\ + .mapbase = CPHYSADDR(_base), \ + .irq = _irq, \ + .regshift = 2, \ + .iotype = UPIO_AU, \ + .flags = UPF_SKIP_TEST \ + } + +static struct plat_serial8250_port au1x00_uart_data[] = { +#if defined(CONFIG_SERIAL_8250_AU1X00) +#if defined(CONFIG_SOC_AU1000) + PORT(UART0_ADDR, AU1000_UART0_INT), + PORT(UART1_ADDR, AU1000_UART1_INT), + PORT(UART2_ADDR, AU1000_UART2_INT), + PORT(UART3_ADDR, AU1000_UART3_INT), +#elif defined(CONFIG_SOC_AU1500) + PORT(UART0_ADDR, AU1500_UART0_INT), + PORT(UART3_ADDR, AU1500_UART3_INT), +#elif defined(CONFIG_SOC_AU1100) + PORT(UART0_ADDR, AU1100_UART0_INT), + PORT(UART1_ADDR, AU1100_UART1_INT), + PORT(UART3_ADDR, AU1100_UART3_INT), +#elif defined(CONFIG_SOC_AU1550) + PORT(UART0_ADDR, AU1550_UART0_INT), + PORT(UART1_ADDR, AU1550_UART1_INT), + PORT(UART3_ADDR, AU1550_UART3_INT), +#elif defined(CONFIG_SOC_AU1200) + PORT(UART0_ADDR, AU1200_UART0_INT), + PORT(UART1_ADDR, AU1200_UART1_INT), +#endif +#endif /* CONFIG_SERIAL_8250_AU1X00 */ + { }, +}; + +static struct platform_device au1xx0_uart_device = { + .name = "serial8250", + .id = PLAT8250_DEV_AU1X00, + .dev = { + .platform_data = au1x00_uart_data, + }, +}; + /* OHCI (USB full speed host controller) */ static struct resource au1xxx_usb_ohci_resources[] = { [0] = { @@ -186,19 +233,6 @@ static struct resource au1200_lcd_resources[] = { } }; -static struct resource au1200_ide0_resources[] = { - [0] = { - .start = AU1XXX_ATA_PHYS_ADDR, - .end = AU1XXX_ATA_PHYS_ADDR + AU1XXX_ATA_PHYS_LEN - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = AU1XXX_ATA_INT, - .end = AU1XXX_ATA_INT, - .flags = IORESOURCE_IRQ, - } -}; - static u64 au1200_lcd_dmamask = ~(u32)0; static struct platform_device au1200_lcd_device = { @@ -212,20 +246,6 @@ static struct platform_device au1200_lcd_device = { .resource = au1200_lcd_resources, }; - -static u64 ide0_dmamask = ~(u32)0; - -static struct platform_device au1200_ide0_device = { - .name = "au1200-ide", - .id = 0, - .dev = { - .dma_mask = &ide0_dmamask, - .coherent_dma_mask = 0xffffffff, - }, - .num_resources = ARRAY_SIZE(au1200_ide0_resources), - .resource = au1200_ide0_resources, -}; - static u64 au1xxx_mmc_dmamask = ~(u32)0; static struct platform_device au1xxx_mmc_device = { @@ -245,31 +265,6 @@ static struct platform_device au1x00_pcmcia_device = { .id = 0, }; -#ifdef CONFIG_MIPS_DB1200 - -static struct resource smc91x_resources[] = { - [0] = { - .name = "smc91x-regs", - .start = AU1XXX_SMC91111_PHYS_ADDR, - .end = AU1XXX_SMC91111_PHYS_ADDR + 0xfffff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = AU1XXX_SMC91111_IRQ, - .end = AU1XXX_SMC91111_IRQ, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device smc91x_device = { - .name = "smc91x", - .id = -1, - .num_resources = ARRAY_SIZE(smc91x_resources), - .resource = smc91x_resources, -}; - -#endif - /* All Alchemy demoboards with I2C have this #define in their headers */ #ifdef SMBUS_PSC_BASE static struct resource pbdb_smbus_resources[] = { @@ -289,6 +284,7 @@ static struct platform_device pbdb_smbus_device = { #endif static struct platform_device *au1xxx_platform_devices[] __initdata = { + &au1xx0_uart_device, &au1xxx_usb_ohci_device, &au1x00_pcmcia_device, #ifdef CONFIG_FB_AU1100 @@ -299,12 +295,8 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = { &au1xxx_usb_gdt_device, &au1xxx_usb_otg_device, &au1200_lcd_device, - &au1200_ide0_device, &au1xxx_mmc_device, #endif -#ifdef CONFIG_MIPS_DB1200 - &smc91x_device, -#endif #ifdef SMBUS_PSC_BASE &pbdb_smbus_device, #endif @@ -312,6 +304,13 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = { int __init au1xxx_platform_init(void) { + unsigned int uartclk = get_au1x00_uart_baud_base() * 16; + int i; + + /* Fill up uartclk. */ + for (i = 0; au1x00_uart_data[i].flags ; i++) + au1x00_uart_data[i].uartclk = uartclk; + return platform_add_devices(au1xxx_platform_devices, ARRAY_SIZE(au1xxx_platform_devices)); } diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c index 54047d69b82..812a5f8b7d2 100644 --- a/arch/mips/au1000/common/power.c +++ b/arch/mips/au1000/common/power.c @@ -29,17 +29,14 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> #include <linux/pm.h> #include <linux/pm_legacy.h> -#include <linux/slab.h> #include <linux/sysctl.h> #include <linux/jiffies.h> -#include <asm/string.h> #include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> #include <asm/cacheflush.h> #include <asm/mach-au1x00/au1000.h> @@ -47,17 +44,13 @@ #define DEBUG 1 #ifdef DEBUG -# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk("%s: " fmt, __func__, ## args) #else # define DPRINTK(fmt, args...) #endif static void au1000_calibrate_delay(void); -extern void set_au1x00_speed(unsigned int new_freq); -extern unsigned int get_au1x00_speed(void); -extern unsigned long get_au1x00_uart_baud_base(void); -extern void set_au1x00_uart_baud_base(unsigned long new_baud_base); extern unsigned long save_local_and_disable(int controller); extern void restore_local_and_enable(int controller, unsigned long mask); extern void local_enable_irq(unsigned int irq_nr); diff --git a/arch/mips/au1000/common/prom.c b/arch/mips/au1000/common/prom.c index 90d70695aa6..f10af829e4e 100644 --- a/arch/mips/au1000/common/prom.c +++ b/arch/mips/au1000/common/prom.c @@ -33,8 +33,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/module.h> -#include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> diff --git a/arch/mips/au1000/common/puts.c b/arch/mips/au1000/common/puts.c index 2705829cd46..e34c67e8929 100644 --- a/arch/mips/au1000/common/puts.c +++ b/arch/mips/au1000/common/puts.c @@ -28,7 +28,6 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/types.h> #include <asm/mach-au1x00/au1000.h> #define SERIAL_BASE UART_BASE diff --git a/arch/mips/au1000/common/reset.c b/arch/mips/au1000/common/reset.c index b8638d293cf..60cec537c74 100644 --- a/arch/mips/au1000/common/reset.c +++ b/arch/mips/au1000/common/reset.c @@ -27,13 +27,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/sched.h> -#include <linux/mm.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/processor.h> -#include <asm/reboot.h> -#include <asm/system.h> + #include <asm/mach-au1x00/au1000.h> extern int au_sleep(void); diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c index 9e4ab80caab..0e86f7a6b4a 100644 --- a/arch/mips/au1000/common/setup.c +++ b/arch/mips/au1000/common/setup.c @@ -25,21 +25,14 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/sched.h> #include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/delay.h> -#include <linux/interrupt.h> #include <linux/module.h> #include <linux/pm.h> -#include <asm/cpu.h> -#include <asm/bootinfo.h> -#include <asm/irq.h> #include <asm/mipsregs.h> #include <asm/reboot.h> -#include <asm/pgtable.h> #include <asm/time.h> #include <au1000.h> @@ -49,8 +42,6 @@ extern void __init board_setup(void); extern void au1000_restart(char *); extern void au1000_halt(void); extern void au1000_power_off(void); -extern void au1x_time_init(void); -extern void au1x_timer_setup(struct irqaction *irq); extern void set_cpuspec(void); void __init plat_mem_setup(void) diff --git a/arch/mips/au1000/common/sleeper.S b/arch/mips/au1000/common/sleeper.S index 683d9da84b6..4b3cf021a45 100644 --- a/arch/mips/au1000/common/sleeper.S +++ b/arch/mips/au1000/common/sleeper.S @@ -9,9 +9,9 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ + #include <asm/asm.h> #include <asm/mipsregs.h> -#include <asm/addrspace.h> #include <asm/regdef.h> #include <asm/stackframe.h> diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index e122bbc6cd8..bdb6d73b26f 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2001 MontaVista Software, ppopov@mvista.com + * Copyright (C) 2001, 2006, 2008 MontaVista Software, <source@mvista.com> * Copied and modified Carsten Langgaard's time.c * * Carsten Langgaard, carstenl@mips.com @@ -34,23 +34,13 @@ #include <linux/types.h> #include <linux/init.h> -#include <linux/kernel_stat.h> -#include <linux/sched.h> #include <linux/spinlock.h> -#include <linux/hardirq.h> -#include <asm/compiler.h> #include <asm/mipsregs.h> #include <asm/time.h> -#include <asm/div64.h> #include <asm/mach-au1x00/au1000.h> -#include <linux/mc146818rtc.h> -#include <linux/timex.h> - -static unsigned long r4k_offset; /* Amount to increment compare reg each time */ -static unsigned long r4k_cur; /* What counter should be at next timer irq */ -int no_au1xxx_32khz; +static int no_au1xxx_32khz; extern int allow_au1k_wait; /* default off for CP0 Counter */ #ifdef CONFIG_PM @@ -184,7 +174,7 @@ wakeup_counter0_set(int ticks) * "wait" is enabled, and we need to detect if the 32KHz isn't present * but requested......got it? :-) -- Dan */ -unsigned long cal_r4koff(void) +unsigned long calc_clock(void) { unsigned long cpu_speed; unsigned long flags; @@ -229,19 +219,13 @@ unsigned long cal_r4koff(void) // Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16)); spin_unlock_irqrestore(&time_lock, flags); - return (cpu_speed / HZ); + return cpu_speed; } void __init plat_time_init(void) { - unsigned int est_freq; - - printk("calculating r4koff... "); - r4k_offset = cal_r4koff(); - printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); + unsigned int est_freq = calc_clock(); - //est_freq = 2*r4k_offset*HZ; - est_freq = r4k_offset*HZ; est_freq += 5000; /* round */ est_freq -= est_freq%10000; printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, @@ -249,9 +233,6 @@ void __init plat_time_init(void) set_au1x00_speed(est_freq); set_au1x00_lcd_clock(); // program the LCD clock - r4k_cur = (read_c0_count() + r4k_offset); - write_c0_compare(r4k_cur); - #ifdef CONFIG_PM /* * setup counter 0, since it keeps ticking after a @@ -265,12 +246,8 @@ void __init plat_time_init(void) * Check to ensure we really have a 32KHz oscillator before * we do this. */ - if (no_au1xxx_32khz) { + if (no_au1xxx_32khz) printk("WARNING: no 32KHz clock found.\n"); - - /* Ensure we get CPO_COUNTER interrupts. */ - set_c0_status(IE_IRQ5); - } else { while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S); au_writel(0, SYS_TOYWRITE); diff --git a/arch/mips/au1000/db1x00/board_setup.c b/arch/mips/au1000/db1x00/board_setup.c index 99eafeada51..b7dcbad5c58 100644 --- a/arch/mips/au1000/db1x00/board_setup.c +++ b/arch/mips/au1000/db1x00/board_setup.c @@ -27,20 +27,9 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/console.h> -#include <linux/mc146818rtc.h> -#include <linux/delay.h> - -#include <asm/cpu.h> -#include <asm/bootinfo.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> -#include <asm/reboot.h> -#include <asm/pgtable.h> + #include <asm/mach-au1x00/au1000.h> #include <asm/mach-db1x00/db1x00.h> diff --git a/arch/mips/au1000/db1x00/init.c b/arch/mips/au1000/db1x00/init.c index e822c123eab..d3b967caf70 100644 --- a/arch/mips/au1000/db1x00/init.c +++ b/arch/mips/au1000/db1x00/init.c @@ -28,13 +28,8 @@ */ #include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/bootmem.h> -#include <linux/string.h> #include <linux/kernel.h> -#include <asm/addrspace.h> #include <asm/bootinfo.h> #include <prom.h> diff --git a/arch/mips/au1000/db1x00/irqmap.c b/arch/mips/au1000/db1x00/irqmap.c index 09cea03411b..eaa50c7b634 100644 --- a/arch/mips/au1000/db1x00/irqmap.c +++ b/arch/mips/au1000/db1x00/irqmap.c @@ -25,26 +25,9 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/errno.h> + #include <linux/init.h> -#include <linux/irq.h> -#include <linux/kernel_stat.h> -#include <linux/module.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timex.h> -#include <linux/slab.h> -#include <linux/random.h> -#include <linux/delay.h> -#include <linux/bitops.h> -#include <asm/bootinfo.h> -#include <asm/io.h> -#include <asm/mipsregs.h> -#include <asm/system.h> #include <asm/mach-au1x00/au1000.h> #ifdef CONFIG_MIPS_DB1500 diff --git a/arch/mips/au1000/mtx-1/board_setup.c b/arch/mips/au1000/mtx-1/board_setup.c index 310d5dff89f..5736354829c 100644 --- a/arch/mips/au1000/mtx-1/board_setup.c +++ b/arch/mips/au1000/mtx-1/board_setup.c @@ -28,19 +28,9 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/console.h> -#include <linux/delay.h> -#include <asm/cpu.h> -#include <asm/bootinfo.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> -#include <asm/reboot.h> -#include <asm/pgtable.h> #include <asm/mach-au1x00/au1000.h> extern int (*board_pci_idsel)(unsigned int devsel, int assert); diff --git a/arch/mips/au1000/mtx-1/init.c b/arch/mips/au1000/mtx-1/init.c index e700fd312a2..c015cbce1cc 100644 --- a/arch/mips/au1000/mtx-1/init.c +++ b/arch/mips/au1000/mtx-1/init.c @@ -28,14 +28,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/string.h> + #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/init.h> -#include <linux/mm.h> -#include <linux/bootmem.h> -#include <asm/addrspace.h> #include <asm/bootinfo.h> #include <prom.h> diff --git a/arch/mips/au1000/mtx-1/irqmap.c b/arch/mips/au1000/mtx-1/irqmap.c index 49c612aeddc..78d70c42c9d 100644 --- a/arch/mips/au1000/mtx-1/irqmap.c +++ b/arch/mips/au1000/mtx-1/irqmap.c @@ -25,26 +25,9 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/errno.h> + #include <linux/init.h> -#include <linux/irq.h> -#include <linux/kernel_stat.h> -#include <linux/module.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timex.h> -#include <linux/slab.h> -#include <linux/random.h> -#include <linux/delay.h> -#include <linux/bitops.h> -#include <asm/bootinfo.h> -#include <asm/io.h> -#include <asm/mipsregs.h> -#include <asm/system.h> #include <asm/mach-au1x00/au1000.h> char irq_tab_alchemy[][5] __initdata = { diff --git a/arch/mips/au1000/mtx-1/platform.c b/arch/mips/au1000/mtx-1/platform.c index ce8637b3afa..a7edbf0829a 100644 --- a/arch/mips/au1000/mtx-1/platform.c +++ b/arch/mips/au1000/mtx-1/platform.c @@ -19,7 +19,6 @@ */ #include <linux/init.h> -#include <linux/types.h> #include <linux/platform_device.h> #include <linux/leds.h> #include <linux/gpio_keys.h> diff --git a/arch/mips/au1000/pb1000/board_setup.c b/arch/mips/au1000/pb1000/board_setup.c index 5198c4f98b4..33f15acc1b1 100644 --- a/arch/mips/au1000/pb1000/board_setup.c +++ b/arch/mips/au1000/pb1000/board_setup.c @@ -23,19 +23,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/console.h> #include <linux/delay.h> -#include <asm/cpu.h> -#include <asm/bootinfo.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> -#include <asm/reboot.h> -#include <asm/pgtable.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-pb1x00/pb1000.h> diff --git a/arch/mips/au1000/pb1000/init.c b/arch/mips/au1000/pb1000/init.c index 2515b9fb24a..549447df71d 100644 --- a/arch/mips/au1000/pb1000/init.c +++ b/arch/mips/au1000/pb1000/init.c @@ -26,14 +26,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/bootmem.h> -#include <linux/string.h> #include <linux/kernel.h> -#include <asm/addrspace.h> #include <asm/bootinfo.h> #include <prom.h> diff --git a/arch/mips/au1000/pb1000/irqmap.c b/arch/mips/au1000/pb1000/irqmap.c index 88e35450820..b3d56b0af32 100644 --- a/arch/mips/au1000/pb1000/irqmap.c +++ b/arch/mips/au1000/pb1000/irqmap.c @@ -25,26 +25,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/errno.h> + #include <linux/init.h> -#include <linux/irq.h> -#include <linux/kernel_stat.h> -#include <linux/module.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/types.h> #include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timex.h> -#include <linux/slab.h> -#include <linux/random.h> -#include <linux/delay.h> -#include <linux/bitops.h> -#include <asm/bootinfo.h> -#include <asm/io.h> -#include <asm/mipsregs.h> -#include <asm/system.h> #include <asm/mach-au1x00/au1000.h> struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/au1000/pb1100/board_setup.c index 42874a6b31d..656164c8e9c 100644 --- a/arch/mips/au1000/pb1100/board_setup.c +++ b/arch/mips/au1000/pb1100/board_setup.c @@ -23,19 +23,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/console.h> #include <linux/delay.h> -#include <asm/cpu.h> -#include <asm/bootinfo.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> -#include <asm/reboot.h> -#include <asm/pgtable.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-pb1x00/pb1100.h> diff --git a/arch/mips/au1000/pb1100/init.c b/arch/mips/au1000/pb1100/init.c index 490c3801c27..c91344648ed 100644 --- a/arch/mips/au1000/pb1100/init.c +++ b/arch/mips/au1000/pb1100/init.c @@ -27,14 +27,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/bootmem.h> -#include <linux/string.h> #include <linux/kernel.h> -#include <asm/addrspace.h> #include <asm/bootinfo.h> #include <prom.h> diff --git a/arch/mips/au1000/pb1100/irqmap.c b/arch/mips/au1000/pb1100/irqmap.c index 880456bf8c1..b5021e3d477 100644 --- a/arch/mips/au1000/pb1100/irqmap.c +++ b/arch/mips/au1000/pb1100/irqmap.c @@ -25,26 +25,9 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/errno.h> + #include <linux/init.h> -#include <linux/irq.h> -#include <linux/kernel_stat.h> -#include <linux/module.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timex.h> -#include <linux/slab.h> -#include <linux/random.h> -#include <linux/delay.h> -#include <linux/bitops.h> -#include <asm/bootinfo.h> -#include <asm/io.h> -#include <asm/mipsregs.h> -#include <asm/system.h> #include <asm/mach-au1x00/au1000.h> struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { diff --git a/arch/mips/au1000/pb1200/Makefile b/arch/mips/au1000/pb1200/Makefile index 970b1b1d5cd..4fe02ea65a6 100644 --- a/arch/mips/au1000/pb1200/Makefile +++ b/arch/mips/au1000/pb1200/Makefile @@ -3,5 +3,6 @@ # lib-y := init.o board_setup.o irqmap.o +obj-y += platform.o EXTRA_CFLAGS += -Werror diff --git a/arch/mips/au1000/pb1200/board_setup.c b/arch/mips/au1000/pb1200/board_setup.c index b98bebfa87c..4493a792cc4 100644 --- a/arch/mips/au1000/pb1200/board_setup.c +++ b/arch/mips/au1000/pb1200/board_setup.c @@ -23,27 +23,11 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> #include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/console.h> -#include <linux/mc146818rtc.h> -#include <linux/delay.h> - -#if defined(CONFIG_BLK_DEV_IDE_AU1XXX) -#include <linux/ide.h> -#endif - -#include <asm/cpu.h> -#include <asm/bootinfo.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> -#include <asm/reboot.h> -#include <asm/pgtable.h> #include <au1000.h> -#include <au1xxx_dbdma.h> #include <prom.h> #ifdef CONFIG_MIPS_PB1200 @@ -52,8 +36,6 @@ #ifdef CONFIG_MIPS_DB1200 #include <asm/mach-db1x00/db1200.h> -#define PB1200_ETH_INT DB1200_ETH_INT -#define PB1200_IDE_INT DB1200_IDE_INT #endif extern void _board_init_irq(void); diff --git a/arch/mips/au1000/pb1200/init.c b/arch/mips/au1000/pb1200/init.c index 069ed45f04f..72af5500660 100644 --- a/arch/mips/au1000/pb1200/init.c +++ b/arch/mips/au1000/pb1200/init.c @@ -27,14 +27,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/bootmem.h> -#include <linux/string.h> #include <linux/kernel.h> -#include <asm/addrspace.h> #include <asm/bootinfo.h> #include <prom.h> diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c index 8fcd0df86f9..e61eb8e0b76 100644 --- a/arch/mips/au1000/pb1200/irqmap.c +++ b/arch/mips/au1000/pb1200/irqmap.c @@ -22,26 +22,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/errno.h> + #include <linux/init.h> -#include <linux/irq.h> -#include <linux/kernel_stat.h> -#include <linux/module.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/types.h> #include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timex.h> -#include <linux/slab.h> -#include <linux/random.h> -#include <linux/delay.h> -#include <linux/bitops.h> - -#include <asm/bootinfo.h> -#include <asm/io.h> -#include <asm/mipsregs.h> -#include <asm/system.h> + #include <asm/mach-au1x00/au1000.h> #ifdef CONFIG_MIPS_PB1200 diff --git a/arch/mips/au1000/pb1200/platform.c b/arch/mips/au1000/pb1200/platform.c new file mode 100644 index 00000000000..5930110b9b6 --- /dev/null +++ b/arch/mips/au1000/pb1200/platform.c @@ -0,0 +1,84 @@ +/* + * Pb1200/DBAu1200 board platform device registration + * + * Copyright (C) 2008 MontaVista Software Inc. <source@mvista.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/init.h> +#include <linux/platform_device.h> + +#include <asm/mach-au1x00/au1xxx.h> + +static struct resource ide_resources[] = { + [0] = { + .start = IDE_PHYS_ADDR, + .end = IDE_PHYS_ADDR + IDE_PHYS_LEN - 1, + .flags = IORESOURCE_MEM + }, + [1] = { + .start = IDE_INT, + .end = IDE_INT, + .flags = IORESOURCE_IRQ + } +}; + +static u64 ide_dmamask = ~(u32)0; + +static struct platform_device ide_device = { + .name = "au1200-ide", + .id = 0, + .dev = { + .dma_mask = &ide_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(ide_resources), + .resource = ide_resources +}; + +static struct resource smc91c111_resources[] = { + [0] = { + .name = "smc91x-regs", + .start = SMC91C111_PHYS_ADDR, + .end = SMC91C111_PHYS_ADDR + 0xf, + .flags = IORESOURCE_MEM + }, + [1] = { + .start = SMC91C111_INT, + .end = SMC91C111_INT, + .flags = IORESOURCE_IRQ + }, +}; + +static struct platform_device smc91c111_device = { + .name = "smc91x", + .id = -1, + .num_resources = ARRAY_SIZE(smc91c111_resources), + .resource = smc91c111_resources +}; + +static struct platform_device *board_platform_devices[] __initdata = { + &ide_device, + &smc91c111_device +}; + +static int __init board_register_devices(void) +{ + return platform_add_devices(board_platform_devices, + ARRAY_SIZE(board_platform_devices)); +} + +arch_initcall(board_register_devices); diff --git a/arch/mips/au1000/pb1500/board_setup.c b/arch/mips/au1000/pb1500/board_setup.c index 5446836869d..24c652e8ec4 100644 --- a/arch/mips/au1000/pb1500/board_setup.c +++ b/arch/mips/au1000/pb1500/board_setup.c @@ -23,19 +23,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/console.h> #include <linux/delay.h> -#include <asm/cpu.h> -#include <asm/bootinfo.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> -#include <asm/reboot.h> -#include <asm/pgtable.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-pb1x00/pb1500.h> diff --git a/arch/mips/au1000/pb1500/init.c b/arch/mips/au1000/pb1500/init.c index db558c96704..488507c07db 100644 --- a/arch/mips/au1000/pb1500/init.c +++ b/arch/mips/au1000/pb1500/init.c @@ -27,14 +27,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/bootmem.h> -#include <linux/string.h> #include <linux/kernel.h> -#include <asm/addrspace.h> #include <asm/bootinfo.h> #include <prom.h> diff --git a/arch/mips/au1000/pb1500/irqmap.c b/arch/mips/au1000/pb1500/irqmap.c index 810f695e24b..4817ab44d07 100644 --- a/arch/mips/au1000/pb1500/irqmap.c +++ b/arch/mips/au1000/pb1500/irqmap.c @@ -25,26 +25,9 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/errno.h> + #include <linux/init.h> -#include <linux/irq.h> -#include <linux/kernel_stat.h> -#include <linux/module.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timex.h> -#include <linux/slab.h> -#include <linux/random.h> -#include <linux/delay.h> -#include <linux/bitops.h> -#include <asm/bootinfo.h> -#include <asm/io.h> -#include <asm/mipsregs.h> -#include <asm/system.h> #include <asm/mach-au1x00/au1000.h> char irq_tab_alchemy[][5] __initdata = { diff --git a/arch/mips/au1000/pb1550/board_setup.c b/arch/mips/au1000/pb1550/board_setup.c index e3cfb0d7318..45d60872b56 100644 --- a/arch/mips/au1000/pb1550/board_setup.c +++ b/arch/mips/au1000/pb1550/board_setup.c @@ -27,20 +27,9 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/console.h> -#include <linux/mc146818rtc.h> -#include <linux/delay.h> -#include <asm/cpu.h> -#include <asm/bootinfo.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> -#include <asm/reboot.h> -#include <asm/pgtable.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-pb1x00/pb1550.h> diff --git a/arch/mips/au1000/pb1550/init.c b/arch/mips/au1000/pb1550/init.c index b716363ea56..f6b2fc58798 100644 --- a/arch/mips/au1000/pb1550/init.c +++ b/arch/mips/au1000/pb1550/init.c @@ -27,14 +27,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/bootmem.h> -#include <linux/string.h> #include <linux/kernel.h> -#include <asm/addrspace.h> #include <asm/bootinfo.h> #include <prom.h> diff --git a/arch/mips/au1000/pb1550/irqmap.c b/arch/mips/au1000/pb1550/irqmap.c index 56becab28e5..e1dac37af08 100644 --- a/arch/mips/au1000/pb1550/irqmap.c +++ b/arch/mips/au1000/pb1550/irqmap.c @@ -25,26 +25,9 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/errno.h> + #include <linux/init.h> -#include <linux/irq.h> -#include <linux/kernel_stat.h> -#include <linux/module.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timex.h> -#include <linux/slab.h> -#include <linux/random.h> -#include <linux/delay.h> -#include <linux/bitops.h> -#include <asm/bootinfo.h> -#include <asm/io.h> -#include <asm/mipsregs.h> -#include <asm/system.h> #include <asm/mach-au1x00/au1000.h> char irq_tab_alchemy[][5] __initdata = { diff --git a/arch/mips/au1000/xxs1500/board_setup.c b/arch/mips/au1000/xxs1500/board_setup.c index b2e413e597a..79d1798621b 100644 --- a/arch/mips/au1000/xxs1500/board_setup.c +++ b/arch/mips/au1000/xxs1500/board_setup.c @@ -23,19 +23,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/console.h> #include <linux/delay.h> -#include <asm/cpu.h> -#include <asm/bootinfo.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> -#include <asm/reboot.h> -#include <asm/pgtable.h> #include <asm/mach-au1x00/au1000.h> void board_reset(void) diff --git a/arch/mips/au1000/xxs1500/init.c b/arch/mips/au1000/xxs1500/init.c index 7e6878c1b0a..24fc6e132dc 100644 --- a/arch/mips/au1000/xxs1500/init.c +++ b/arch/mips/au1000/xxs1500/init.c @@ -26,14 +26,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/bootmem.h> -#include <linux/string.h> #include <linux/kernel.h> -#include <asm/addrspace.h> #include <asm/bootinfo.h> #include <prom.h> diff --git a/arch/mips/au1000/xxs1500/irqmap.c b/arch/mips/au1000/xxs1500/irqmap.c index a343da13433..dd6e3d1eb4d 100644 --- a/arch/mips/au1000/xxs1500/irqmap.c +++ b/arch/mips/au1000/xxs1500/irqmap.c @@ -25,26 +25,9 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/errno.h> + #include <linux/init.h> -#include <linux/irq.h> -#include <linux/kernel_stat.h> -#include <linux/module.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timex.h> -#include <linux/slab.h> -#include <linux/random.h> -#include <linux/delay.h> -#include <linux/bitops.h> -#include <asm/bootinfo.h> -#include <asm/io.h> -#include <asm/mipsregs.h> -#include <asm/system.h> #include <asm/mach-au1x00/au1000.h> struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig index 6db0bdaefb2..4f6bce99d5c 100644 --- a/arch/mips/configs/mipssim_defconfig +++ b/arch/mips/configs/mipssim_defconfig @@ -641,7 +641,6 @@ CONFIG_CROSSCOMPILE=y CONFIG_CMDLINE="nfsroot=192.168.192.169:/u1/mipsel,timeo=20 ip=dhcp" # CONFIG_DEBUG_STACK_USAGE is not set # CONFIG_RUNTIME_DEBUG is not set -# CONFIG_MIPS_UNCACHED is not set # # Security options diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig index 518a60892b7..780c7fc24b8 100644 --- a/arch/mips/configs/pnx8550-jbs_defconfig +++ b/arch/mips/configs/pnx8550-jbs_defconfig @@ -1223,7 +1223,6 @@ CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp" # CONFIG_KGDB is not set CONFIG_SYS_SUPPORTS_KGDB=y # CONFIG_RUNTIME_DEBUG is not set -# CONFIG_MIPS_UNCACHED is not set # # Security options diff --git a/arch/mips/configs/pnx8550-stb810_defconfig b/arch/mips/configs/pnx8550-stb810_defconfig index 68351eb81bc..267f21ed1d0 100644 --- a/arch/mips/configs/pnx8550-stb810_defconfig +++ b/arch/mips/configs/pnx8550-stb810_defconfig @@ -1213,7 +1213,6 @@ CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp" # CONFIG_KGDB is not set CONFIG_SYS_SUPPORTS_KGDB=y # CONFIG_RUNTIME_DEBUG is not set -# CONFIG_MIPS_UNCACHED is not set # # Security options diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c index 60349062595..3965fda94a8 100644 --- a/arch/mips/dec/time.c +++ b/arch/mips/dec/time.c @@ -9,30 +9,15 @@ * */ #include <linux/bcd.h> -#include <linux/errno.h> #include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> #include <linux/mc146818rtc.h> -#include <linux/mm.h> -#include <linux/module.h> #include <linux/param.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/time.h> -#include <linux/types.h> - -#include <asm/bootinfo.h> -#include <asm/cpu.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> -#include <asm/sections.h> -#include <asm/time.h> +#include <asm/cpu-features.h> +#include <asm/ds1287.h> +#include <asm/time.h> #include <asm/dec/interrupts.h> #include <asm/dec/ioasic.h> -#include <asm/dec/ioasic_addrs.h> #include <asm/dec/machtype.h> unsigned long read_persistent_clock(void) @@ -139,42 +124,32 @@ int rtc_mips_set_mmss(unsigned long nowtime) return retval; } -static int dec_timer_state(void) +void __init plat_time_init(void) { - return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0; -} + u32 start, end; + int i = HZ / 10; -static void dec_timer_ack(void) -{ - CMOS_READ(RTC_REG_C); /* Ack the RTC interrupt. */ -} - -static cycle_t dec_ioasic_hpt_read(void) -{ - /* - * The free-running counter is 32-bit which is good for about - * 2 minutes, 50 seconds at possible count rates of up to 25MHz. - */ - return ioasic_read(IO_REG_FCTR); -} + /* Set up the rate of periodic DS1287 interrupts. */ + ds1287_set_base_clock(HZ); + if (cpu_has_counter) { + while (!ds1287_timer_state()) + ; -void __init plat_time_init(void) -{ - mips_timer_ack = dec_timer_ack; + start = read_c0_count(); - if (!cpu_has_counter && IOASIC) - /* For pre-R4k systems we use the I/O ASIC's counter. */ - clocksource_mips.read = dec_ioasic_hpt_read; + while (i--) + while (!ds1287_timer_state()) + ; - /* Set up the rate of periodic DS1287 interrupts. */ - CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - __ffs(HZ)), RTC_REG_A); -} + end = read_c0_count(); -void __init plat_timer_setup(struct irqaction *irq) -{ - setup_irq(dec_interrupt[DEC_IRQ_RTC], irq); + mips_hpt_frequency = (end - start) * 10; + printk(KERN_INFO "MIPS counter frequency %dHz\n", + mips_hpt_frequency); + } else if (IOASIC) + /* For pre-R4k systems we use the I/O ASIC's counter. */ + dec_ioasic_clocksource_init(); - /* Enable periodic DS1287 interrupts. */ - CMOS_WRITE(CMOS_READ(RTC_REG_B) | RTC_PIE, RTC_REG_B); + ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]); } diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c index c886d804d30..f39c444e42d 100644 --- a/arch/mips/jmr3927/rbhma3100/setup.c +++ b/arch/mips/jmr3927/rbhma3100/setup.c @@ -36,11 +36,13 @@ #include <linux/pm.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/gpio.h> #ifdef CONFIG_SERIAL_TXX9 #include <linux/serial_core.h> #endif #include <asm/txx9tmr.h> +#include <asm/txx9pio.h> #include <asm/reboot.h> #include <asm/jmr3927/jmr3927.h> #include <asm/mipsregs.h> @@ -340,9 +342,12 @@ static void __init tx3927_setup(void) /* PIO */ /* PIO[15:12] connected to LEDs */ - tx3927_pioptr->dir = 0x0000f000; - tx3927_pioptr->maskcpu = 0; - tx3927_pioptr->maskext = 0; + __raw_writel(0x0000f000, &tx3927_pioptr->dir); + __raw_writel(0, &tx3927_pioptr->maskcpu); + __raw_writel(0, &tx3927_pioptr->maskext); + txx9_gpio_init(TX3927_PIO_REG, 0, 16); + gpio_request(11, "dipsw1"); + gpio_request(10, "dipsw2"); { unsigned int conf; diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 6fcdb6fda2e..45545be3eb8 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -10,12 +10,15 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o +obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o +obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o +obj-$(CONFIG_SYNC_R4K) += sync-r4k.o binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ irix5sys.o sysirix.o @@ -50,6 +53,8 @@ obj-$(CONFIG_MIPS_MT) += mips-mt.o obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o +obj-$(CONFIG_MIPS_CMP) += smp-cmp.o +obj-$(CONFIG_CPU_MIPSR2) += spram.o obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o @@ -62,6 +67,7 @@ obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o +obj-$(CONFIG_IRQ_GIC) += irq-gic.o obj-$(CONFIG_32BIT) += scall32-o32.o obj-$(CONFIG_64BIT) += scall64-64.o @@ -77,6 +83,8 @@ obj-$(CONFIG_64BIT) += cpu-bugs64.o obj-$(CONFIG_I8253) += i8253.o +obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o + obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff --git a/arch/mips/kernel/cevt-ds1287.c b/arch/mips/kernel/cevt-ds1287.c new file mode 100644 index 00000000000..df4acb68bfb --- /dev/null +++ b/arch/mips/kernel/cevt-ds1287.c @@ -0,0 +1,129 @@ +/* + * DS1287 clockevent driver + * + * Copyright (C) 2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <linux/clockchips.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/mc146818rtc.h> + +#include <asm/time.h> + +int ds1287_timer_state(void) +{ + return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0; +} + +int ds1287_set_base_clock(unsigned int hz) +{ + u8 rate; + + switch (hz) { + case 128: + rate = 0x9; + break; + case 256: + rate = 0x8; + break; + case 1024: + rate = 0x6; + break; + default: + return -EINVAL; + } + + CMOS_WRITE(RTC_REF_CLCK_32KHZ | rate, RTC_REG_A); + + return 0; +} + +static int ds1287_set_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + return -EINVAL; +} + +static void ds1287_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + u8 val; + + spin_lock(&rtc_lock); + + val = CMOS_READ(RTC_REG_B); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + val |= RTC_PIE; + break; + default: + val &= ~RTC_PIE; + break; + } + + CMOS_WRITE(val, RTC_REG_B); + + spin_unlock(&rtc_lock); +} + +static void ds1287_event_handler(struct clock_event_device *dev) +{ +} + +static struct clock_event_device ds1287_clockevent = { + .name = "ds1287", + .features = CLOCK_EVT_FEAT_PERIODIC, + .cpumask = CPU_MASK_CPU0, + .set_next_event = ds1287_set_next_event, + .set_mode = ds1287_set_mode, + .event_handler = ds1287_event_handler, +}; + +static irqreturn_t ds1287_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *cd = &ds1287_clockevent; + + /* Ack the RTC interrupt. */ + CMOS_READ(RTC_REG_C); + + cd->event_handler(cd); + + return IRQ_HANDLED; +} + +static struct irqaction ds1287_irqaction = { + .handler = ds1287_interrupt, + .flags = IRQF_DISABLED | IRQF_PERCPU, + .name = "ds1287", +}; + +int __init ds1287_clockevent_init(int irq) +{ + struct clock_event_device *cd; + + cd = &ds1287_clockevent; + cd->rating = 100; + cd->irq = irq; + clockevent_set_clock(cd, 32768); + cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); + cd->min_delta_ns = clockevent_delta2ns(0x300, cd); + + clockevents_register_device(&ds1287_clockevent); + + return setup_irq(irq, &ds1287_irqaction); +} diff --git a/arch/mips/kernel/cevt-gt641xx.c b/arch/mips/kernel/cevt-gt641xx.c index c36772631fe..6e2f58520af 100644 --- a/arch/mips/kernel/cevt-gt641xx.c +++ b/arch/mips/kernel/cevt-gt641xx.c @@ -25,8 +25,6 @@ #include <asm/gt64120.h> #include <asm/time.h> -#include <irq.h> - static DEFINE_SPINLOCK(gt641xx_timer_lock); static unsigned int gt641xx_base_clock; diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 89c3304cb93..335a6ae3d59 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -169,6 +169,7 @@ static inline void check_wait(void) case CPU_24K: case CPU_34K: + case CPU_1004K: cpu_wait = r4k_wait; if (read_c0_config7() & MIPS_CONF7_WII) cpu_wait = r4k_wait_irqoff; @@ -675,6 +676,12 @@ static void __cpuinit decode_configs(struct cpuinfo_mips *c) return; } +#ifdef CONFIG_CPU_MIPSR2 +extern void spram_config(void); +#else +static inline void spram_config(void) {} +#endif + static inline void cpu_probe_mips(struct cpuinfo_mips *c) { decode_configs(c); @@ -711,7 +718,12 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c) case PRID_IMP_74K: c->cputype = CPU_74K; break; + case PRID_IMP_1004K: + c->cputype = CPU_1004K; + break; } + + spram_config(); } static inline void cpu_probe_alchemy(struct cpuinfo_mips *c) @@ -778,7 +790,7 @@ static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c) } } -static inline void cpu_probe_philips(struct cpuinfo_mips *c) +static inline void cpu_probe_nxp(struct cpuinfo_mips *c) { decode_configs(c); switch (c->processor_id & 0xff00) { @@ -787,7 +799,7 @@ static inline void cpu_probe_philips(struct cpuinfo_mips *c) c->isa_level = MIPS_CPU_ISA_M32R1; break; default: - panic("Unknown Philips Core!"); /* REVISIT: die? */ + panic("Unknown NXP Core!"); /* REVISIT: die? */ break; } } @@ -876,6 +888,7 @@ static __cpuinit const char *cpu_to_name(struct cpuinfo_mips *c) case CPU_24K: name = "MIPS 24K"; break; case CPU_25KF: name = "MIPS 25Kf"; break; case CPU_34K: name = "MIPS 34K"; break; + case CPU_1004K: name = "MIPS 1004K"; break; case CPU_74K: name = "MIPS 74K"; break; case CPU_VR4111: name = "NEC VR4111"; break; case CPU_VR4121: name = "NEC VR4121"; break; @@ -925,8 +938,8 @@ __cpuinit void cpu_probe(void) case PRID_COMP_SANDCRAFT: cpu_probe_sandcraft(c); break; - case PRID_COMP_PHILIPS: - cpu_probe_philips(c); + case PRID_COMP_NXP: + cpu_probe_nxp(c); break; default: c->cputype = CPU_UNKNOWN; diff --git a/arch/mips/kernel/csrc-ioasic.c b/arch/mips/kernel/csrc-ioasic.c new file mode 100644 index 00000000000..1d5f63cf899 --- /dev/null +++ b/arch/mips/kernel/csrc-ioasic.c @@ -0,0 +1,65 @@ +/* + * DEC I/O ASIC's counter clocksource + * + * Copyright (C) 2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <linux/clocksource.h> +#include <linux/init.h> + +#include <asm/ds1287.h> +#include <asm/time.h> +#include <asm/dec/ioasic.h> +#include <asm/dec/ioasic_addrs.h> + +static cycle_t dec_ioasic_hpt_read(void) +{ + return ioasic_read(IO_REG_FCTR); +} + +static struct clocksource clocksource_dec = { + .name = "dec-ioasic", + .read = dec_ioasic_hpt_read, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +void __init dec_ioasic_clocksource_init(void) +{ + unsigned int freq; + u32 start, end; + int i = HZ / 10; + + + while (!ds1287_timer_state()) + ; + + start = dec_ioasic_hpt_read(); + + while (i--) + while (!ds1287_timer_state()) + ; + + end = dec_ioasic_hpt_read(); + + freq = (end - start) * 10; + printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq); + + clocksource_dec.rating = 200 + freq / 10000000; + clocksource_set_clock(&clocksource_dec, freq); + + clocksource_register(&clocksource_dec); +} diff --git a/arch/mips/kernel/gpio_txx9.c b/arch/mips/kernel/gpio_txx9.c new file mode 100644 index 00000000000..b1436a85799 --- /dev/null +++ b/arch/mips/kernel/gpio_txx9.c @@ -0,0 +1,87 @@ +/* + * A gpio chip driver for TXx9 SoCs + * + * Copyright (C) 2008 Atsushi Nemoto <anemo@mba.ocn.ne.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/gpio.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <asm/txx9pio.h> + +static DEFINE_SPINLOCK(txx9_gpio_lock); + +static struct txx9_pio_reg __iomem *txx9_pioptr; + +static int txx9_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + return __raw_readl(&txx9_pioptr->din) & (1 << offset); +} + +static void txx9_gpio_set_raw(unsigned int offset, int value) +{ + u32 val; + val = __raw_readl(&txx9_pioptr->dout); + if (value) + val |= 1 << offset; + else + val &= ~(1 << offset); + __raw_writel(val, &txx9_pioptr->dout); +} + +static void txx9_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + unsigned long flags; + spin_lock_irqsave(&txx9_gpio_lock, flags); + txx9_gpio_set_raw(offset, value); + mmiowb(); + spin_unlock_irqrestore(&txx9_gpio_lock, flags); +} + +static int txx9_gpio_dir_in(struct gpio_chip *chip, unsigned int offset) +{ + spin_lock_irq(&txx9_gpio_lock); + __raw_writel(__raw_readl(&txx9_pioptr->dir) & ~(1 << offset), + &txx9_pioptr->dir); + mmiowb(); + spin_unlock_irq(&txx9_gpio_lock); + return 0; +} + +static int txx9_gpio_dir_out(struct gpio_chip *chip, unsigned int offset, + int value) +{ + spin_lock_irq(&txx9_gpio_lock); + txx9_gpio_set_raw(offset, value); + __raw_writel(__raw_readl(&txx9_pioptr->dir) | (1 << offset), + &txx9_pioptr->dir); + mmiowb(); + spin_unlock_irq(&txx9_gpio_lock); + return 0; +} + +static struct gpio_chip txx9_gpio_chip = { + .get = txx9_gpio_get, + .set = txx9_gpio_set, + .direction_input = txx9_gpio_dir_in, + .direction_output = txx9_gpio_dir_out, + .label = "TXx9", +}; + +int __init txx9_gpio_init(unsigned long baseaddr, + unsigned int base, unsigned int num) +{ + txx9_pioptr = ioremap(baseaddr, sizeof(struct txx9_pio_reg)); + if (!txx9_pioptr) + return -ENODEV; + txx9_gpio_chip.base = base; + txx9_gpio_chip.ngpio = num; + return gpiochip_add(&txx9_gpio_chip); +} diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c new file mode 100644 index 00000000000..f0a4bb19e09 --- /dev/null +++ b/arch/mips/kernel/irq-gic.c @@ -0,0 +1,295 @@ +#undef DEBUG + +#include <linux/bitmap.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/gic.h> +#include <asm/gcmpregs.h> +#include <asm/mips-boards/maltaint.h> +#include <asm/irq.h> +#include <linux/hardirq.h> +#include <asm-generic/bitops/find.h> + + +static unsigned long _gic_base; +static unsigned int _irqbase, _mapsize, numvpes, numintrs; +static struct gic_intr_map *_intrmap; + +static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; +static struct gic_pending_regs pending_regs[NR_CPUS]; +static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; + +#define gic_wedgeb2bok 0 /* + * Can GIC handle b2b writes to wedge register? + */ +#if gic_wedgeb2bok == 0 +static DEFINE_SPINLOCK(gic_wedgeb2b_lock); +#endif + +void gic_send_ipi(unsigned int intr) +{ +#if gic_wedgeb2bok == 0 + unsigned long flags; +#endif + pr_debug("CPU%d: %s status %08x\n", smp_processor_id(), __func__, + read_c0_status()); + if (!gic_wedgeb2bok) + spin_lock_irqsave(&gic_wedgeb2b_lock, flags); + GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr); + if (!gic_wedgeb2bok) { + (void) GIC_REG(SHARED, GIC_SH_CONFIG); + spin_unlock_irqrestore(&gic_wedgeb2b_lock, flags); + } +} + +/* This is Malta specific and needs to be exported */ +static void vpe_local_setup(unsigned int numvpes) +{ + int i; + unsigned long timer_interrupt = 5, perf_interrupt = 5; + unsigned int vpe_ctl; + + /* + * Setup the default performance counter timer interrupts + * for all VPEs + */ + for (i = 0; i < numvpes; i++) { + GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + + /* Are Interrupts locally routable? */ + GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl); + if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK) + GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), + GIC_MAP_TO_PIN_MSK | timer_interrupt); + + if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK) + GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), + GIC_MAP_TO_PIN_MSK | perf_interrupt); + } +} + +unsigned int gic_get_int(void) +{ + unsigned int i; + unsigned long *pending, *intrmask, *pcpu_mask; + unsigned long *pending_abs, *intrmask_abs; + + /* Get per-cpu bitmaps */ + pending = pending_regs[smp_processor_id()].pending; + intrmask = intrmask_regs[smp_processor_id()].intrmask; + pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask; + + pending_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED, + GIC_SH_PEND_31_0_OFS); + intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED, + GIC_SH_MASK_31_0_OFS); + + for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) { + GICREAD(*pending_abs, pending[i]); + GICREAD(*intrmask_abs, intrmask[i]); + pending_abs++; + intrmask_abs++; + } + + bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS); + bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS); + + i = find_first_bit(pending, GIC_NUM_INTRS); + + pr_debug("CPU%d: %s pend=%d\n", smp_processor_id(), __func__, i); + + return i; +} + +static unsigned int gic_irq_startup(unsigned int irq) +{ + pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); + irq -= _irqbase; + /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */ + GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))), + 1 << (irq % 32)); + return 0; +} + +static void gic_irq_ack(unsigned int irq) +{ +#if gic_wedgeb2bok == 0 + unsigned long flags; +#endif + pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); + irq -= _irqbase; + GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))), + 1 << (irq % 32)); + + if (_intrmap[irq].trigtype == GIC_TRIG_EDGE) { + if (!gic_wedgeb2bok) + spin_lock_irqsave(&gic_wedgeb2b_lock, flags); + GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); + if (!gic_wedgeb2bok) { + (void) GIC_REG(SHARED, GIC_SH_CONFIG); + spin_unlock_irqrestore(&gic_wedgeb2b_lock, flags); + } + } +} + +static void gic_mask_irq(unsigned int irq) +{ + pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); + irq -= _irqbase; + /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */ + GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))), + 1 << (irq % 32)); +} + +static void gic_unmask_irq(unsigned int irq) +{ + pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); + irq -= _irqbase; + /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */ + GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))), + 1 << (irq % 32)); +} + +#ifdef CONFIG_SMP + +static DEFINE_SPINLOCK(gic_lock); + +static void gic_set_affinity(unsigned int irq, cpumask_t cpumask) +{ + cpumask_t tmp = CPU_MASK_NONE; + unsigned long flags; + int i; + + pr_debug(KERN_DEBUG "%s called\n", __func__); + irq -= _irqbase; + + cpus_and(tmp, cpumask, cpu_online_map); + if (cpus_empty(tmp)) + return; + + /* Assumption : cpumask refers to a single CPU */ + spin_lock_irqsave(&gic_lock, flags); + for (;;) { + /* Re-route this IRQ */ + GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp)); + + /* + * FIXME: assumption that _intrmap is ordered and has no holes + */ + + /* Update the intr_map */ + _intrmap[irq].cpunum = first_cpu(tmp); + + /* Update the pcpu_masks */ + for (i = 0; i < NR_CPUS; i++) + clear_bit(irq, pcpu_masks[i].pcpu_mask); + set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask); + + } + irq_desc[irq].affinity = cpumask; + spin_unlock_irqrestore(&gic_lock, flags); + +} +#endif + +static struct irq_chip gic_irq_controller = { + .name = "MIPS GIC", + .startup = gic_irq_startup, + .ack = gic_irq_ack, + .mask = gic_mask_irq, + .mask_ack = gic_mask_irq, + .unmask = gic_unmask_irq, + .eoi = gic_unmask_irq, +#ifdef CONFIG_SMP + .set_affinity = gic_set_affinity, +#endif +}; + +static void __init setup_intr(unsigned int intr, unsigned int cpu, + unsigned int pin, unsigned int polarity, unsigned int trigtype) +{ + /* Setup Intr to Pin mapping */ + if (pin & GIC_MAP_TO_NMI_MSK) { + GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin); + /* FIXME: hack to route NMI to all cpu's */ + for (cpu = 0; cpu < NR_CPUS; cpu += 32) { + GICWRITE(GIC_REG_ADDR(SHARED, + GIC_SH_MAP_TO_VPE_REG_OFF(intr, cpu)), + 0xffffffff); + } + } else { + GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), + GIC_MAP_TO_PIN_MSK | pin); + /* Setup Intr to CPU mapping */ + GIC_SH_MAP_TO_VPE_SMASK(intr, cpu); + } + + /* Setup Intr Polarity */ + GIC_SET_POLARITY(intr, polarity); + + /* Setup Intr Trigger Type */ + GIC_SET_TRIGGER(intr, trigtype); + + /* Init Intr Masks */ + GIC_SET_INTR_MASK(intr, 0); +} + +static void __init gic_basic_init(void) +{ + unsigned int i, cpu; + + /* Setup defaults */ + for (i = 0; i < GIC_NUM_INTRS; i++) { + GIC_SET_POLARITY(i, GIC_POL_POS); + GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL); + GIC_SET_INTR_MASK(i, 0); + } + + /* Setup specifics */ + for (i = 0; i < _mapsize; i++) { + cpu = _intrmap[i].cpunum; + if (cpu == X) + continue; + + setup_intr(_intrmap[i].intrnum, + _intrmap[i].cpunum, + _intrmap[i].pin, + _intrmap[i].polarity, + _intrmap[i].trigtype); + /* Initialise per-cpu Interrupt software masks */ + if (_intrmap[i].ipiflag) + set_bit(_intrmap[i].intrnum, pcpu_masks[cpu].pcpu_mask); + } + + vpe_local_setup(numvpes); + + for (i = _irqbase; i < (_irqbase + numintrs); i++) + set_irq_chip(i, &gic_irq_controller); +} + +void __init gic_init(unsigned long gic_base_addr, + unsigned long gic_addrspace_size, + struct gic_intr_map *intr_map, unsigned int intr_map_size, + unsigned int irqbase) +{ + unsigned int gicconfig; + + _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, + gic_addrspace_size); + _irqbase = irqbase; + _intrmap = intr_map; + _mapsize = intr_map_size; + + GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); + numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >> + GIC_SH_CONFIG_NUMINTRS_SHF; + numintrs = ((numintrs + 1) * 8); + + numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >> + GIC_SH_CONFIG_NUMVPES_SHF; + + pr_debug("%s called\n", __func__); + + gic_basic_init(); +} diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c index 4edc7e451d9..963c16d266a 100644 --- a/arch/mips/kernel/irq-msc01.c +++ b/arch/mips/kernel/irq-msc01.c @@ -17,6 +17,7 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/msc01_ic.h> +#include <asm/traps.h> static unsigned long _icctrl_msc; #define MSC01_IC_REG_BASE _icctrl_msc @@ -98,14 +99,13 @@ void ll_msc_irq(void) } } -void -msc_bind_eic_interrupt(unsigned int irq, unsigned int set) +static void msc_bind_eic_interrupt(int irq, int set) { MSCIC_WRITE(MSC01_IC_RAMW, (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF)); } -struct irq_chip msc_levelirq_type = { +static struct irq_chip msc_levelirq_type = { .name = "SOC-it-Level", .ack = level_mask_and_ack_msc_irq, .mask = mask_msc_irq, @@ -115,7 +115,7 @@ struct irq_chip msc_levelirq_type = { .end = end_msc_irq, }; -struct irq_chip msc_edgeirq_type = { +static struct irq_chip msc_edgeirq_type = { .name = "SOC-it-Edge", .ack = edge_mask_and_ack_msc_irq, .mask = mask_msc_irq, @@ -128,8 +128,6 @@ struct irq_chip msc_edgeirq_type = { void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqmap_t *imp, int nirq) { - extern void (*board_bind_eic_interrupt)(unsigned int irq, unsigned int regset); - _icctrl_msc = (unsigned long) ioremap(icubase, 0x40000); /* Reset interrupt controller - initialises all registers to 0 */ diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index c0faabd5201..6c8e8c4246f 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -14,7 +14,7 @@ /* #define DEBUG_SIG */ #ifdef DEBUG_SIG -# define DEBUGP(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args) +# define DEBUGP(fmt, args...) printk("%s: " fmt, __func__, ##args) #else # define DEBUGP(fmt, args...) #endif diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c new file mode 100644 index 00000000000..ca476c4f62a --- /dev/null +++ b/arch/mips/kernel/smp-cmp.c @@ -0,0 +1,265 @@ +/* + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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) 2007 MIPS Technologies, Inc. + * Chris Dearman (chris@mips.com) + */ + +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/cpumask.h> +#include <linux/interrupt.h> +#include <linux/compiler.h> + +#include <asm/atomic.h> +#include <asm/cacheflush.h> +#include <asm/cpu.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/hardirq.h> +#include <asm/mmu_context.h> +#include <asm/smp.h> +#include <asm/time.h> +#include <asm/mipsregs.h> +#include <asm/mipsmtregs.h> +#include <asm/mips_mt.h> + +/* + * Crude manipulation of the CPU masks to control which + * which CPU's are brought online during initialisation + * + * Beware... this needs to be called after CPU discovery + * but before CPU bringup + */ +static int __init allowcpus(char *str) +{ + cpumask_t cpu_allow_map; + char buf[256]; + int len; + + cpus_clear(cpu_allow_map); + if (cpulist_parse(str, cpu_allow_map) == 0) { + cpu_set(0, cpu_allow_map); + cpus_and(cpu_possible_map, cpu_possible_map, cpu_allow_map); + len = cpulist_scnprintf(buf, sizeof(buf)-1, cpu_possible_map); + buf[len] = '\0'; + pr_debug("Allowable CPUs: %s\n", buf); + return 1; + } else + return 0; +} +__setup("allowcpus=", allowcpus); + +static void ipi_call_function(unsigned int cpu) +{ + unsigned int action = 0; + + pr_debug("CPU%d: %s cpu %d status %08x\n", + smp_processor_id(), __func__, cpu, read_c0_status()); + + switch (cpu) { + case 0: + action = GIC_IPI_EXT_INTR_CALLFNC_VPE0; + break; + case 1: + action = GIC_IPI_EXT_INTR_CALLFNC_VPE1; + break; + case 2: + action = GIC_IPI_EXT_INTR_CALLFNC_VPE2; + break; + case 3: + action = GIC_IPI_EXT_INTR_CALLFNC_VPE3; + break; + } + gic_send_ipi(action); +} + + +static void ipi_resched(unsigned int cpu) +{ + unsigned int action = 0; + + pr_debug("CPU%d: %s cpu %d status %08x\n", + smp_processor_id(), __func__, cpu, read_c0_status()); + + switch (cpu) { + case 0: + action = GIC_IPI_EXT_INTR_RESCHED_VPE0; + break; + case 1: + action = GIC_IPI_EXT_INTR_RESCHED_VPE1; + break; + case 2: + action = GIC_IPI_EXT_INTR_RESCHED_VPE2; + break; + case 3: + action = GIC_IPI_EXT_INTR_RESCHED_VPE3; + break; + } + gic_send_ipi(action); +} + +/* + * FIXME: This isn't restricted to CMP + * The SMVP kernel could use GIC interrupts if available + */ +void cmp_send_ipi_single(int cpu, unsigned int action) +{ + unsigned long flags; + + local_irq_save(flags); + + switch (action) { + case SMP_CALL_FUNCTION: + ipi_call_function(cpu); + break; + + case SMP_RESCHEDULE_YOURSELF: + ipi_resched(cpu); + break; + } + + local_irq_restore(flags); +} + +static void cmp_send_ipi_mask(cpumask_t mask, unsigned int action) +{ + unsigned int i; + + for_each_cpu_mask(i, mask) + cmp_send_ipi_single(i, action); +} + +static void cmp_init_secondary(void) +{ + struct cpuinfo_mips *c = ¤t_cpu_data; + + /* Assume GIC is present */ + change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 | + STATUSF_IP7); + + /* Enable per-cpu interrupts: platform specific */ + + c->core = (read_c0_ebase() >> 1) & 0xff; +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) + c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE; +#endif +#ifdef CONFIG_MIPS_MT_SMTC + c->tc_id = (read_c0_tcbind() >> TCBIND_CURTC_SHIFT) & TCBIND_CURTC; +#endif +} + +static void cmp_smp_finish(void) +{ + pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); + + /* CDFIXME: remove this? */ + write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ)); + +#ifdef CONFIG_MIPS_MT_FPAFF + /* If we have an FPU, enroll ourselves in the FPU-full mask */ + if (cpu_has_fpu) + cpu_set(smp_processor_id(), mt_fpu_cpumask); +#endif /* CONFIG_MIPS_MT_FPAFF */ + + local_irq_enable(); +} + +static void cmp_cpus_done(void) +{ + pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); +} + +/* + * Setup the PC, SP, and GP of a secondary processor and start it running + * smp_bootstrap is the place to resume from + * __KSTK_TOS(idle) is apparently the stack pointer + * (unsigned long)idle->thread_info the gp + */ +static void cmp_boot_secondary(int cpu, struct task_struct *idle) +{ + struct thread_info *gp = task_thread_info(idle); + unsigned long sp = __KSTK_TOS(idle); + unsigned long pc = (unsigned long)&smp_bootstrap; + unsigned long a0 = 0; + + pr_debug("SMPCMP: CPU%d: %s cpu %d\n", smp_processor_id(), + __func__, cpu); + +#if 0 + /* Needed? */ + flush_icache_range((unsigned long)gp, + (unsigned long)(gp + sizeof(struct thread_info))); +#endif + + amon_cpu_start(cpu, pc, sp, gp, a0); +} + +/* + * Common setup before any secondaries are started + */ +void __init cmp_smp_setup(void) +{ + int i; + int ncpu = 0; + + pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); + +#ifdef CONFIG_MIPS_MT_FPAFF + /* If we have an FPU, enroll ourselves in the FPU-full mask */ + if (cpu_has_fpu) + cpu_set(0, mt_fpu_cpumask); +#endif /* CONFIG_MIPS_MT_FPAFF */ + + for (i = 1; i < NR_CPUS; i++) { + if (amon_cpu_avail(i)) { + cpu_set(i, phys_cpu_present_map); + __cpu_number_map[i] = ++ncpu; + __cpu_logical_map[ncpu] = i; + } + } + + if (cpu_has_mipsmt) { + unsigned int nvpe, mvpconf0 = read_c0_mvpconf0(); + + nvpe = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; + smp_num_siblings = nvpe; + } + pr_info("Detected %i available secondary CPU(s)\n", ncpu); +} + +void __init cmp_prepare_cpus(unsigned int max_cpus) +{ + pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n", + smp_processor_id(), __func__, max_cpus); + + /* + * FIXME: some of these options are per-system, some per-core and + * some per-cpu + */ + mips_mt_set_cpuoptions(); +} + +struct plat_smp_ops cmp_smp_ops = { + .send_ipi_single = cmp_send_ipi_single, + .send_ipi_mask = cmp_send_ipi_mask, + .init_secondary = cmp_init_secondary, + .smp_finish = cmp_smp_finish, + .cpus_done = cmp_cpus_done, + .boot_secondary = cmp_boot_secondary, + .smp_setup = cmp_smp_setup, + .prepare_cpus = cmp_prepare_cpus, +}; diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 89e6f6aa516..87a1816c1f4 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c @@ -36,110 +36,7 @@ #include <asm/mipsmtregs.h> #include <asm/mips_mt.h> -#define MIPS_CPU_IPI_RESCHED_IRQ 0 -#define MIPS_CPU_IPI_CALL_IRQ 1 - -static int cpu_ipi_resched_irq, cpu_ipi_call_irq; - -#if 0 -static void dump_mtregisters(int vpe, int tc) -{ - printk("vpe %d tc %d\n", vpe, tc); - - settc(tc); - - printk(" c0 status 0x%lx\n", read_vpe_c0_status()); - printk(" vpecontrol 0x%lx\n", read_vpe_c0_vpecontrol()); - printk(" vpeconf0 0x%lx\n", read_vpe_c0_vpeconf0()); - printk(" tcstatus 0x%lx\n", read_tc_c0_tcstatus()); - printk(" tcrestart 0x%lx\n", read_tc_c0_tcrestart()); - printk(" tcbind 0x%lx\n", read_tc_c0_tcbind()); - printk(" tchalt 0x%lx\n", read_tc_c0_tchalt()); -} -#endif - -void __init sanitize_tlb_entries(void) -{ - int i, tlbsiz; - unsigned long mvpconf0, ncpu; - - if (!cpu_has_mipsmt) - return; - - /* Enable VPC */ - set_c0_mvpcontrol(MVPCONTROL_VPC); - - back_to_back_c0_hazard(); - - /* Disable TLB sharing */ - clear_c0_mvpcontrol(MVPCONTROL_STLB); - - mvpconf0 = read_c0_mvpconf0(); - - printk(KERN_INFO "MVPConf0 0x%lx TLBS %lx PTLBE %ld\n", mvpconf0, - (mvpconf0 & MVPCONF0_TLBS) >> MVPCONF0_TLBS_SHIFT, - (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT); - - tlbsiz = (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT; - ncpu = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; - - printk(" tlbsiz %d ncpu %ld\n", tlbsiz, ncpu); - - if (tlbsiz > 0) { - /* share them out across the vpe's */ - tlbsiz /= ncpu; - - printk(KERN_INFO "setting Config1.MMU_size to %d\n", tlbsiz); - - for (i = 0; i < ncpu; i++) { - settc(i); - - if (i == 0) - write_c0_config1((read_c0_config1() & ~(0x3f << 25)) | (tlbsiz << 25)); - else - write_vpe_c0_config1((read_vpe_c0_config1() & ~(0x3f << 25)) | - (tlbsiz << 25)); - } - } - - clear_c0_mvpcontrol(MVPCONTROL_VPC); -} - -static void ipi_resched_dispatch(void) -{ - do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); -} - -static void ipi_call_dispatch(void) -{ - do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); -} - -static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) -{ - return IRQ_HANDLED; -} - -static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) -{ - smp_call_function_interrupt(); - - return IRQ_HANDLED; -} - -static struct irqaction irq_resched = { - .handler = ipi_resched_interrupt, - .flags = IRQF_DISABLED|IRQF_PERCPU, - .name = "IPI_resched" -}; - -static struct irqaction irq_call = { - .handler = ipi_call_interrupt, - .flags = IRQF_DISABLED|IRQF_PERCPU, - .name = "IPI_call" -}; - -static void __init smp_copy_vpe_config(void) +static void __init smvp_copy_vpe_config(void) { write_vpe_c0_status( (read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0); @@ -156,7 +53,7 @@ static void __init smp_copy_vpe_config(void) write_vpe_c0_count(read_c0_count()); } -static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0, +static unsigned int __init smvp_vpe_init(unsigned int tc, unsigned int mvpconf0, unsigned int ncpu) { if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)) @@ -182,12 +79,12 @@ static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0, write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); if (tc != 0) - smp_copy_vpe_config(); + smvp_copy_vpe_config(); return ncpu; } -static void __init smp_tc_init(unsigned int tc, unsigned int mvpconf0) +static void __init smvp_tc_init(unsigned int tc, unsigned int mvpconf0) { unsigned long tmp; @@ -254,15 +151,20 @@ static void vsmp_send_ipi_mask(cpumask_t mask, unsigned int action) static void __cpuinit vsmp_init_secondary(void) { - /* Enable per-cpu interrupts */ + extern int gic_present; /* This is Malta specific: IPI,performance and timer inetrrupts */ - write_c0_status((read_c0_status() & ~ST0_IM ) | - (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP6 | STATUSF_IP7)); + if (gic_present) + change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | + STATUSF_IP6 | STATUSF_IP7); + else + change_c0_status(ST0_IM, STATUSF_IP0 | STATUSF_IP1 | + STATUSF_IP6 | STATUSF_IP7); } static void __cpuinit vsmp_smp_finish(void) { + /* CDFIXME: remove this? */ write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ)); #ifdef CONFIG_MIPS_MT_FPAFF @@ -323,7 +225,7 @@ static void __cpuinit vsmp_boot_secondary(int cpu, struct task_struct *idle) /* * Common setup before any secondaries are started * Make sure all CPU's are in a sensible state before we boot any of the - * secondarys + * secondaries */ static void __init vsmp_smp_setup(void) { @@ -356,8 +258,8 @@ static void __init vsmp_smp_setup(void) for (tc = 0; tc <= ntc; tc++) { settc(tc); - smp_tc_init(tc, mvpconf0); - ncpu = smp_vpe_init(tc, mvpconf0, ncpu); + smvp_tc_init(tc, mvpconf0); + ncpu = smvp_vpe_init(tc, mvpconf0, ncpu); } /* Release config state */ @@ -371,21 +273,6 @@ static void __init vsmp_smp_setup(void) static void __init vsmp_prepare_cpus(unsigned int max_cpus) { mips_mt_set_cpuoptions(); - - /* set up ipi interrupts */ - if (cpu_has_vint) { - set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch); - set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); - } - - cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ; - cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ; - - setup_irq(cpu_ipi_resched_irq, &irq_resched); - setup_irq(cpu_ipi_call_irq, &irq_call); - - set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq); - set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq); } struct plat_smp_ops vsmp_smp_ops = { diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 9d41dab90a8..33780cc61ce 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -35,6 +35,7 @@ #include <asm/atomic.h> #include <asm/cpu.h> #include <asm/processor.h> +#include <asm/r4k-timer.h> #include <asm/system.h> #include <asm/mmu_context.h> #include <asm/time.h> @@ -125,6 +126,8 @@ asmlinkage __cpuinit void start_secondary(void) cpu_set(cpu, cpu_callin_map); + synchronise_count_slave(); + cpu_idle(); } @@ -287,6 +290,7 @@ void smp_send_stop(void) void __init smp_cpus_done(unsigned int max_cpus) { mp_ops->cpus_done(); + synchronise_count_master(); } /* called from main before smp_init() */ diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index b42e71c7111..3e863186cd2 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -174,14 +174,6 @@ static int clock_hang_reported[NR_CPUS]; #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ -/* Initialize shared TLB - the should probably migrate to smtc_setup_cpus() */ - -void __init sanitize_tlb_entries(void) -{ - printk("Deprecated sanitize_tlb_entries() invoked\n"); -} - - /* * Configure shared TLB - VPC configuration bit must be set by caller */ @@ -339,7 +331,8 @@ static void smtc_tc_setup(int vpe, int tc, int cpu) /* In general, all TCs should have the same cpu_data indications */ memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips)); /* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */ - if (cpu_data[0].cputype == CPU_34K) + if (cpu_data[0].cputype == CPU_34K || + cpu_data[0].cputype == CPU_1004K) cpu_data[cpu].options &= ~MIPS_CPU_FPU; cpu_data[cpu].vpe_id = vpe; cpu_data[cpu].tc_id = tc; diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c new file mode 100644 index 00000000000..6ddb507a87e --- /dev/null +++ b/arch/mips/kernel/spram.c @@ -0,0 +1,221 @@ +/* + * MIPS SPRAM support + * + * 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. + * + * Copyright (C) 2007, 2008 MIPS Technologies, Inc. + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/ptrace.h> +#include <linux/stddef.h> + +#include <asm/cpu.h> +#include <asm/fpu.h> +#include <asm/mipsregs.h> +#include <asm/system.h> +#include <asm/r4kcache.h> +#include <asm/hazards.h> + +/* + * These definitions are correct for the 24K/34K/74K SPRAM sample + * implementation. The 4KS interpreted the tags differently... + */ +#define SPRAM_TAG0_ENABLE 0x00000080 +#define SPRAM_TAG0_PA_MASK 0xfffff000 +#define SPRAM_TAG1_SIZE_MASK 0xfffff000 + +#define SPRAM_TAG_STRIDE 8 + +#define ERRCTL_SPRAM (1 << 28) + +/* errctl access */ +#define read_c0_errctl(x) read_c0_ecc(x) +#define write_c0_errctl(x) write_c0_ecc(x) + +/* + * Different semantics to the set_c0_* function built by __BUILD_SET_C0 + */ +static __cpuinit unsigned int bis_c0_errctl(unsigned int set) +{ + unsigned int res; + res = read_c0_errctl(); + write_c0_errctl(res | set); + return res; +} + +static __cpuinit void ispram_store_tag(unsigned int offset, unsigned int data) +{ + unsigned int errctl; + + /* enable SPRAM tag access */ + errctl = bis_c0_errctl(ERRCTL_SPRAM); + ehb(); + + write_c0_taglo(data); + ehb(); + + cache_op(Index_Store_Tag_I, CKSEG0|offset); + ehb(); + + write_c0_errctl(errctl); + ehb(); +} + + +static __cpuinit unsigned int ispram_load_tag(unsigned int offset) +{ + unsigned int data; + unsigned int errctl; + + /* enable SPRAM tag access */ + errctl = bis_c0_errctl(ERRCTL_SPRAM); + ehb(); + cache_op(Index_Load_Tag_I, CKSEG0 | offset); + ehb(); + data = read_c0_taglo(); + ehb(); + write_c0_errctl(errctl); + ehb(); + + return data; +} + +static __cpuinit void dspram_store_tag(unsigned int offset, unsigned int data) +{ + unsigned int errctl; + + /* enable SPRAM tag access */ + errctl = bis_c0_errctl(ERRCTL_SPRAM); + ehb(); + write_c0_dtaglo(data); + ehb(); + cache_op(Index_Store_Tag_D, CKSEG0 | offset); + ehb(); + write_c0_errctl(errctl); + ehb(); +} + + +static __cpuinit unsigned int dspram_load_tag(unsigned int offset) +{ + unsigned int data; + unsigned int errctl; + + errctl = bis_c0_errctl(ERRCTL_SPRAM); + ehb(); + cache_op(Index_Load_Tag_D, CKSEG0 | offset); + ehb(); + data = read_c0_dtaglo(); + ehb(); + write_c0_errctl(errctl); + ehb(); + + return data; +} + +static __cpuinit void probe_spram(char *type, + unsigned int base, + unsigned int (*read)(unsigned int), + void (*write)(unsigned int, unsigned int)) +{ + unsigned int firstsize = 0, lastsize = 0; + unsigned int firstpa = 0, lastpa = 0, pa = 0; + unsigned int offset = 0; + unsigned int size, tag0, tag1; + unsigned int enabled; + int i; + + /* + * The limit is arbitrary but avoids the loop running away if + * the SPRAM tags are implemented differently + */ + + for (i = 0; i < 8; i++) { + tag0 = read(offset); + tag1 = read(offset+SPRAM_TAG_STRIDE); + pr_debug("DBG %s%d: tag0=%08x tag1=%08x\n", + type, i, tag0, tag1); + + size = tag1 & SPRAM_TAG1_SIZE_MASK; + + if (size == 0) + break; + + if (i != 0) { + /* tags may repeat... */ + if ((pa == firstpa && size == firstsize) || + (pa == lastpa && size == lastsize)) + break; + } + + /* Align base with size */ + base = (base + size - 1) & ~(size-1); + + /* reprogram the base address base address and enable */ + tag0 = (base & SPRAM_TAG0_PA_MASK) | SPRAM_TAG0_ENABLE; + write(offset, tag0); + + base += size; + + /* reread the tag */ + tag0 = read(offset); + pa = tag0 & SPRAM_TAG0_PA_MASK; + enabled = tag0 & SPRAM_TAG0_ENABLE; + + if (i == 0) { + firstpa = pa; + firstsize = size; + } + + lastpa = pa; + lastsize = size; + + if (strcmp(type, "DSPRAM") == 0) { + unsigned int *vp = (unsigned int *)(CKSEG1 | pa); + unsigned int v; +#define TDAT 0x5a5aa5a5 + vp[0] = TDAT; + vp[1] = ~TDAT; + + mb(); + + v = vp[0]; + if (v != TDAT) + printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n", + vp, TDAT, v); + v = vp[1]; + if (v != ~TDAT) + printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n", + vp+1, ~TDAT, v); + } + + pr_info("%s%d: PA=%08x,Size=%08x%s\n", + type, i, pa, size, enabled ? ",enabled" : ""); + offset += 2 * SPRAM_TAG_STRIDE; + } +} + +__cpuinit void spram_config(void) +{ + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int config0; + + switch (c->cputype) { + case CPU_24K: + case CPU_34K: + case CPU_74K: + config0 = read_c0_config(); + /* FIXME: addresses are Malta specific */ + if (config0 & (1<<24)) { + probe_spram("ISPRAM", 0x1c000000, + &ispram_load_tag, &ispram_store_tag); + } + if (config0 & (1<<23)) + probe_spram("DSPRAM", 0x1c100000, + &dspram_load_tag, &dspram_store_tag); + } +} diff --git a/arch/mips/kernel/sync-r4k.c b/arch/mips/kernel/sync-r4k.c new file mode 100644 index 00000000000..9021108eb9c --- /dev/null +++ b/arch/mips/kernel/sync-r4k.c @@ -0,0 +1,159 @@ +/* + * Count register synchronisation. + * + * All CPUs will have their count registers synchronised to the CPU0 expirelo + * value. This can cause a small timewarp for CPU0. All other CPU's should + * not have done anything significant (but they may have had interrupts + * enabled briefly - prom_smp_finish() should not be responsible for enabling + * interrupts...) + * + * FIXME: broken for SMTC + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/irqflags.h> +#include <linux/r4k-timer.h> + +#include <asm/atomic.h> +#include <asm/barrier.h> +#include <asm/cpumask.h> +#include <asm/mipsregs.h> + +static atomic_t __initdata count_start_flag = ATOMIC_INIT(0); +static atomic_t __initdata count_count_start = ATOMIC_INIT(0); +static atomic_t __initdata count_count_stop = ATOMIC_INIT(0); + +#define COUNTON 100 +#define NR_LOOPS 5 + +void __init synchronise_count_master(void) +{ + int i; + unsigned long flags; + unsigned int initcount; + int nslaves; + +#ifdef CONFIG_MIPS_MT_SMTC + /* + * SMTC needs to synchronise per VPE, not per CPU + * ignore for now + */ + return; +#endif + + pr_info("Checking COUNT synchronization across %u CPUs: ", + num_online_cpus()); + + local_irq_save(flags); + + /* + * Notify the slaves that it's time to start + */ + atomic_set(&count_start_flag, 1); + smp_wmb(); + + /* Count will be initialised to expirelo for all CPU's */ + initcount = expirelo; + + /* + * We loop a few times to get a primed instruction cache, + * then the last pass is more or less synchronised and + * the master and slaves each set their cycle counters to a known + * value all at once. This reduces the chance of having random offsets + * between the processors, and guarantees that the maximum + * delay between the cycle counters is never bigger than + * the latency of information-passing (cachelines) between + * two CPUs. + */ + + nslaves = num_online_cpus()-1; + for (i = 0; i < NR_LOOPS; i++) { + /* slaves loop on '!= ncpus' */ + while (atomic_read(&count_count_start) != nslaves) + mb(); + atomic_set(&count_count_stop, 0); + smp_wmb(); + + /* this lets the slaves write their count register */ + atomic_inc(&count_count_start); + + /* + * Everyone initialises count in the last loop: + */ + if (i == NR_LOOPS-1) + write_c0_count(initcount); + + /* + * Wait for all slaves to leave the synchronization point: + */ + while (atomic_read(&count_count_stop) != nslaves) + mb(); + atomic_set(&count_count_start, 0); + smp_wmb(); + atomic_inc(&count_count_stop); + } + /* Arrange for an interrupt in a short while */ + write_c0_compare(read_c0_count() + COUNTON); + + local_irq_restore(flags); + + /* + * i386 code reported the skew here, but the + * count registers were almost certainly out of sync + * so no point in alarming people + */ + printk("done.\n"); +} + +void __init synchronise_count_slave(void) +{ + int i; + unsigned long flags; + unsigned int initcount; + int ncpus; + +#ifdef CONFIG_MIPS_MT_SMTC + /* + * SMTC needs to synchronise per VPE, not per CPU + * ignore for now + */ + return; +#endif + + local_irq_save(flags); + + /* + * Not every cpu is online at the time this gets called, + * so we first wait for the master to say everyone is ready + */ + + while (!atomic_read(&count_start_flag)) + mb(); + + /* Count will be initialised to expirelo for all CPU's */ + initcount = expirelo; + + ncpus = num_online_cpus(); + for (i = 0; i < NR_LOOPS; i++) { + atomic_inc(&count_count_start); + while (atomic_read(&count_count_start) != ncpus) + mb(); + + /* + * Everyone initialises count in the last loop: + */ + if (i == NR_LOOPS-1) + write_c0_count(initcount); + + atomic_inc(&count_count_stop); + while (atomic_read(&count_count_stop) != ncpus) + mb(); + } + /* Arrange for an interrupt in a short while */ + write_c0_compare(read_c0_count() + COUNTON); + + local_irq_restore(flags); +} +#undef NR_LOOPS +#endif diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index b45a7093ca2..1f467d53464 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -38,7 +38,6 @@ int __weak rtc_mips_set_time(unsigned long sec) { return 0; } -EXPORT_SYMBOL(rtc_mips_set_time); int __weak rtc_mips_set_mmss(unsigned long nowtime) { @@ -50,13 +49,11 @@ int update_persistent_clock(struct timespec now) return rtc_mips_set_mmss(now.tv_sec); } -int null_perf_irq(void) +static int null_perf_irq(void) { return 0; } -EXPORT_SYMBOL(null_perf_irq); - int (*perf_irq)(void) = null_perf_irq; EXPORT_SYMBOL(perf_irq); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 984c0d0a7b4..cb8b0e2c795 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -22,6 +22,7 @@ #include <linux/kallsyms.h> #include <linux/bootmem.h> #include <linux/interrupt.h> +#include <linux/ptrace.h> #include <asm/bootinfo.h> #include <asm/branch.h> @@ -80,19 +81,22 @@ void (*board_bind_eic_interrupt)(int irq, int regset); static void show_raw_backtrace(unsigned long reg29) { - unsigned long *sp = (unsigned long *)reg29; + unsigned long *sp = (unsigned long *)(reg29 & ~3); unsigned long addr; printk("Call Trace:"); #ifdef CONFIG_KALLSYMS printk("\n"); #endif - while (!kstack_end(sp)) { - addr = *sp++; - if (__kernel_text_address(addr)) - print_ip_sym(addr); +#define IS_KVA01(a) ((((unsigned int)a) & 0xc0000000) == 0x80000000) + if (IS_KVA01(sp)) { + while (!kstack_end(sp)) { + addr = *sp++; + if (__kernel_text_address(addr)) + print_ip_sym(addr); + } + printk("\n"); } - printk("\n"); } #ifdef CONFIG_KALLSYMS @@ -192,16 +196,19 @@ EXPORT_SYMBOL(dump_stack); static void show_code(unsigned int __user *pc) { long i; + unsigned short __user *pc16 = NULL; printk("\nCode:"); + if ((unsigned long)pc & 1) + pc16 = (unsigned short __user *)((unsigned long)pc & ~1); for(i = -3 ; i < 6 ; i++) { unsigned int insn; - if (__get_user(insn, pc + i)) { + if (pc16 ? __get_user(insn, pc16 + i) : __get_user(insn, pc + i)) { printk(" (Bad address in epc)\n"); break; } - printk("%c%08x%c", (i?' ':'<'), insn, (i?' ':'>')); + printk("%c%0*x%c", (i?' ':'<'), pc16 ? 4 : 8, insn, (i?' ':'>')); } } @@ -311,10 +318,21 @@ void show_regs(struct pt_regs *regs) void show_registers(const struct pt_regs *regs) { + const int field = 2 * sizeof(unsigned long); + __show_regs(regs); print_modules(); - printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", - current->comm, task_pid_nr(current), current_thread_info(), current); + printk("Process %s (pid: %d, threadinfo=%p, task=%p, tls=%0*lx)\n", + current->comm, current->pid, current_thread_info(), current, + field, current_thread_info()->tp_value); + if (cpu_has_userlocal) { + unsigned long tls; + + tls = read_c0_userlocal(); + if (tls != current_thread_info()->tp_value) + printk("*HwTLS: %0*lx\n", field, tls); + } + show_stacktrace(current, regs); show_code((unsigned int __user *) regs->cp0_epc); printk("\n"); @@ -657,35 +675,24 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) 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; @@ -695,12 +702,34 @@ asmlinkage void do_bp(struct pt_regs *regs) 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: @@ -710,7 +739,6 @@ out_sigsegv: 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; @@ -719,32 +747,7 @@ asmlinkage void do_tr(struct pt_regs *regs) 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: @@ -985,6 +988,21 @@ asmlinkage void do_reserved(struct pt_regs *regs) (regs->cp0_cause & 0x7f) >> 2); } +static int __initdata l1parity = 1; +static int __init nol1parity(char *s) +{ + l1parity = 0; + return 1; +} +__setup("nol1par", nol1parity); +static int __initdata l2parity = 1; +static int __init nol2parity(char *s) +{ + l2parity = 0; + return 1; +} +__setup("nol2par", nol2parity); + /* * Some MIPS CPUs can enable/disable for cache parity detection, but do * it different ways. @@ -994,6 +1012,62 @@ static inline void parity_protection_init(void) switch (current_cpu_type()) { case CPU_24K: case CPU_34K: + case CPU_74K: + case CPU_1004K: + { +#define ERRCTL_PE 0x80000000 +#define ERRCTL_L2P 0x00800000 + unsigned long errctl; + unsigned int l1parity_present, l2parity_present; + + errctl = read_c0_ecc(); + errctl &= ~(ERRCTL_PE|ERRCTL_L2P); + + /* probe L1 parity support */ + write_c0_ecc(errctl | ERRCTL_PE); + back_to_back_c0_hazard(); + l1parity_present = (read_c0_ecc() & ERRCTL_PE); + + /* probe L2 parity support */ + write_c0_ecc(errctl|ERRCTL_L2P); + back_to_back_c0_hazard(); + l2parity_present = (read_c0_ecc() & ERRCTL_L2P); + + if (l1parity_present && l2parity_present) { + if (l1parity) + errctl |= ERRCTL_PE; + if (l1parity ^ l2parity) + errctl |= ERRCTL_L2P; + } else if (l1parity_present) { + if (l1parity) + errctl |= ERRCTL_PE; + } else if (l2parity_present) { + if (l2parity) + errctl |= ERRCTL_L2P; + } else { + /* No parity available */ + } + + printk(KERN_INFO "Writing ErrCtl register=%08lx\n", errctl); + + write_c0_ecc(errctl); + back_to_back_c0_hazard(); + errctl = read_c0_ecc(); + printk(KERN_INFO "Readback ErrCtl register=%08lx\n", errctl); + + if (l1parity_present) + printk(KERN_INFO "Cache parity protection %sabled\n", + (errctl & ERRCTL_PE) ? "en" : "dis"); + + if (l2parity_present) { + if (l1parity_present && l1parity) + errctl ^= ERRCTL_L2P; + printk(KERN_INFO "L2 cache parity protection %sabled\n", + (errctl & ERRCTL_L2P) ? "en" : "dis"); + } + } + break; + case CPU_5KC: write_c0_ecc(0x80000000); back_to_back_c0_hazard(); @@ -1306,6 +1380,17 @@ int cp0_compare_irq; int cp0_perfcount_irq; EXPORT_SYMBOL_GPL(cp0_perfcount_irq); +static int __cpuinitdata noulri; + +static int __init ulri_disable(char *s) +{ + pr_info("Disabling ulri\n"); + noulri = 1; + + return 1; +} +__setup("noulri", ulri_disable); + void __cpuinit per_cpu_trap_init(void) { unsigned int cpu = smp_processor_id(); @@ -1342,16 +1427,14 @@ void __cpuinit per_cpu_trap_init(void) change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, status_set); -#ifdef CONFIG_CPU_MIPSR2 if (cpu_has_mips_r2) { unsigned int enable = 0x0000000f; - if (cpu_has_userlocal) + if (!noulri && cpu_has_userlocal) enable |= (1 << 29); write_c0_hwrena(enable); } -#endif #ifdef CONFIG_MIPS_MT_SMTC if (!secondaryTC) { diff --git a/arch/mips/math-emu/ieee754dp.h b/arch/mips/math-emu/ieee754dp.h index 8977eb585a3..76278653844 100644 --- a/arch/mips/math-emu/ieee754dp.h +++ b/arch/mips/math-emu/ieee754dp.h @@ -46,7 +46,7 @@ #define DPDNORMX DPDNORMx(xm, xe) #define DPDNORMY DPDNORMx(ym, ye) -static __inline ieee754dp builddp(int s, int bx, u64 m) +static inline ieee754dp builddp(int s, int bx, u64 m) { ieee754dp r; diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h index 9917c1e4d94..d9e3586b5bc 100644 --- a/arch/mips/math-emu/ieee754sp.h +++ b/arch/mips/math-emu/ieee754sp.h @@ -51,7 +51,7 @@ #define SPDNORMX SPDNORMx(xm, xe) #define SPDNORMY SPDNORMx(ym, ye) -static __inline ieee754sp buildsp(int s, int bx, unsigned m) +static inline ieee754sp buildsp(int s, int bx, unsigned m) { ieee754sp r; diff --git a/arch/mips/mips-boards/generic/Makefile b/arch/mips/mips-boards/generic/Makefile index b31d8dfed1b..f7f87fc09d1 100644 --- a/arch/mips/mips-boards/generic/Makefile +++ b/arch/mips/mips-boards/generic/Makefile @@ -20,6 +20,7 @@ obj-y := reset.o display.o init.o memory.o \ cmdline.o time.o +obj-y += amon.o obj-$(CONFIG_EARLY_PRINTK) += console.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/mips/mips-boards/generic/amon.c b/arch/mips/mips-boards/generic/amon.c new file mode 100644 index 00000000000..b7633fda418 --- /dev/null +++ b/arch/mips/mips-boards/generic/amon.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2007 MIPS Technologies, Inc. + * All rights reserved. + + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * Arbitrary Monitor interface + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/smp.h> + +#include <asm-mips/addrspace.h> +#include <asm-mips/mips-boards/launch.h> +#include <asm-mips/mipsmtregs.h> + +int amon_cpu_avail(int cpu) +{ + struct cpulaunch *launch = (struct cpulaunch *)KSEG0ADDR(CPULAUNCH); + + if (cpu < 0 || cpu >= NCPULAUNCH) { + pr_debug("avail: cpu%d is out of range\n", cpu); + return 0; + } + + launch += cpu; + if (!(launch->flags & LAUNCH_FREADY)) { + pr_debug("avail: cpu%d is not ready\n", cpu); + return 0; + } + if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) { + pr_debug("avail: too late.. cpu%d is already gone\n", cpu); + return 0; + } + + return 1; +} + +void amon_cpu_start(int cpu, + unsigned long pc, unsigned long sp, + unsigned long gp, unsigned long a0) +{ + volatile struct cpulaunch *launch = + (struct cpulaunch *)KSEG0ADDR(CPULAUNCH); + + if (!amon_cpu_avail(cpu)) + return; + if (cpu == smp_processor_id()) { + pr_debug("launch: I am cpu%d!\n", cpu); + return; + } + launch += cpu; + + pr_debug("launch: starting cpu%d\n", cpu); + + launch->pc = pc; + launch->gp = gp; + launch->sp = sp; + launch->a0 = a0; + + /* Make sure target sees parameters before the go bit */ + smp_mb(); + + launch->flags |= LAUNCH_FGO; + while ((launch->flags & LAUNCH_FGONE) == 0) + ; + pr_debug("launch: cpu%d gone!\n", cpu); +} diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c index 1695dca5506..83b9dc73920 100644 --- a/arch/mips/mips-boards/generic/init.c +++ b/arch/mips/mips-boards/generic/init.c @@ -226,7 +226,7 @@ void __init kgdb_config(void) } #endif -void __init mips_nmi_setup(void) +static void __init mips_nmi_setup(void) { void *base; extern char except_vec_nmi; @@ -238,7 +238,7 @@ void __init mips_nmi_setup(void) flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); } -void __init mips_ejtag_setup(void) +static void __init mips_ejtag_setup(void) { void *base; extern char except_vec_ejtag_debug; @@ -295,15 +295,21 @@ void __init prom_init(void) break; case MIPS_REVISION_CORID_CORE_MSC: case MIPS_REVISION_CORID_CORE_FPGA2: - case MIPS_REVISION_CORID_CORE_FPGA3: - case MIPS_REVISION_CORID_CORE_FPGA4: case MIPS_REVISION_CORID_CORE_24K: - case MIPS_REVISION_CORID_CORE_EMUL_MSC: + /* + * SOCit/ROCit support is essentially identical + * but make an attempt to distinguish them + */ mips_revision_sconid = MIPS_REVISION_SCON_SOCIT; break; + case MIPS_REVISION_CORID_CORE_FPGA3: + case MIPS_REVISION_CORID_CORE_FPGA4: + case MIPS_REVISION_CORID_CORE_FPGA5: + case MIPS_REVISION_CORID_CORE_EMUL_MSC: default: - mips_display_message("CC Error"); - while (1); /* We die here... */ + /* See above */ + mips_revision_sconid = MIPS_REVISION_SCON_ROCIT; + break; } } @@ -418,6 +424,9 @@ void __init prom_init(void) #ifdef CONFIG_SERIAL_8250_CONSOLE console_config(); #endif +#ifdef CONFIG_MIPS_CMP + register_smp_ops(&cmp_smp_ops); +#endif #ifdef CONFIG_MIPS_MT_SMP register_smp_ops(&vsmp_smp_ops); #endif diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c index dc272c18823..5e443bba566 100644 --- a/arch/mips/mips-boards/generic/memory.c +++ b/arch/mips/mips-boards/generic/memory.c @@ -37,7 +37,7 @@ enum yamon_memtypes { yamon_prom, yamon_free, }; -struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; +static struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; #ifdef DEBUG static char *mtypes[3] = { @@ -50,7 +50,7 @@ static char *mtypes[3] = { /* determined physical memory size, not overridden by command line args */ unsigned long physical_memsize = 0L; -struct prom_pmemblock * __init prom_getmdesc(void) +static struct prom_pmemblock * __init prom_getmdesc(void) { char *memsize_str; unsigned int memsize; diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index b50e0fc406a..008fd82b584 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -55,16 +55,36 @@ unsigned long cpu_khz; static int mips_cpu_timer_irq; +static int mips_cpu_perf_irq; extern int cp0_perfcount_irq; +DEFINE_PER_CPU(unsigned int, tickcount); +#define tickcount_this_cpu __get_cpu_var(tickcount) +static unsigned long ledbitmask; + static void mips_timer_dispatch(void) { +#if defined(CONFIG_MIPS_MALTA) || defined(CONFIG_MIPS_ATLAS) + /* + * Yes, this is very tacky, won't work as expected with SMTC and + * dyntick will break it, + * but it gives me a nice warm feeling during debug + */ +#define LEDBAR 0xbf000408 + if (tickcount_this_cpu++ >= HZ) { + tickcount_this_cpu = 0; + change_bit(smp_processor_id(), &ledbitmask); + smp_wmb(); /* Make sure every one else sees the change */ + /* This will pick up any recent changes made by other CPU's */ + *(unsigned int *)LEDBAR = ledbitmask; + } +#endif do_IRQ(mips_cpu_timer_irq); } static void mips_perf_dispatch(void) { - do_IRQ(cp0_perfcount_irq); + do_IRQ(mips_cpu_perf_irq); } /* @@ -127,21 +147,20 @@ unsigned long read_persistent_clock(void) return mc146818_get_cmos_time(); } -void __init plat_perf_setup(void) +static void __init plat_perf_setup(void) { - cp0_perfcount_irq = -1; - #ifdef MSC01E_INT_BASE if (cpu_has_veic) { set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch); - cp0_perfcount_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; + mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; } else #endif if (cp0_perfcount_irq >= 0) { if (cpu_has_vint) set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); + mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; #ifdef CONFIG_SMP - set_irq_handler(cp0_perfcount_irq, handle_percpu_irq); + set_irq_handler(mips_cpu_perf_irq, handle_percpu_irq); #endif } } diff --git a/arch/mips/mips-boards/malta/Makefile b/arch/mips/mips-boards/malta/Makefile index 931ca4600a6..8dc6e2ac4c0 100644 --- a/arch/mips/mips-boards/malta/Makefile +++ b/arch/mips/mips-boards/malta/Makefile @@ -22,6 +22,7 @@ obj-y := malta_int.o malta_platform.o malta_setup.o obj-$(CONFIG_MTD) += malta_mtd.o +# FIXME FIXME FIXME obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o EXTRA_CFLAGS += -Werror diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c index dbe60eb55e2..8c495104b32 100644 --- a/arch/mips/mips-boards/malta/malta_int.c +++ b/arch/mips/mips-boards/malta/malta_int.c @@ -31,6 +31,7 @@ #include <linux/kernel.h> #include <linux/random.h> +#include <asm/traps.h> #include <asm/i8259.h> #include <asm/irq_cpu.h> #include <asm/irq_regs.h> @@ -41,6 +42,14 @@ #include <asm/mips-boards/generic.h> #include <asm/mips-boards/msc01_pci.h> #include <asm/msc01_ic.h> +#include <asm/gic.h> +#include <asm/gcmpregs.h> + +int gcmp_present = -1; +int gic_present; +static unsigned long _msc01_biu_base; +static unsigned long _gcmp_base; +static unsigned int ipi_map[NR_CPUS]; static DEFINE_SPINLOCK(mips_irq_lock); @@ -121,6 +130,17 @@ static void malta_hw0_irqdispatch(void) do_IRQ(MALTA_INT_BASE + irq); } +static void malta_ipi_irqdispatch(void) +{ + int irq; + + irq = gic_get_int(); + if (irq < 0) + return; /* interrupt has already been cleared */ + + do_IRQ(MIPS_GIC_IRQ_BASE + irq); +} + static void corehi_irqdispatch(void) { unsigned int intedge, intsteer, pcicmd, pcibadaddr; @@ -257,12 +277,61 @@ asmlinkage void plat_irq_dispatch(void) if (irq == MIPSCPU_INT_I8259A) malta_hw0_irqdispatch(); + else if (gic_present && ((1 << irq) & ipi_map[smp_processor_id()])) + malta_ipi_irqdispatch(); else if (irq >= 0) do_IRQ(MIPS_CPU_IRQ_BASE + irq); else spurious_interrupt(); } +#ifdef CONFIG_MIPS_MT_SMP + + +#define GIC_MIPS_CPU_IPI_RESCHED_IRQ 3 +#define GIC_MIPS_CPU_IPI_CALL_IRQ 4 + +#define MIPS_CPU_IPI_RESCHED_IRQ 0 /* SW int 0 for resched */ +#define C_RESCHED C_SW0 +#define MIPS_CPU_IPI_CALL_IRQ 1 /* SW int 1 for resched */ +#define C_CALL C_SW1 +static int cpu_ipi_resched_irq, cpu_ipi_call_irq; + +static void ipi_resched_dispatch(void) +{ + do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); +} + +static void ipi_call_dispatch(void) +{ + do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); +} + +static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) +{ + return IRQ_HANDLED; +} + +static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) +{ + smp_call_function_interrupt(); + + return IRQ_HANDLED; +} + +static struct irqaction irq_resched = { + .handler = ipi_resched_interrupt, + .flags = IRQF_DISABLED|IRQF_PERCPU, + .name = "IPI_resched" +}; + +static struct irqaction irq_call = { + .handler = ipi_call_interrupt, + .flags = IRQF_DISABLED|IRQF_PERCPU, + .name = "IPI_call" +}; +#endif /* CONFIG_MIPS_MT_SMP */ + static struct irqaction i8259irq = { .handler = no_action, .name = "XT-PIC cascade" @@ -273,13 +342,13 @@ static struct irqaction corehi_irqaction = { .name = "CoreHi" }; -msc_irqmap_t __initdata msc_irqmap[] = { +static msc_irqmap_t __initdata msc_irqmap[] = { {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, }; -int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap); +static int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap); -msc_irqmap_t __initdata msc_eicirqmap[] = { +static msc_irqmap_t __initdata msc_eicirqmap[] = { {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0}, {MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0}, @@ -291,15 +360,90 @@ msc_irqmap_t __initdata msc_eicirqmap[] = { {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} }; -int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap); + +static int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap); + +/* + * This GIC specific tabular array defines the association between External + * Interrupts and CPUs/Core Interrupts. The nature of the External + * Interrupts is also defined here - polarity/trigger. + */ +static struct gic_intr_map gic_intr_map[] = { + { GIC_EXT_INTR(0), X, X, X, X, 0 }, + { GIC_EXT_INTR(1), X, X, X, X, 0 }, + { GIC_EXT_INTR(2), X, X, X, X, 0 }, + { GIC_EXT_INTR(3), 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, + { GIC_EXT_INTR(4), 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, + { GIC_EXT_INTR(5), 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, + { GIC_EXT_INTR(6), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, + { GIC_EXT_INTR(7), 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, + { GIC_EXT_INTR(8), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, + { GIC_EXT_INTR(9), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, + { GIC_EXT_INTR(10), X, X, X, X, 0 }, + { GIC_EXT_INTR(11), X, X, X, X, 0 }, + { GIC_EXT_INTR(12), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, + { GIC_EXT_INTR(13), 0, GIC_MAP_TO_NMI_MSK, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, + { GIC_EXT_INTR(14), 0, GIC_MAP_TO_NMI_MSK, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, + { GIC_EXT_INTR(15), X, X, X, X, 0 }, + { GIC_EXT_INTR(16), 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, + { GIC_EXT_INTR(17), 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, + { GIC_EXT_INTR(18), 1, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, + { GIC_EXT_INTR(19), 1, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, + { GIC_EXT_INTR(20), 2, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, + { GIC_EXT_INTR(21), 2, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, + { GIC_EXT_INTR(22), 3, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, + { GIC_EXT_INTR(23), 3, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, +}; + +/* + * GCMP needs to be detected before any SMP initialisation + */ +int __init gcmp_probe(unsigned long addr, unsigned long size) +{ + if (gcmp_present >= 0) + return gcmp_present; + + _gcmp_base = (unsigned long) ioremap_nocache(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ); + _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ); + gcmp_present = (GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) == GCMP_BASE_ADDR; + + if (gcmp_present) + printk(KERN_DEBUG "GCMP present\n"); + return gcmp_present; +} + +void __init fill_ipi_map(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(gic_intr_map); i++) { + if (gic_intr_map[i].ipiflag && (gic_intr_map[i].cpunum != X)) + ipi_map[gic_intr_map[i].cpunum] |= + (1 << (gic_intr_map[i].pin + 2)); + } +} void __init arch_init_irq(void) { + int gic_present, gcmp_present; + init_i8259_irqs(); if (!cpu_has_veic) mips_cpu_irq_init(); + gcmp_present = gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ); + if (gcmp_present) { + GCMPGCB(GICBA) = GIC_BASE_ADDR | GCMP_GCB_GICBA_EN_MSK; + gic_present = 1; + } else { + _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ); + gic_present = (REG(_msc01_biu_base, MSC01_SC_CFG) & + MSC01_SC_CFG_GICPRES_MSK) >> MSC01_SC_CFG_GICPRES_SHF; + } + if (gic_present) + printk(KERN_DEBUG "GIC present\n"); + switch (mips_revision_sconid) { case MIPS_REVISION_SCON_SOCIT: case MIPS_REVISION_SCON_ROCIT: @@ -360,4 +504,206 @@ void __init arch_init_irq(void) setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); } + +#if defined(CONFIG_MIPS_MT_SMP) + if (gic_present) { + /* FIXME */ + int i; + struct { + unsigned int resched; + unsigned int call; + } ipiirq[] = { + { + .resched = GIC_IPI_EXT_INTR_RESCHED_VPE0, + .call = GIC_IPI_EXT_INTR_CALLFNC_VPE0}, + { + .resched = GIC_IPI_EXT_INTR_RESCHED_VPE1, + .call = GIC_IPI_EXT_INTR_CALLFNC_VPE1 + }, { + .resched = GIC_IPI_EXT_INTR_RESCHED_VPE2, + .call = GIC_IPI_EXT_INTR_CALLFNC_VPE2 + }, { + .resched = GIC_IPI_EXT_INTR_RESCHED_VPE3, + .call = GIC_IPI_EXT_INTR_CALLFNC_VPE3 + } + }; +#define NIPI (sizeof(ipiirq)/sizeof(ipiirq[0])) + fill_ipi_map(); + gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE); + if (!gcmp_present) { + /* Enable the GIC */ + i = REG(_msc01_biu_base, MSC01_SC_CFG); + REG(_msc01_biu_base, MSC01_SC_CFG) = + (i | (0x1 << MSC01_SC_CFG_GICENA_SHF)); + pr_debug("GIC Enabled\n"); + } + + /* set up ipi interrupts */ + if (cpu_has_vint) { + set_vi_handler(MIPSCPU_INT_IPI0, malta_ipi_irqdispatch); + set_vi_handler(MIPSCPU_INT_IPI1, malta_ipi_irqdispatch); + } + /* Argh.. this really needs sorting out.. */ + printk("CPU%d: status register was %08x\n", smp_processor_id(), read_c0_status()); + write_c0_status(read_c0_status() | STATUSF_IP3 | STATUSF_IP4); + printk("CPU%d: status register now %08x\n", smp_processor_id(), read_c0_status()); + write_c0_status(0x1100dc00); + printk("CPU%d: status register frc %08x\n", smp_processor_id(), read_c0_status()); + for (i = 0; i < NIPI; i++) { + setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, &irq_resched); + setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].call, &irq_call); + + set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, handle_percpu_irq); + set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].call, handle_percpu_irq); + } + } else { + /* set up ipi interrupts */ + if (cpu_has_veic) { + set_vi_handler (MSC01E_INT_SW0, ipi_resched_dispatch); + set_vi_handler (MSC01E_INT_SW1, ipi_call_dispatch); + cpu_ipi_resched_irq = MSC01E_INT_SW0; + cpu_ipi_call_irq = MSC01E_INT_SW1; + } else { + if (cpu_has_vint) { + set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch); + set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); + } + cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ; + cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ; + } + + setup_irq(cpu_ipi_resched_irq, &irq_resched); + setup_irq(cpu_ipi_call_irq, &irq_call); + + set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq); + set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq); + } +#endif +} + +void malta_be_init(void) +{ + if (gcmp_present) { + /* Could change CM error mask register */ + } +} + + +static char *tr[8] = { + "mem", "gcr", "gic", "mmio", + "0x04", "0x05", "0x06", "0x07" +}; + +static char *mcmd[32] = { + [0x00] = "0x00", + [0x01] = "Legacy Write", + [0x02] = "Legacy Read", + [0x03] = "0x03", + [0x04] = "0x04", + [0x05] = "0x05", + [0x06] = "0x06", + [0x07] = "0x07", + [0x08] = "Coherent Read Own", + [0x09] = "Coherent Read Share", + [0x0a] = "Coherent Read Discard", + [0x0b] = "Coherent Ready Share Always", + [0x0c] = "Coherent Upgrade", + [0x0d] = "Coherent Writeback", + [0x0e] = "0x0e", + [0x0f] = "0x0f", + [0x10] = "Coherent Copyback", + [0x11] = "Coherent Copyback Invalidate", + [0x12] = "Coherent Invalidate", + [0x13] = "Coherent Write Invalidate", + [0x14] = "Coherent Completion Sync", + [0x15] = "0x15", + [0x16] = "0x16", + [0x17] = "0x17", + [0x18] = "0x18", + [0x19] = "0x19", + [0x1a] = "0x1a", + [0x1b] = "0x1b", + [0x1c] = "0x1c", + [0x1d] = "0x1d", + [0x1e] = "0x1e", + [0x1f] = "0x1f" +}; + +static char *core[8] = { + "Invalid/OK", "Invalid/Data", + "Shared/OK", "Shared/Data", + "Modified/OK", "Modified/Data", + "Exclusive/OK", "Exclusive/Data" +}; + +static char *causes[32] = { + "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR", + "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07", + "0x08", "0x09", "0x0a", "0x0b", + "0x0c", "0x0d", "0x0e", "0x0f", + "0x10", "0x11", "0x12", "0x13", + "0x14", "0x15", "0x16", "INTVN_WR_ERR", + "INTVN_RD_ERR", "0x19", "0x1a", "0x1b", + "0x1c", "0x1d", "0x1e", "0x1f" +}; + +int malta_be_handler(struct pt_regs *regs, int is_fixup) +{ + /* This duplicates the handling in do_be which seems wrong */ + int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL; + + if (gcmp_present) { + unsigned long cm_error = GCMPGCB(GCMEC); + unsigned long cm_addr = GCMPGCB(GCMEA); + unsigned long cm_other = GCMPGCB(GCMEO); + unsigned long cause, ocause; + char buf[256]; + + cause = (cm_error & GCMP_GCB_GMEC_ERROR_TYPE_MSK); + if (cause != 0) { + cause >>= GCMP_GCB_GMEC_ERROR_TYPE_SHF; + if (cause < 16) { + unsigned long cca_bits = (cm_error >> 15) & 7; + unsigned long tr_bits = (cm_error >> 12) & 7; + unsigned long mcmd_bits = (cm_error >> 7) & 0x1f; + unsigned long stag_bits = (cm_error >> 3) & 15; + unsigned long sport_bits = (cm_error >> 0) & 7; + + snprintf(buf, sizeof(buf), + "CCA=%lu TR=%s MCmd=%s STag=%lu " + "SPort=%lu\n", + cca_bits, tr[tr_bits], mcmd[mcmd_bits], + stag_bits, sport_bits); + } else { + /* glob state & sresp together */ + unsigned long c3_bits = (cm_error >> 18) & 7; + unsigned long c2_bits = (cm_error >> 15) & 7; + unsigned long c1_bits = (cm_error >> 12) & 7; + unsigned long c0_bits = (cm_error >> 9) & 7; + unsigned long sc_bit = (cm_error >> 8) & 1; + unsigned long mcmd_bits = (cm_error >> 3) & 0x1f; + unsigned long sport_bits = (cm_error >> 0) & 7; + snprintf(buf, sizeof(buf), + "C3=%s C2=%s C1=%s C0=%s SC=%s " + "MCmd=%s SPort=%lu\n", + core[c3_bits], core[c2_bits], + core[c1_bits], core[c0_bits], + sc_bit ? "True" : "False", + mcmd[mcmd_bits], sport_bits); + } + + ocause = (cm_other & GCMP_GCB_GMEO_ERROR_2ND_MSK) >> + GCMP_GCB_GMEO_ERROR_2ND_SHF; + + printk("CM_ERROR=%08lx %s <%s>\n", cm_error, + causes[cause], buf); + printk("CM_ADDR =%08lx\n", cm_addr); + printk("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]); + + /* reprime cause register */ + GCMPGCB(GCMEC) = 0; + } + } + + return retval; } diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c index 2cd8f5734b3..e7cad54936c 100644 --- a/arch/mips/mips-boards/malta/malta_setup.c +++ b/arch/mips/mips-boards/malta/malta_setup.c @@ -1,7 +1,7 @@ /* * Carsten Langgaard, carstenl@mips.com * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * Copyright (C) Dmitri Vorobiev + * Copyright (C) 2008 Dmitri Vorobiev * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as @@ -36,7 +36,10 @@ #include <linux/console.h> #endif -struct resource standard_io_resources[] = { +extern void malta_be_init(void); +extern int malta_be_handler(struct pt_regs *regs, int is_fixup); + +static struct resource standard_io_resources[] = { { .name = "dma1", .start = 0x00, @@ -220,4 +223,7 @@ void __init plat_mem_setup(void) screen_info_setup(); #endif mips_reboot_setup(); + + board_be_init = malta_be_init; + board_be_handler = malta_be_handler; } diff --git a/arch/mips/mipssim/sim_setup.c b/arch/mips/mipssim/sim_setup.c index d49fe73426b..7c7148ef264 100644 --- a/arch/mips/mipssim/sim_setup.c +++ b/arch/mips/mipssim/sim_setup.c @@ -39,9 +39,6 @@ static void __init serial_init(void); unsigned int _isbonito = 0; -extern void __init sanitize_tlb_entries(void); - - const char *get_system_type(void) { return "MIPSsim"; @@ -55,9 +52,6 @@ void __init plat_mem_setup(void) pr_info("Linux started...\n"); -#ifdef CONFIG_MIPS_MT_SMP - sanitize_tlb_entries(); -#endif } extern struct plat_smp_ops ssmtc_smp_ops; diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index c6f832e0f41..48731020ca0 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -4,30 +4,29 @@ obj-y += cache.o dma-default.o extable.o fault.o \ init.o pgtable.o tlbex.o tlbex-fault.o \ - uasm.o + uasm.o page.o obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o obj-$(CONFIG_64BIT) += pgtable-64.o obj-$(CONFIG_HIGHMEM) += highmem.o -obj-$(CONFIG_CPU_LOONGSON2) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_MIPS32) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_MIPS64) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_NEVADA) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_R10000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_R3000) += c-r3k.o tlb-r3k.o pg-r4k.o -obj-$(CONFIG_CPU_R4300) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_R4X00) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_R5000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_R5432) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_R8000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r8k.o -obj-$(CONFIG_CPU_RM7000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_RM9000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_SB1) += c-r4k.o cerr-sb1.o cex-sb1.o pg-sb1.o \ - tlb-r4k.o -obj-$(CONFIG_CPU_TX39XX) += c-tx39.o pg-r4k.o tlb-r3k.o -obj-$(CONFIG_CPU_TX49XX) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o +obj-$(CONFIG_CPU_LOONGSON2) += c-r4k.o cex-gen.o tlb-r4k.o +obj-$(CONFIG_CPU_MIPS32) += c-r4k.o cex-gen.o tlb-r4k.o +obj-$(CONFIG_CPU_MIPS64) += c-r4k.o cex-gen.o tlb-r4k.o +obj-$(CONFIG_CPU_NEVADA) += c-r4k.o cex-gen.o tlb-r4k.o +obj-$(CONFIG_CPU_R10000) += c-r4k.o cex-gen.o tlb-r4k.o +obj-$(CONFIG_CPU_R3000) += c-r3k.o tlb-r3k.o +obj-$(CONFIG_CPU_R4300) += c-r4k.o cex-gen.o tlb-r4k.o +obj-$(CONFIG_CPU_R4X00) += c-r4k.o cex-gen.o tlb-r4k.o +obj-$(CONFIG_CPU_R5000) += c-r4k.o cex-gen.o tlb-r4k.o +obj-$(CONFIG_CPU_R5432) += c-r4k.o cex-gen.o tlb-r4k.o +obj-$(CONFIG_CPU_R8000) += c-r4k.o cex-gen.o tlb-r8k.o +obj-$(CONFIG_CPU_RM7000) += c-r4k.o cex-gen.o tlb-r4k.o +obj-$(CONFIG_CPU_RM9000) += c-r4k.o cex-gen.o tlb-r4k.o +obj-$(CONFIG_CPU_SB1) += c-r4k.o cerr-sb1.o cex-sb1.o tlb-r4k.o +obj-$(CONFIG_CPU_TX39XX) += c-tx39.o tlb-r3k.o +obj-$(CONFIG_CPU_TX49XX) += c-r4k.o cex-gen.o tlb-r4k.o +obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-gen.o tlb-r4k.o obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 77aefb4ebed..643c8bcffff 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -14,6 +14,7 @@ #include <linux/linkage.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/bitops.h> #include <asm/bcache.h> @@ -53,6 +54,12 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info, preempt_enable(); } +#if defined(CONFIG_MIPS_CMP) +#define cpu_has_safe_index_cacheops 0 +#else +#define cpu_has_safe_index_cacheops 1 +#endif + /* * Must die. */ @@ -481,6 +488,8 @@ static inline void local_r4k_flush_cache_page(void *args) if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { r4k_blast_dcache_page(addr); + if (exec && !cpu_icache_snoops_remote_store) + r4k_blast_scache_page(addr); } if (exec) { if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) { @@ -583,7 +592,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) * subset property so we have to flush the primary caches * explicitly */ - if (size >= dcache_size) { + if (cpu_has_safe_index_cacheops && size >= dcache_size) { r4k_blast_dcache(); } else { R4600_HIT_CACHEOP_WAR_IMPL; @@ -606,7 +615,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) return; } - if (size >= dcache_size) { + if (cpu_has_safe_index_cacheops && size >= dcache_size) { r4k_blast_dcache(); } else { R4600_HIT_CACHEOP_WAR_IMPL; @@ -968,6 +977,7 @@ static void __cpuinit probe_pcache(void) case CPU_24K: case CPU_34K: case CPU_74K: + case CPU_1004K: if ((read_c0_config7() & (1 << 16))) { /* effectively physically indexed dcache, thus no virtual aliases. */ @@ -1216,9 +1226,25 @@ void au1x00_fixup_config_od(void) } } +static int __cpuinitdata cca = -1; + +static int __init cca_setup(char *str) +{ + get_option(&str, &cca); + + return 1; +} + +__setup("cca=", cca_setup); + static void __cpuinit coherency_setup(void) { - change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT); + if (cca < 0 || cca > 7) + cca = read_c0_config() & CONF_CM_CMASK; + _page_cachable_default = cca << _CACHE_SHIFT; + + pr_debug("Using cache attribute %d\n", cca); + change_c0_config(CONF_CM_CMASK, cca); /* * c0_status.cu=0 specifies that updates by the sc instruction use @@ -1248,6 +1274,20 @@ static void __cpuinit coherency_setup(void) } } +#if defined(CONFIG_DMA_NONCOHERENT) + +static int __cpuinitdata coherentio; + +static int __init setcoherentio(char *str) +{ + coherentio = 1; + + return 1; +} + +__setup("coherentio", setcoherentio); +#endif + void __cpuinit r4k_cache_init(void) { extern void build_clear_page(void); @@ -1307,14 +1347,22 @@ void __cpuinit r4k_cache_init(void) flush_data_cache_page = r4k_flush_data_cache_page; flush_icache_range = r4k_flush_icache_range; -#ifdef CONFIG_DMA_NONCOHERENT - _dma_cache_wback_inv = r4k_dma_cache_wback_inv; - _dma_cache_wback = r4k_dma_cache_wback_inv; - _dma_cache_inv = r4k_dma_cache_inv; +#if defined(CONFIG_DMA_NONCOHERENT) + if (coherentio) { + _dma_cache_wback_inv = (void *)cache_noop; + _dma_cache_wback = (void *)cache_noop; + _dma_cache_inv = (void *)cache_noop; + } else { + _dma_cache_wback_inv = r4k_dma_cache_wback_inv; + _dma_cache_wback = r4k_dma_cache_wback_inv; + _dma_cache_inv = r4k_dma_cache_inv; + } #endif build_clear_page(); build_copy_page(); +#if !defined(CONFIG_MIPS_CMP) local_r4k___flush_cache_all(NULL); +#endif coherency_setup(); } diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index f5903679ee6..034e8506f6e 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -130,8 +130,28 @@ void __update_cache(struct vm_area_struct *vma, unsigned long address, } } -static char cache_panic[] __cpuinitdata = - "Yeee, unsupported cache architecture."; +unsigned long _page_cachable_default; +EXPORT_SYMBOL_GPL(_page_cachable_default); + +static inline void setup_protection_map(void) +{ + protection_map[0] = PAGE_NONE; + protection_map[1] = PAGE_READONLY; + protection_map[2] = PAGE_COPY; + protection_map[3] = PAGE_COPY; + protection_map[4] = PAGE_READONLY; + protection_map[5] = PAGE_READONLY; + protection_map[6] = PAGE_COPY; + protection_map[7] = PAGE_COPY; + protection_map[8] = PAGE_NONE; + protection_map[9] = PAGE_READONLY; + protection_map[10] = PAGE_SHARED; + protection_map[11] = PAGE_SHARED; + protection_map[12] = PAGE_READONLY; + protection_map[13] = PAGE_READONLY; + protection_map[14] = PAGE_SHARED; + protection_map[15] = PAGE_SHARED; +} void __devinit cpu_cache_init(void) { @@ -139,34 +159,29 @@ void __devinit cpu_cache_init(void) extern void __weak r3k_cache_init(void); r3k_cache_init(); - return; } if (cpu_has_6k_cache) { extern void __weak r6k_cache_init(void); r6k_cache_init(); - return; } if (cpu_has_4k_cache) { extern void __weak r4k_cache_init(void); r4k_cache_init(); - return; } if (cpu_has_8k_cache) { extern void __weak r8k_cache_init(void); r8k_cache_init(); - return; } if (cpu_has_tx39_cache) { extern void __weak tx39_cache_init(void); tx39_cache_init(); - return; } - panic(cache_panic); + setup_protection_map(); } int __weak __uncached_access(struct file *file, unsigned long addr) diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index c7aed133d11..ecd562d2c34 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -142,7 +142,7 @@ void *kmap_coherent(struct page *page, unsigned long addr) #endif vaddr = __fix_to_virt(FIX_CMAP_END - idx); pte = mk_pte(page, PAGE_KERNEL); -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) +#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) entrylo = pte.pte_high; #else entrylo = pte_val(pte) >> 6; @@ -221,7 +221,7 @@ void copy_user_highpage(struct page *to, struct page *from, copy_page(vto, vfrom); kunmap_atomic(vfrom, KM_USER0); } - if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) || + if ((!cpu_has_ic_fills_f_dc) || pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) flush_data_cache_page((unsigned long)vto); kunmap_atomic(vto, KM_USER1); @@ -229,8 +229,6 @@ void copy_user_highpage(struct page *to, struct page *from, smp_wmb(); } -EXPORT_SYMBOL(copy_user_highpage); - void copy_to_user_page(struct vm_area_struct *vma, struct page *page, unsigned long vaddr, void *dst, const void *src, unsigned long len) @@ -249,8 +247,6 @@ void copy_to_user_page(struct vm_area_struct *vma, flush_cache_page(vma, vaddr, page_to_pfn(page)); } -EXPORT_SYMBOL(copy_to_user_page); - void copy_from_user_page(struct vm_area_struct *vma, struct page *page, unsigned long vaddr, void *dst, const void *src, unsigned long len) @@ -267,9 +263,6 @@ void copy_from_user_page(struct vm_area_struct *vma, } } -EXPORT_SYMBOL(copy_from_user_page); - - #ifdef CONFIG_HIGHMEM unsigned long highstart_pfn, highend_pfn; diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c new file mode 100644 index 00000000000..d827d614436 --- /dev/null +++ b/arch/mips/mm/page.c @@ -0,0 +1,684 @@ +/* + * 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) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2007 Maciej W. Rozycki + * Copyright (C) 2008 Thiemo Seufer + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/proc_fs.h> + +#include <asm/bugs.h> +#include <asm/cacheops.h> +#include <asm/inst.h> +#include <asm/io.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/prefetch.h> +#include <asm/system.h> +#include <asm/bootinfo.h> +#include <asm/mipsregs.h> +#include <asm/mmu_context.h> +#include <asm/cpu.h> +#include <asm/war.h> + +#ifdef CONFIG_SIBYTE_DMA_PAGEOPS +#include <asm/sibyte/sb1250.h> +#include <asm/sibyte/sb1250_regs.h> +#include <asm/sibyte/sb1250_dma.h> +#endif + +#include "uasm.h" + +/* Registers used in the assembled routines. */ +#define ZERO 0 +#define AT 2 +#define A0 4 +#define A1 5 +#define A2 6 +#define T0 8 +#define T1 9 +#define T2 10 +#define T3 11 +#define T9 25 +#define RA 31 + +/* Handle labels (which must be positive integers). */ +enum label_id { + label_clear_nopref = 1, + label_clear_pref, + label_copy_nopref, + label_copy_pref_both, + label_copy_pref_store, +}; + +UASM_L_LA(_clear_nopref) +UASM_L_LA(_clear_pref) +UASM_L_LA(_copy_nopref) +UASM_L_LA(_copy_pref_both) +UASM_L_LA(_copy_pref_store) + +/* We need one branch and therefore one relocation per target label. */ +static struct uasm_label __cpuinitdata labels[5]; +static struct uasm_reloc __cpuinitdata relocs[5]; + +#define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010) +#define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020) + +/* + * Maximum sizes: + * + * R4000 128 bytes S-cache: 0x058 bytes + * R4600 v1.7: 0x05c bytes + * R4600 v2.0: 0x060 bytes + * With prefetching, 16 word strides 0x120 bytes + */ + +static u32 clear_page_array[0x120 / 4]; + +#ifdef CONFIG_SIBYTE_DMA_PAGEOPS +void clear_page_cpu(void *page) __attribute__((alias("clear_page_array"))); +#else +void clear_page(void *page) __attribute__((alias("clear_page_array"))); +#endif + +EXPORT_SYMBOL(clear_page); + +/* + * Maximum sizes: + * + * R4000 128 bytes S-cache: 0x11c bytes + * R4600 v1.7: 0x080 bytes + * R4600 v2.0: 0x07c bytes + * With prefetching, 16 word strides 0x540 bytes + */ +static u32 copy_page_array[0x540 / 4]; + +#ifdef CONFIG_SIBYTE_DMA_PAGEOPS +void +copy_page_cpu(void *to, void *from) __attribute__((alias("copy_page_array"))); +#else +void copy_page(void *to, void *from) __attribute__((alias("copy_page_array"))); +#endif + +EXPORT_SYMBOL(copy_page); + + +static int pref_bias_clear_store __cpuinitdata; +static int pref_bias_copy_load __cpuinitdata; +static int pref_bias_copy_store __cpuinitdata; + +static u32 pref_src_mode __cpuinitdata; +static u32 pref_dst_mode __cpuinitdata; + +static int clear_word_size __cpuinitdata; +static int copy_word_size __cpuinitdata; + +static int half_clear_loop_size __cpuinitdata; +static int half_copy_loop_size __cpuinitdata; + +static int cache_line_size __cpuinitdata; +#define cache_line_mask() (cache_line_size - 1) + +static inline void __cpuinit +pg_addiu(u32 **buf, unsigned int reg1, unsigned int reg2, unsigned int off) +{ + if (cpu_has_64bit_gp_regs && DADDI_WAR && r4k_daddiu_bug()) { + if (off > 0x7fff) { + uasm_i_lui(buf, T9, uasm_rel_hi(off)); + uasm_i_addiu(buf, T9, T9, uasm_rel_lo(off)); + } else + uasm_i_addiu(buf, T9, ZERO, off); + uasm_i_daddu(buf, reg1, reg2, T9); + } else { + if (off > 0x7fff) { + uasm_i_lui(buf, T9, uasm_rel_hi(off)); + uasm_i_addiu(buf, T9, T9, uasm_rel_lo(off)); + UASM_i_ADDU(buf, reg1, reg2, T9); + } else + UASM_i_ADDIU(buf, reg1, reg2, off); + } +} + +static void __cpuinit set_prefetch_parameters(void) +{ + if (cpu_has_64bit_gp_regs || cpu_has_64bit_zero_reg) + clear_word_size = 8; + else + clear_word_size = 4; + + if (cpu_has_64bit_gp_regs) + copy_word_size = 8; + else + copy_word_size = 4; + + /* + * The pref's used here are using "streaming" hints, which cause the + * copied data to be kicked out of the cache sooner. A page copy often + * ends up copying a lot more data than is commonly used, so this seems + * to make sense in terms of reducing cache pollution, but I've no real + * performance data to back this up. + */ + if (cpu_has_prefetch) { + /* + * XXX: Most prefetch bias values in here are based on + * guesswork. + */ + cache_line_size = cpu_dcache_line_size(); + switch (current_cpu_type()) { + case CPU_TX49XX: + /* TX49 supports only Pref_Load */ + pref_bias_copy_load = 256; + break; + + case CPU_RM9000: + /* + * As a workaround for erratum G105 which make the + * PrepareForStore hint unusable we fall back to + * StoreRetained on the RM9000. Once it is known which + * versions of the RM9000 we'll be able to condition- + * alize this. + */ + + case CPU_R10000: + case CPU_R12000: + case CPU_R14000: + /* + * Those values have been experimentally tuned for an + * Origin 200. + */ + pref_bias_clear_store = 512; + pref_bias_copy_load = 256; + pref_bias_copy_store = 256; + pref_src_mode = Pref_LoadStreamed; + pref_dst_mode = Pref_StoreStreamed; + break; + + case CPU_SB1: + case CPU_SB1A: + pref_bias_clear_store = 128; + pref_bias_copy_load = 128; + pref_bias_copy_store = 128; + /* + * SB1 pass1 Pref_LoadStreamed/Pref_StoreStreamed + * hints are broken. + */ + if (current_cpu_type() == CPU_SB1 && + (current_cpu_data.processor_id & 0xff) < 0x02) { + pref_src_mode = Pref_Load; + pref_dst_mode = Pref_Store; + } else { + pref_src_mode = Pref_LoadStreamed; + pref_dst_mode = Pref_StoreStreamed; + } + break; + + default: + pref_bias_clear_store = 128; + pref_bias_copy_load = 256; + pref_bias_copy_store = 128; + pref_src_mode = Pref_LoadStreamed; + pref_dst_mode = Pref_PrepareForStore; + break; + } + } else { + if (cpu_has_cache_cdex_s) + cache_line_size = cpu_scache_line_size(); + else if (cpu_has_cache_cdex_p) + cache_line_size = cpu_dcache_line_size(); + } + /* + * Too much unrolling will overflow the available space in + * clear_space_array / copy_page_array. 8 words sounds generous, + * but a R4000 with 128 byte L2 line length can exceed even that. + */ + half_clear_loop_size = min(8 * clear_word_size, + max(cache_line_size >> 1, + 4 * clear_word_size)); + half_copy_loop_size = min(8 * copy_word_size, + max(cache_line_size >> 1, + 4 * copy_word_size)); +} + +static void __cpuinit build_clear_store(u32 **buf, int off) +{ + if (cpu_has_64bit_gp_regs || cpu_has_64bit_zero_reg) { + uasm_i_sd(buf, ZERO, off, A0); + } else { + uasm_i_sw(buf, ZERO, off, A0); + } +} + +static inline void __cpuinit build_clear_pref(u32 **buf, int off) +{ + if (off & cache_line_mask()) + return; + + if (pref_bias_clear_store) { + uasm_i_pref(buf, pref_dst_mode, pref_bias_clear_store + off, + A0); + } else if (cpu_has_cache_cdex_s) { + uasm_i_cache(buf, Create_Dirty_Excl_SD, off, A0); + } else if (cpu_has_cache_cdex_p) { + if (R4600_V1_HIT_CACHEOP_WAR && cpu_is_r4600_v1_x()) { + uasm_i_nop(buf); + uasm_i_nop(buf); + uasm_i_nop(buf); + uasm_i_nop(buf); + } + + if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) + uasm_i_lw(buf, ZERO, ZERO, AT); + + uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0); + } +} + +void __cpuinit build_clear_page(void) +{ + int off; + u32 *buf = (u32 *)&clear_page_array; + struct uasm_label *l = labels; + struct uasm_reloc *r = relocs; + int i; + + memset(labels, 0, sizeof(labels)); + memset(relocs, 0, sizeof(relocs)); + + set_prefetch_parameters(); + + /* + * This algorithm makes the following assumptions: + * - The prefetch bias is a multiple of 2 words. + * - The prefetch bias is less than one page. + */ + BUG_ON(pref_bias_clear_store % (2 * clear_word_size)); + BUG_ON(PAGE_SIZE < pref_bias_clear_store); + + off = PAGE_SIZE - pref_bias_clear_store; + if (off > 0xffff || !pref_bias_clear_store) + pg_addiu(&buf, A2, A0, off); + else + uasm_i_ori(&buf, A2, A0, off); + + if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) + uasm_i_lui(&buf, AT, 0xa000); + + off = min(8, pref_bias_clear_store / cache_line_size) * + cache_line_size; + while (off) { + build_clear_pref(&buf, -off); + off -= cache_line_size; + } + uasm_l_clear_pref(&l, buf); + do { + build_clear_pref(&buf, off); + build_clear_store(&buf, off); + off += clear_word_size; + } while (off < half_clear_loop_size); + pg_addiu(&buf, A0, A0, 2 * off); + off = -off; + do { + build_clear_pref(&buf, off); + if (off == -clear_word_size) + uasm_il_bne(&buf, &r, A0, A2, label_clear_pref); + build_clear_store(&buf, off); + off += clear_word_size; + } while (off < 0); + + if (pref_bias_clear_store) { + pg_addiu(&buf, A2, A0, pref_bias_clear_store); + uasm_l_clear_nopref(&l, buf); + off = 0; + do { + build_clear_store(&buf, off); + off += clear_word_size; + } while (off < half_clear_loop_size); + pg_addiu(&buf, A0, A0, 2 * off); + off = -off; + do { + if (off == -clear_word_size) + uasm_il_bne(&buf, &r, A0, A2, + label_clear_nopref); + build_clear_store(&buf, off); + off += clear_word_size; + } while (off < 0); + } + + uasm_i_jr(&buf, RA); + uasm_i_nop(&buf); + + BUG_ON(buf > clear_page_array + ARRAY_SIZE(clear_page_array)); + + uasm_resolve_relocs(relocs, labels); + + pr_debug("Synthesized clear page handler (%u instructions).\n", + (u32)(buf - clear_page_array)); + + pr_debug("\t.set push\n"); + pr_debug("\t.set noreorder\n"); + for (i = 0; i < (buf - clear_page_array); i++) + pr_debug("\t.word 0x%08x\n", clear_page_array[i]); + pr_debug("\t.set pop\n"); +} + +static void __cpuinit build_copy_load(u32 **buf, int reg, int off) +{ + if (cpu_has_64bit_gp_regs) { + uasm_i_ld(buf, reg, off, A1); + } else { + uasm_i_lw(buf, reg, off, A1); + } +} + +static void __cpuinit build_copy_store(u32 **buf, int reg, int off) +{ + if (cpu_has_64bit_gp_regs) { + uasm_i_sd(buf, reg, off, A0); + } else { + uasm_i_sw(buf, reg, off, A0); + } +} + +static inline void build_copy_load_pref(u32 **buf, int off) +{ + if (off & cache_line_mask()) + return; + + if (pref_bias_copy_load) + uasm_i_pref(buf, pref_src_mode, pref_bias_copy_load + off, A1); +} + +static inline void build_copy_store_pref(u32 **buf, int off) +{ + if (off & cache_line_mask()) + return; + + if (pref_bias_copy_store) { + uasm_i_pref(buf, pref_dst_mode, pref_bias_copy_store + off, + A0); + } else if (cpu_has_cache_cdex_s) { + uasm_i_cache(buf, Create_Dirty_Excl_SD, off, A0); + } else if (cpu_has_cache_cdex_p) { + if (R4600_V1_HIT_CACHEOP_WAR && cpu_is_r4600_v1_x()) { + uasm_i_nop(buf); + uasm_i_nop(buf); + uasm_i_nop(buf); + uasm_i_nop(buf); + } + + if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) + uasm_i_lw(buf, ZERO, ZERO, AT); + + uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0); + } +} + +void __cpuinit build_copy_page(void) +{ + int off; + u32 *buf = (u32 *)©_page_array; + struct uasm_label *l = labels; + struct uasm_reloc *r = relocs; + int i; + + memset(labels, 0, sizeof(labels)); + memset(relocs, 0, sizeof(relocs)); + + set_prefetch_parameters(); + + /* + * This algorithm makes the following assumptions: + * - All prefetch biases are multiples of 8 words. + * - The prefetch biases are less than one page. + * - The store prefetch bias isn't greater than the load + * prefetch bias. + */ + BUG_ON(pref_bias_copy_load % (8 * copy_word_size)); + BUG_ON(pref_bias_copy_store % (8 * copy_word_size)); + BUG_ON(PAGE_SIZE < pref_bias_copy_load); + BUG_ON(pref_bias_copy_store > pref_bias_copy_load); + + off = PAGE_SIZE - pref_bias_copy_load; + if (off > 0xffff || !pref_bias_copy_load) + pg_addiu(&buf, A2, A0, off); + else + uasm_i_ori(&buf, A2, A0, off); + + if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) + uasm_i_lui(&buf, AT, 0xa000); + + off = min(8, pref_bias_copy_load / cache_line_size) * cache_line_size; + while (off) { + build_copy_load_pref(&buf, -off); + off -= cache_line_size; + } + off = min(8, pref_bias_copy_store / cache_line_size) * cache_line_size; + while (off) { + build_copy_store_pref(&buf, -off); + off -= cache_line_size; + } + uasm_l_copy_pref_both(&l, buf); + do { + build_copy_load_pref(&buf, off); + build_copy_load(&buf, T0, off); + build_copy_load_pref(&buf, off + copy_word_size); + build_copy_load(&buf, T1, off + copy_word_size); + build_copy_load_pref(&buf, off + 2 * copy_word_size); + build_copy_load(&buf, T2, off + 2 * copy_word_size); + build_copy_load_pref(&buf, off + 3 * copy_word_size); + build_copy_load(&buf, T3, off + 3 * copy_word_size); + build_copy_store_pref(&buf, off); + build_copy_store(&buf, T0, off); + build_copy_store_pref(&buf, off + copy_word_size); + build_copy_store(&buf, T1, off + copy_word_size); + build_copy_store_pref(&buf, off + 2 * copy_word_size); + build_copy_store(&buf, T2, off + 2 * copy_word_size); + build_copy_store_pref(&buf, off + 3 * copy_word_size); + build_copy_store(&buf, T3, off + 3 * copy_word_size); + off += 4 * copy_word_size; + } while (off < half_copy_loop_size); + pg_addiu(&buf, A1, A1, 2 * off); + pg_addiu(&buf, A0, A0, 2 * off); + off = -off; + do { + build_copy_load_pref(&buf, off); + build_copy_load(&buf, T0, off); + build_copy_load_pref(&buf, off + copy_word_size); + build_copy_load(&buf, T1, off + copy_word_size); + build_copy_load_pref(&buf, off + 2 * copy_word_size); + build_copy_load(&buf, T2, off + 2 * copy_word_size); + build_copy_load_pref(&buf, off + 3 * copy_word_size); + build_copy_load(&buf, T3, off + 3 * copy_word_size); + build_copy_store_pref(&buf, off); + build_copy_store(&buf, T0, off); + build_copy_store_pref(&buf, off + copy_word_size); + build_copy_store(&buf, T1, off + copy_word_size); + build_copy_store_pref(&buf, off + 2 * copy_word_size); + build_copy_store(&buf, T2, off + 2 * copy_word_size); + build_copy_store_pref(&buf, off + 3 * copy_word_size); + if (off == -(4 * copy_word_size)) + uasm_il_bne(&buf, &r, A2, A0, label_copy_pref_both); + build_copy_store(&buf, T3, off + 3 * copy_word_size); + off += 4 * copy_word_size; + } while (off < 0); + + if (pref_bias_copy_load - pref_bias_copy_store) { + pg_addiu(&buf, A2, A0, + pref_bias_copy_load - pref_bias_copy_store); + uasm_l_copy_pref_store(&l, buf); + off = 0; + do { + build_copy_load(&buf, T0, off); + build_copy_load(&buf, T1, off + copy_word_size); + build_copy_load(&buf, T2, off + 2 * copy_word_size); + build_copy_load(&buf, T3, off + 3 * copy_word_size); + build_copy_store_pref(&buf, off); + build_copy_store(&buf, T0, off); + build_copy_store_pref(&buf, off + copy_word_size); + build_copy_store(&buf, T1, off + copy_word_size); + build_copy_store_pref(&buf, off + 2 * copy_word_size); + build_copy_store(&buf, T2, off + 2 * copy_word_size); + build_copy_store_pref(&buf, off + 3 * copy_word_size); + build_copy_store(&buf, T3, off + 3 * copy_word_size); + off += 4 * copy_word_size; + } while (off < half_copy_loop_size); + pg_addiu(&buf, A1, A1, 2 * off); + pg_addiu(&buf, A0, A0, 2 * off); + off = -off; + do { + build_copy_load(&buf, T0, off); + build_copy_load(&buf, T1, off + copy_word_size); + build_copy_load(&buf, T2, off + 2 * copy_word_size); + build_copy_load(&buf, T3, off + 3 * copy_word_size); + build_copy_store_pref(&buf, off); + build_copy_store(&buf, T0, off); + build_copy_store_pref(&buf, off + copy_word_size); + build_copy_store(&buf, T1, off + copy_word_size); + build_copy_store_pref(&buf, off + 2 * copy_word_size); + build_copy_store(&buf, T2, off + 2 * copy_word_size); + build_copy_store_pref(&buf, off + 3 * copy_word_size); + if (off == -(4 * copy_word_size)) + uasm_il_bne(&buf, &r, A2, A0, + label_copy_pref_store); + build_copy_store(&buf, T3, off + 3 * copy_word_size); + off += 4 * copy_word_size; + } while (off < 0); + } + + if (pref_bias_copy_store) { + pg_addiu(&buf, A2, A0, pref_bias_copy_store); + uasm_l_copy_nopref(&l, buf); + off = 0; + do { + build_copy_load(&buf, T0, off); + build_copy_load(&buf, T1, off + copy_word_size); + build_copy_load(&buf, T2, off + 2 * copy_word_size); + build_copy_load(&buf, T3, off + 3 * copy_word_size); + build_copy_store(&buf, T0, off); + build_copy_store(&buf, T1, off + copy_word_size); + build_copy_store(&buf, T2, off + 2 * copy_word_size); + build_copy_store(&buf, T3, off + 3 * copy_word_size); + off += 4 * copy_word_size; + } while (off < half_copy_loop_size); + pg_addiu(&buf, A1, A1, 2 * off); + pg_addiu(&buf, A0, A0, 2 * off); + off = -off; + do { + build_copy_load(&buf, T0, off); + build_copy_load(&buf, T1, off + copy_word_size); + build_copy_load(&buf, T2, off + 2 * copy_word_size); + build_copy_load(&buf, T3, off + 3 * copy_word_size); + build_copy_store(&buf, T0, off); + build_copy_store(&buf, T1, off + copy_word_size); + build_copy_store(&buf, T2, off + 2 * copy_word_size); + if (off == -(4 * copy_word_size)) + uasm_il_bne(&buf, &r, A2, A0, + label_copy_nopref); + build_copy_store(&buf, T3, off + 3 * copy_word_size); + off += 4 * copy_word_size; + } while (off < 0); + } + + uasm_i_jr(&buf, RA); + uasm_i_nop(&buf); + + BUG_ON(buf > copy_page_array + ARRAY_SIZE(copy_page_array)); + + uasm_resolve_relocs(relocs, labels); + + pr_debug("Synthesized copy page handler (%u instructions).\n", + (u32)(buf - copy_page_array)); + + pr_debug("\t.set push\n"); + pr_debug("\t.set noreorder\n"); + for (i = 0; i < (buf - copy_page_array); i++) + pr_debug("\t.word 0x%08x\n", copy_page_array[i]); + pr_debug("\t.set pop\n"); +} + +#ifdef CONFIG_SIBYTE_DMA_PAGEOPS + +/* + * Pad descriptors to cacheline, since each is exclusively owned by a + * particular CPU. + */ +struct dmadscr { + u64 dscr_a; + u64 dscr_b; + u64 pad_a; + u64 pad_b; +} ____cacheline_aligned_in_smp page_descr[DM_NUM_CHANNELS]; + +void sb1_dma_init(void) +{ + int i; + + for (i = 0; i < DM_NUM_CHANNELS; 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)); + + __raw_writeq(base_val, base_reg); + __raw_writeq(base_val | M_DM_DSCR_BASE_RESET, base_reg); + __raw_writeq(base_val | M_DM_DSCR_BASE_ENABL, base_reg); + } +} + +void clear_page(void *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((unsigned long)page) != (long)CKSEG0) + return clear_page_cpu(page); + + page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_ZERO_MEM | + M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT; + page_descr[cpu].dscr_b = V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE); + __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT))); + + /* + * Don't really want to do it this way, but there's no + * reliable way to delay completion detection. + */ + while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG))) + & M_DM_DSCR_BASE_INTERRUPT)) + ; + __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE))); +} + +void copy_page(void *to, void *from) +{ + 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((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 | + M_DM_DSCRA_INTERRUPT; + page_descr[cpu].dscr_b = from_phys | V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE); + __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT))); + + /* + * Don't really want to do it this way, but there's no + * reliable way to delay completion detection. + */ + while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG))) + & M_DM_DSCR_BASE_INTERRUPT)) + ; + __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE))); +} + +#endif /* CONFIG_SIBYTE_DMA_PAGEOPS */ diff --git a/arch/mips/mm/pg-r4k.c b/arch/mips/mm/pg-r4k.c deleted file mode 100644 index 455dedb5b39..00000000000 --- a/arch/mips/mm/pg-r4k.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * 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) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org) - * Copyright (C) 2007 Maciej W. Rozycki - */ -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/proc_fs.h> - -#include <asm/bugs.h> -#include <asm/cacheops.h> -#include <asm/inst.h> -#include <asm/io.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/prefetch.h> -#include <asm/system.h> -#include <asm/bootinfo.h> -#include <asm/mipsregs.h> -#include <asm/mmu_context.h> -#include <asm/cpu.h> -#include <asm/war.h> - -#define half_scache_line_size() (cpu_scache_line_size() >> 1) -#define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010) -#define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020) - - -/* - * Maximum sizes: - * - * R4000 128 bytes S-cache: 0x58 bytes - * R4600 v1.7: 0x5c bytes - * R4600 v2.0: 0x60 bytes - * With prefetching, 16 byte strides 0xa0 bytes - */ - -static unsigned int clear_page_array[0x130 / 4]; - -void clear_page(void * page) __attribute__((alias("clear_page_array"))); - -EXPORT_SYMBOL(clear_page); - -/* - * Maximum sizes: - * - * R4000 128 bytes S-cache: 0x11c bytes - * R4600 v1.7: 0x080 bytes - * R4600 v2.0: 0x07c bytes - * With prefetching, 16 byte strides 0x0b8 bytes - */ -static unsigned int copy_page_array[0x148 / 4]; - -void copy_page(void *to, void *from) __attribute__((alias("copy_page_array"))); - -EXPORT_SYMBOL(copy_page); - -/* - * This is suboptimal for 32-bit kernels; we assume that R10000 is only used - * with 64-bit kernels. The prefetch offsets have been experimentally tuned - * an Origin 200. - */ -static int pref_offset_clear __cpuinitdata = 512; -static int pref_offset_copy __cpuinitdata = 256; - -static unsigned int pref_src_mode __cpuinitdata; -static unsigned int pref_dst_mode __cpuinitdata; - -static int load_offset __cpuinitdata; -static int store_offset __cpuinitdata; - -static unsigned int __cpuinitdata *dest, *epc; - -static unsigned int instruction_pending; -static union mips_instruction delayed_mi; - -static void __cpuinit emit_instruction(union mips_instruction mi) -{ - if (instruction_pending) - *epc++ = delayed_mi.word; - - instruction_pending = 1; - delayed_mi = mi; -} - -static inline void flush_delay_slot_or_nop(void) -{ - if (instruction_pending) { - *epc++ = delayed_mi.word; - instruction_pending = 0; - return; - } - - *epc++ = 0; -} - -static inline unsigned int *label(void) -{ - if (instruction_pending) { - *epc++ = delayed_mi.word; - instruction_pending = 0; - } - - return epc; -} - -static inline void build_insn_word(unsigned int word) -{ - union mips_instruction mi; - - mi.word = word; - - emit_instruction(mi); -} - -static inline void build_nop(void) -{ - build_insn_word(0); /* nop */ -} - -static inline void build_src_pref(int advance) -{ - if (!(load_offset & (cpu_dcache_line_size() - 1)) && advance) { - union mips_instruction mi; - - mi.i_format.opcode = pref_op; - mi.i_format.rs = 5; /* $a1 */ - mi.i_format.rt = pref_src_mode; - mi.i_format.simmediate = load_offset + advance; - - emit_instruction(mi); - } -} - -static inline void __build_load_reg(int reg) -{ - union mips_instruction mi; - unsigned int width; - - if (cpu_has_64bit_gp_regs) { - mi.i_format.opcode = ld_op; - width = 8; - } else { - mi.i_format.opcode = lw_op; - width = 4; - } - mi.i_format.rs = 5; /* $a1 */ - mi.i_format.rt = reg; /* $reg */ - mi.i_format.simmediate = load_offset; - - load_offset += width; - emit_instruction(mi); -} - -static inline void build_load_reg(int reg) -{ - if (cpu_has_prefetch) - build_src_pref(pref_offset_copy); - - __build_load_reg(reg); -} - -static inline void build_dst_pref(int advance) -{ - if (!(store_offset & (cpu_dcache_line_size() - 1)) && advance) { - union mips_instruction mi; - - mi.i_format.opcode = pref_op; - mi.i_format.rs = 4; /* $a0 */ - mi.i_format.rt = pref_dst_mode; - mi.i_format.simmediate = store_offset + advance; - - emit_instruction(mi); - } -} - -static inline void build_cdex_s(void) -{ - union mips_instruction mi; - - if ((store_offset & (cpu_scache_line_size() - 1))) - return; - - mi.c_format.opcode = cache_op; - mi.c_format.rs = 4; /* $a0 */ - mi.c_format.c_op = 3; /* Create Dirty Exclusive */ - mi.c_format.cache = 3; /* Secondary Data Cache */ - mi.c_format.simmediate = store_offset; - - emit_instruction(mi); -} - -static inline void build_cdex_p(void) -{ - union mips_instruction mi; - - if (store_offset & (cpu_dcache_line_size() - 1)) - return; - - if (R4600_V1_HIT_CACHEOP_WAR && cpu_is_r4600_v1_x()) { - build_nop(); - build_nop(); - build_nop(); - build_nop(); - } - - if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) - build_insn_word(0x8c200000); /* lw $zero, ($at) */ - - mi.c_format.opcode = cache_op; - mi.c_format.rs = 4; /* $a0 */ - mi.c_format.c_op = 3; /* Create Dirty Exclusive */ - mi.c_format.cache = 1; /* Data Cache */ - mi.c_format.simmediate = store_offset; - - emit_instruction(mi); -} - -static void __cpuinit __build_store_reg(int reg) -{ - union mips_instruction mi; - unsigned int width; - - if (cpu_has_64bit_gp_regs || - (cpu_has_64bit_zero_reg && reg == 0)) { - mi.i_format.opcode = sd_op; - width = 8; - } else { - mi.i_format.opcode = sw_op; - width = 4; - } - mi.i_format.rs = 4; /* $a0 */ - mi.i_format.rt = reg; /* $reg */ - mi.i_format.simmediate = store_offset; - - store_offset += width; - emit_instruction(mi); -} - -static inline void build_store_reg(int reg) -{ - int pref_off = cpu_has_prefetch ? - (reg ? pref_offset_copy : pref_offset_clear) : 0; - if (pref_off) - build_dst_pref(pref_off); - else if (cpu_has_cache_cdex_s) - build_cdex_s(); - else if (cpu_has_cache_cdex_p) - build_cdex_p(); - - __build_store_reg(reg); -} - -static inline void build_addiu_rt_rs(unsigned int rt, unsigned int rs, - unsigned long offset) -{ - union mips_instruction mi; - - BUG_ON(offset > 0x7fff); - - if (cpu_has_64bit_gp_regs && DADDI_WAR && r4k_daddiu_bug()) { - mi.i_format.opcode = addiu_op; - mi.i_format.rs = 0; /* $zero */ - mi.i_format.rt = 25; /* $t9 */ - mi.i_format.simmediate = offset; - emit_instruction(mi); - - mi.r_format.opcode = spec_op; - mi.r_format.rs = rs; - mi.r_format.rt = 25; /* $t9 */ - mi.r_format.rd = rt; - mi.r_format.re = 0; - mi.r_format.func = daddu_op; - } else { - mi.i_format.opcode = cpu_has_64bit_gp_regs ? - daddiu_op : addiu_op; - mi.i_format.rs = rs; - mi.i_format.rt = rt; - mi.i_format.simmediate = offset; - } - emit_instruction(mi); -} - -static inline void build_addiu_a2_a0(unsigned long offset) -{ - build_addiu_rt_rs(6, 4, offset); /* $a2, $a0, offset */ -} - -static inline void build_addiu_a2(unsigned long offset) -{ - build_addiu_rt_rs(6, 6, offset); /* $a2, $a2, offset */ -} - -static inline void build_addiu_a1(unsigned long offset) -{ - build_addiu_rt_rs(5, 5, offset); /* $a1, $a1, offset */ - - load_offset -= offset; -} - -static inline void build_addiu_a0(unsigned long offset) -{ - build_addiu_rt_rs(4, 4, offset); /* $a0, $a0, offset */ - - store_offset -= offset; -} - -static inline void build_bne(unsigned int *dest) -{ - union mips_instruction mi; - - mi.i_format.opcode = bne_op; - mi.i_format.rs = 6; /* $a2 */ - mi.i_format.rt = 4; /* $a0 */ - mi.i_format.simmediate = dest - epc - 1; - - *epc++ = mi.word; - flush_delay_slot_or_nop(); -} - -static inline void build_jr_ra(void) -{ - union mips_instruction mi; - - mi.r_format.opcode = spec_op; - mi.r_format.rs = 31; - mi.r_format.rt = 0; - mi.r_format.rd = 0; - mi.r_format.re = 0; - mi.r_format.func = jr_op; - - *epc++ = mi.word; - flush_delay_slot_or_nop(); -} - -void __cpuinit build_clear_page(void) -{ - unsigned int loop_start; - unsigned long off; - int i; - - epc = (unsigned int *) &clear_page_array; - instruction_pending = 0; - store_offset = 0; - - if (cpu_has_prefetch) { - switch (current_cpu_type()) { - case CPU_TX49XX: - /* TX49 supports only Pref_Load */ - pref_offset_clear = 0; - pref_offset_copy = 0; - break; - - case CPU_RM9000: - /* - * As a workaround for erratum G105 which make the - * PrepareForStore hint unusable we fall back to - * StoreRetained on the RM9000. Once it is known which - * versions of the RM9000 we'll be able to condition- - * alize this. - */ - - case CPU_R10000: - case CPU_R12000: - case CPU_R14000: - pref_src_mode = Pref_LoadStreamed; - pref_dst_mode = Pref_StoreStreamed; - break; - - default: - pref_src_mode = Pref_LoadStreamed; - pref_dst_mode = Pref_PrepareForStore; - break; - } - } - - off = PAGE_SIZE - (cpu_has_prefetch ? pref_offset_clear : 0); - if (off > 0x7fff) { - build_addiu_a2_a0(off >> 1); - build_addiu_a2(off >> 1); - } else - build_addiu_a2_a0(off); - - if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) - build_insn_word(0x3c01a000); /* lui $at, 0xa000 */ - -dest = label(); - do { - build_store_reg(0); - build_store_reg(0); - build_store_reg(0); - build_store_reg(0); - } while (store_offset < half_scache_line_size()); - build_addiu_a0(2 * store_offset); - loop_start = store_offset; - do { - build_store_reg(0); - build_store_reg(0); - build_store_reg(0); - build_store_reg(0); - } while ((store_offset - loop_start) < half_scache_line_size()); - build_bne(dest); - - if (cpu_has_prefetch && pref_offset_clear) { - build_addiu_a2_a0(pref_offset_clear); - dest = label(); - loop_start = store_offset; - do { - __build_store_reg(0); - __build_store_reg(0); - __build_store_reg(0); - __build_store_reg(0); - } while ((store_offset - loop_start) < half_scache_line_size()); - build_addiu_a0(2 * store_offset); - loop_start = store_offset; - do { - __build_store_reg(0); - __build_store_reg(0); - __build_store_reg(0); - __build_store_reg(0); - } while ((store_offset - loop_start) < half_scache_line_size()); - build_bne(dest); - } - - build_jr_ra(); - - BUG_ON(epc > clear_page_array + ARRAY_SIZE(clear_page_array)); - - pr_info("Synthesized clear page handler (%u instructions).\n", - (unsigned int)(epc - clear_page_array)); - - pr_debug("\t.set push\n"); - pr_debug("\t.set noreorder\n"); - for (i = 0; i < (epc - clear_page_array); i++) - pr_debug("\t.word 0x%08x\n", clear_page_array[i]); - pr_debug("\t.set pop\n"); -} - -void __cpuinit build_copy_page(void) -{ - unsigned int loop_start; - unsigned long off; - int i; - - epc = (unsigned int *) ©_page_array; - store_offset = load_offset = 0; - instruction_pending = 0; - - off = PAGE_SIZE - (cpu_has_prefetch ? pref_offset_copy : 0); - if (off > 0x7fff) { - build_addiu_a2_a0(off >> 1); - build_addiu_a2(off >> 1); - } else - build_addiu_a2_a0(off); - - if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) - build_insn_word(0x3c01a000); /* lui $at, 0xa000 */ - -dest = label(); - loop_start = store_offset; - do { - build_load_reg( 8); - build_load_reg( 9); - build_load_reg(10); - build_load_reg(11); - build_store_reg( 8); - build_store_reg( 9); - build_store_reg(10); - build_store_reg(11); - } while ((store_offset - loop_start) < half_scache_line_size()); - build_addiu_a0(2 * store_offset); - build_addiu_a1(2 * load_offset); - loop_start = store_offset; - do { - build_load_reg( 8); - build_load_reg( 9); - build_load_reg(10); - build_load_reg(11); - build_store_reg( 8); - build_store_reg( 9); - build_store_reg(10); - build_store_reg(11); - } while ((store_offset - loop_start) < half_scache_line_size()); - build_bne(dest); - - if (cpu_has_prefetch && pref_offset_copy) { - build_addiu_a2_a0(pref_offset_copy); - dest = label(); - loop_start = store_offset; - do { - __build_load_reg( 8); - __build_load_reg( 9); - __build_load_reg(10); - __build_load_reg(11); - __build_store_reg( 8); - __build_store_reg( 9); - __build_store_reg(10); - __build_store_reg(11); - } while ((store_offset - loop_start) < half_scache_line_size()); - build_addiu_a0(2 * store_offset); - build_addiu_a1(2 * load_offset); - loop_start = store_offset; - do { - __build_load_reg( 8); - __build_load_reg( 9); - __build_load_reg(10); - __build_load_reg(11); - __build_store_reg( 8); - __build_store_reg( 9); - __build_store_reg(10); - __build_store_reg(11); - } while ((store_offset - loop_start) < half_scache_line_size()); - build_bne(dest); - } - - build_jr_ra(); - - BUG_ON(epc > copy_page_array + ARRAY_SIZE(copy_page_array)); - - pr_info("Synthesized copy page handler (%u instructions).\n", - (unsigned int)(epc - copy_page_array)); - - pr_debug("\t.set push\n"); - pr_debug("\t.set noreorder\n"); - for (i = 0; i < (epc - copy_page_array); i++) - pr_debug("\t.word 0x%08x\n", copy_page_array[i]); - pr_debug("\t.set pop\n"); -} diff --git a/arch/mips/mm/pg-sb1.c b/arch/mips/mm/pg-sb1.c deleted file mode 100644 index 49e289d0541..00000000000 --- a/arch/mips/mm/pg-sb1.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org) - * Copyright (C) 2000 SiByte, Inc. - * Copyright (C) 2005 Thiemo Seufer - * - * Written by Justin Carlson of SiByte, Inc. - * and Kip Walker of Broadcom Corp. - * - * - * 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. - */ -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/smp.h> - -#include <asm/io.h> -#include <asm/sibyte/sb1250.h> -#include <asm/sibyte/sb1250_regs.h> -#include <asm/sibyte/sb1250_dma.h> - -#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS -#define SB1_PREF_LOAD_STREAMED_HINT "0" -#define SB1_PREF_STORE_STREAMED_HINT "1" -#else -#define SB1_PREF_LOAD_STREAMED_HINT "4" -#define SB1_PREF_STORE_STREAMED_HINT "5" -#endif - -static inline void clear_page_cpu(void *page) -{ - unsigned char *addr = (unsigned char *) page; - unsigned char *end = addr + PAGE_SIZE; - - /* - * JDCXXX - This should be bottlenecked by the write buffer, but these - * things tend to be mildly unpredictable...should check this on the - * performance model - * - * We prefetch 4 lines ahead. We're also "cheating" slightly here... - * since we know we're on an SB1, we force the assembler to take - * 64-bit operands to speed things up - */ - __asm__ __volatile__( - " .set push \n" - " .set mips4 \n" - " .set noreorder \n" -#ifdef CONFIG_CPU_HAS_PREFETCH - " daddiu %0, %0, 128 \n" - " pref " SB1_PREF_STORE_STREAMED_HINT ", -128(%0) \n" - /* Prefetch the first 4 lines */ - " pref " SB1_PREF_STORE_STREAMED_HINT ", -96(%0) \n" - " pref " SB1_PREF_STORE_STREAMED_HINT ", -64(%0) \n" - " pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%0) \n" - "1: sd $0, -128(%0) \n" /* Throw out a cacheline of 0's */ - " sd $0, -120(%0) \n" - " sd $0, -112(%0) \n" - " sd $0, -104(%0) \n" - " daddiu %0, %0, 32 \n" - " bnel %0, %1, 1b \n" - " pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%0) \n" - " daddiu %0, %0, -128 \n" -#endif - " sd $0, 0(%0) \n" /* Throw out a cacheline of 0's */ - "1: sd $0, 8(%0) \n" - " sd $0, 16(%0) \n" - " sd $0, 24(%0) \n" - " daddiu %0, %0, 32 \n" - " bnel %0, %1, 1b \n" - " sd $0, 0(%0) \n" - " .set pop \n" - : "+r" (addr) - : "r" (end) - : "memory"); -} - -static inline void copy_page_cpu(void *to, void *from) -{ - unsigned char *src = (unsigned char *)from; - unsigned char *dst = (unsigned char *)to; - unsigned char *end = src + PAGE_SIZE; - - /* - * The pref's used here are using "streaming" hints, which cause the - * copied data to be kicked out of the cache sooner. A page copy often - * ends up copying a lot more data than is commonly used, so this seems - * to make sense in terms of reducing cache pollution, but I've no real - * performance data to back this up - */ - __asm__ __volatile__( - " .set push \n" - " .set mips4 \n" - " .set noreorder \n" -#ifdef CONFIG_CPU_HAS_PREFETCH - " daddiu %0, %0, 128 \n" - " daddiu %1, %1, 128 \n" - " pref " SB1_PREF_LOAD_STREAMED_HINT ", -128(%0)\n" - /* Prefetch the first 4 lines */ - " pref " SB1_PREF_STORE_STREAMED_HINT ", -128(%1)\n" - " pref " SB1_PREF_LOAD_STREAMED_HINT ", -96(%0)\n" - " pref " SB1_PREF_STORE_STREAMED_HINT ", -96(%1)\n" - " pref " SB1_PREF_LOAD_STREAMED_HINT ", -64(%0)\n" - " pref " SB1_PREF_STORE_STREAMED_HINT ", -64(%1)\n" - " pref " SB1_PREF_LOAD_STREAMED_HINT ", -32(%0)\n" - "1: pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%1)\n" -# ifdef CONFIG_64BIT - " ld $8, -128(%0) \n" /* Block copy a cacheline */ - " ld $9, -120(%0) \n" - " ld $10, -112(%0) \n" - " ld $11, -104(%0) \n" - " sd $8, -128(%1) \n" - " sd $9, -120(%1) \n" - " sd $10, -112(%1) \n" - " sd $11, -104(%1) \n" -# else - " lw $2, -128(%0) \n" /* Block copy a cacheline */ - " lw $3, -124(%0) \n" - " lw $6, -120(%0) \n" - " lw $7, -116(%0) \n" - " lw $8, -112(%0) \n" - " lw $9, -108(%0) \n" - " lw $10, -104(%0) \n" - " lw $11, -100(%0) \n" - " sw $2, -128(%1) \n" - " sw $3, -124(%1) \n" - " sw $6, -120(%1) \n" - " sw $7, -116(%1) \n" - " sw $8, -112(%1) \n" - " sw $9, -108(%1) \n" - " sw $10, -104(%1) \n" - " sw $11, -100(%1) \n" -# endif - " daddiu %0, %0, 32 \n" - " daddiu %1, %1, 32 \n" - " bnel %0, %2, 1b \n" - " pref " SB1_PREF_LOAD_STREAMED_HINT ", -32(%0)\n" - " daddiu %0, %0, -128 \n" - " daddiu %1, %1, -128 \n" -#endif -#ifdef CONFIG_64BIT - " ld $8, 0(%0) \n" /* Block copy a cacheline */ - "1: ld $9, 8(%0) \n" - " ld $10, 16(%0) \n" - " ld $11, 24(%0) \n" - " sd $8, 0(%1) \n" - " sd $9, 8(%1) \n" - " sd $10, 16(%1) \n" - " sd $11, 24(%1) \n" -#else - " lw $2, 0(%0) \n" /* Block copy a cacheline */ - "1: lw $3, 4(%0) \n" - " lw $6, 8(%0) \n" - " lw $7, 12(%0) \n" - " lw $8, 16(%0) \n" - " lw $9, 20(%0) \n" - " lw $10, 24(%0) \n" - " lw $11, 28(%0) \n" - " sw $2, 0(%1) \n" - " sw $3, 4(%1) \n" - " sw $6, 8(%1) \n" - " sw $7, 12(%1) \n" - " sw $8, 16(%1) \n" - " sw $9, 20(%1) \n" - " sw $10, 24(%1) \n" - " sw $11, 28(%1) \n" -#endif - " daddiu %0, %0, 32 \n" - " daddiu %1, %1, 32 \n" - " bnel %0, %2, 1b \n" -#ifdef CONFIG_64BIT - " ld $8, 0(%0) \n" -#else - " lw $2, 0(%0) \n" -#endif - " .set pop \n" - : "+r" (src), "+r" (dst) - : "r" (end) -#ifdef CONFIG_64BIT - : "$8", "$9", "$10", "$11", "memory"); -#else - : "$2", "$3", "$6", "$7", "$8", "$9", "$10", "$11", "memory"); -#endif -} - - -#ifdef CONFIG_SIBYTE_DMA_PAGEOPS - -/* - * Pad descriptors to cacheline, since each is exclusively owned by a - * particular CPU. - */ -typedef struct dmadscr_s { - u64 dscr_a; - u64 dscr_b; - u64 pad_a; - u64 pad_b; -} dmadscr_t; - -static dmadscr_t page_descr[DM_NUM_CHANNELS] - __attribute__((aligned(SMP_CACHE_BYTES))); - -void sb1_dma_init(void) -{ - int i; - - for (i = 0; i < DM_NUM_CHANNELS; 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)); - - __raw_writeq(base_val, base_reg); - __raw_writeq(base_val | M_DM_DSCR_BASE_RESET, base_reg); - __raw_writeq(base_val | M_DM_DSCR_BASE_ENABL, base_reg); - } -} - -void clear_page(void *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((unsigned long)page) != (long)CKSEG0) - return clear_page_cpu(page); - - page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_ZERO_MEM | - M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT; - page_descr[cpu].dscr_b = V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE); - __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT))); - - /* - * Don't really want to do it this way, but there's no - * reliable way to delay completion detection. - */ - while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG))) - & M_DM_DSCR_BASE_INTERRUPT)) - ; - __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE))); -} - -void copy_page(void *to, void *from) -{ - 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((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 | - M_DM_DSCRA_INTERRUPT; - page_descr[cpu].dscr_b = from_phys | V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE); - __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT))); - - /* - * Don't really want to do it this way, but there's no - * reliable way to delay completion detection. - */ - while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG))) - & M_DM_DSCR_BASE_INTERRUPT)) - ; - __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE))); -} - -#else /* !CONFIG_SIBYTE_DMA_PAGEOPS */ - -void clear_page(void *page) -{ - return clear_page_cpu(page); -} - -void copy_page(void *to, void *from) -{ - return copy_page_cpu(to, from); -} - -#endif /* !CONFIG_SIBYTE_DMA_PAGEOPS */ - -EXPORT_SYMBOL(clear_page); -EXPORT_SYMBOL(copy_page); - -void __cpuinit build_clear_page(void) -{ -} - -void __cpuinit build_copy_page(void) -{ -} diff --git a/arch/mips/mm/pgtable.c b/arch/mips/mm/pgtable.c index 57df1c38e30..7dfa579ab24 100644 --- a/arch/mips/mm/pgtable.c +++ b/arch/mips/mm/pgtable.c @@ -12,7 +12,6 @@ void show_mem(void) printk("Mem-info:\n"); show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); pfn = max_mapnr; while (pfn-- > 0) { if (!pfn_valid(pfn)) diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 63065d6e806..5ce2fa74562 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -299,7 +299,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) idx = read_c0_index(); ptep = pte_offset_map(pmdp, address); -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) +#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) write_c0_entrylo0(ptep->pte_high); ptep++; write_c0_entrylo1(ptep->pte_high); diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index 1a6f7704cc8..1655aa69e13 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c @@ -58,13 +58,13 @@ enum opcode { insn_invalid, insn_addu, insn_addiu, insn_and, insn_andi, insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, - insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0, - insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, - insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld, - insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0, - insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll, - insn_sra, insn_srl, insn_subu, insn_sw, insn_tlbp, insn_tlbwi, - insn_tlbwr, insn_xor, insn_xori + insn_bne, insn_cache, insn_daddu, insn_daddiu, insn_dmfc0, + insn_dmtc0, insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, + insn_dsrl32, insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, + insn_ld, insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, + insn_mtc0, insn_ori, insn_pref, insn_rfe, insn_sc, insn_scd, + insn_sd, insn_sll, insn_sra, insn_srl, insn_subu, insn_sw, + insn_tlbp, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori }; struct insn { @@ -94,6 +94,7 @@ static struct insn insn_table[] __cpuinitdata = { { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM }, { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM }, { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, + { insn_cache, M(cache_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD }, { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET}, @@ -116,6 +117,7 @@ static struct insn insn_table[] __cpuinitdata = { { insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET}, { insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET}, { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, + { insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 }, { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, @@ -337,6 +339,7 @@ I_u1s2(_bgezl) I_u1s2(_bltz) I_u1s2(_bltzl) I_u1u2s3(_bne) +I_u2s3u1(_cache) I_u1u2u3(_dmfc0) I_u1u2u3(_dmtc0) I_u2u1s3(_daddiu) @@ -359,6 +362,7 @@ I_u2s3u1(_lw) I_u1u2u3(_mfc0) I_u1u2u3(_mtc0) I_u2u1u3(_ori) +I_u2s3u1(_pref) I_0(_rfe) I_u2s3u1(_sc) I_u2s3u1(_scd) @@ -555,6 +559,14 @@ uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) } void __cpuinit +uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1, + unsigned int reg2, int lid) +{ + uasm_r_mips_pc16(r, *p, lid); + uasm_i_bne(p, reg1, reg2, 0); +} + +void __cpuinit uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) { uasm_r_mips_pc16(r, *p, lid); diff --git a/arch/mips/mm/uasm.h b/arch/mips/mm/uasm.h index fe0574f6e77..0d6a66f3203 100644 --- a/arch/mips/mm/uasm.h +++ b/arch/mips/mm/uasm.h @@ -55,6 +55,7 @@ Ip_u1s2(_bgezl); Ip_u1s2(_bltz); Ip_u1s2(_bltzl); Ip_u1u2s3(_bne); +Ip_u2s3u1(_cache); Ip_u1u2u3(_dmfc0); Ip_u1u2u3(_dmtc0); Ip_u2u1s3(_daddiu); @@ -77,6 +78,7 @@ Ip_u2s3u1(_lw); Ip_u1u2u3(_mfc0); Ip_u1u2u3(_mtc0); Ip_u2u1u3(_ori); +Ip_u2s3u1(_pref); Ip_0(_rfe); Ip_u2s3u1(_sc); Ip_u2s3u1(_scd); @@ -177,6 +179,8 @@ void uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); void uasm_il_b(u32 **p, struct uasm_reloc **r, int lid); void uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); void uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); +void uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1, + unsigned int reg2, int lid); void uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); diff --git a/arch/mips/philips/pnx8550/common/Makefile b/arch/mips/nxp/pnx8550/common/Makefile index 31cc1a5cec3..31cc1a5cec3 100644 --- a/arch/mips/philips/pnx8550/common/Makefile +++ b/arch/mips/nxp/pnx8550/common/Makefile diff --git a/arch/mips/philips/pnx8550/common/gdb_hook.c b/arch/mips/nxp/pnx8550/common/gdb_hook.c index ad4624f6d9b..ad4624f6d9b 100644 --- a/arch/mips/philips/pnx8550/common/gdb_hook.c +++ b/arch/mips/nxp/pnx8550/common/gdb_hook.c diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/nxp/pnx8550/common/int.c index aad03429a5e..aad03429a5e 100644 --- a/arch/mips/philips/pnx8550/common/int.c +++ b/arch/mips/nxp/pnx8550/common/int.c diff --git a/arch/mips/philips/pnx8550/common/pci.c b/arch/mips/nxp/pnx8550/common/pci.c index eee4f3dfc41..eee4f3dfc41 100644 --- a/arch/mips/philips/pnx8550/common/pci.c +++ b/arch/mips/nxp/pnx8550/common/pci.c diff --git a/arch/mips/philips/pnx8550/common/platform.c b/arch/mips/nxp/pnx8550/common/platform.c index c839436bd01..c7c763dbe58 100644 --- a/arch/mips/philips/pnx8550/common/platform.c +++ b/arch/mips/nxp/pnx8550/common/platform.c @@ -1,5 +1,5 @@ /* - * Platform device support for Philips PNX8550 SoCs + * Platform device support for NXP PNX8550 SoCs * * Copyright 2005, Embedded Alley Solutions, Inc * diff --git a/arch/mips/philips/pnx8550/common/proc.c b/arch/mips/nxp/pnx8550/common/proc.c index 18b125e3b65..18b125e3b65 100644 --- a/arch/mips/philips/pnx8550/common/proc.c +++ b/arch/mips/nxp/pnx8550/common/proc.c diff --git a/arch/mips/philips/pnx8550/common/prom.c b/arch/mips/nxp/pnx8550/common/prom.c index 2f567452e7a..2f567452e7a 100644 --- a/arch/mips/philips/pnx8550/common/prom.c +++ b/arch/mips/nxp/pnx8550/common/prom.c diff --git a/arch/mips/philips/pnx8550/common/reset.c b/arch/mips/nxp/pnx8550/common/reset.c index 7b2cbc5b2c7..7b2cbc5b2c7 100644 --- a/arch/mips/philips/pnx8550/common/reset.c +++ b/arch/mips/nxp/pnx8550/common/reset.c diff --git a/arch/mips/philips/pnx8550/common/setup.c b/arch/mips/nxp/pnx8550/common/setup.c index 92d764c9770..92d764c9770 100644 --- a/arch/mips/philips/pnx8550/common/setup.c +++ b/arch/mips/nxp/pnx8550/common/setup.c diff --git a/arch/mips/philips/pnx8550/common/time.c b/arch/mips/nxp/pnx8550/common/time.c index 62f495b57f9..62f495b57f9 100644 --- a/arch/mips/philips/pnx8550/common/time.c +++ b/arch/mips/nxp/pnx8550/common/time.c diff --git a/arch/mips/philips/pnx8550/jbs/Makefile b/arch/mips/nxp/pnx8550/jbs/Makefile index e8228dbca8f..ad6a8ca7d8c 100644 --- a/arch/mips/philips/pnx8550/jbs/Makefile +++ b/arch/mips/nxp/pnx8550/jbs/Makefile @@ -1,4 +1,4 @@ -# Makefile for the Philips JBS Board. +# Makefile for the NXP JBS Board. lib-y := init.o board_setup.o irqmap.o diff --git a/arch/mips/philips/pnx8550/jbs/board_setup.c b/arch/mips/nxp/pnx8550/jbs/board_setup.c index f92826e0096..f92826e0096 100644 --- a/arch/mips/philips/pnx8550/jbs/board_setup.c +++ b/arch/mips/nxp/pnx8550/jbs/board_setup.c diff --git a/arch/mips/philips/pnx8550/jbs/init.c b/arch/mips/nxp/pnx8550/jbs/init.c index 90b4d35f3ec..d59b4a4e5e8 100644 --- a/arch/mips/philips/pnx8550/jbs/init.c +++ b/arch/mips/nxp/pnx8550/jbs/init.c @@ -40,7 +40,7 @@ extern char *prom_getenv(char *envname); const char *get_system_type(void) { - return "Philips PNX8550/JBS"; + return "NXP PNX8550/JBS"; } void __init prom_init(void) diff --git a/arch/mips/philips/pnx8550/jbs/irqmap.c b/arch/mips/nxp/pnx8550/jbs/irqmap.c index 98c3429e6e5..7fc89842002 100644 --- a/arch/mips/philips/pnx8550/jbs/irqmap.c +++ b/arch/mips/nxp/pnx8550/jbs/irqmap.c @@ -1,5 +1,5 @@ /* - * Philips JBS board irqmap. + * NXP JBS board irqmap. * * Copyright 2005 Embedded Alley Solutions, Inc * source@embeddealley.com @@ -33,4 +33,3 @@ char pnx8550_irq_tab[][5] __initdata = { [9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, [17] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, }; - diff --git a/arch/mips/philips/pnx8550/stb810/Makefile b/arch/mips/nxp/pnx8550/stb810/Makefile index f14b592af39..ab91d72c566 100644 --- a/arch/mips/philips/pnx8550/stb810/Makefile +++ b/arch/mips/nxp/pnx8550/stb810/Makefile @@ -1,4 +1,4 @@ -# Makefile for the Philips STB810 Board. +# Makefile for the NXP STB810 Board. lib-y := prom_init.o board_setup.o irqmap.o diff --git a/arch/mips/philips/pnx8550/stb810/board_setup.c b/arch/mips/nxp/pnx8550/stb810/board_setup.c index 345d71e53cf..1282c27cfcb 100644 --- a/arch/mips/philips/pnx8550/stb810/board_setup.c +++ b/arch/mips/nxp/pnx8550/stb810/board_setup.c @@ -1,7 +1,7 @@ /* * STB810 specific board startup routines. * - * Based on the arch/mips/philips/pnx8550/jbs/board_setup.c + * Based on the arch/mips/nxp/pnx8550/jbs/board_setup.c * * Author: MontaVista Software, Inc. * source@mvista.com diff --git a/arch/mips/philips/pnx8550/stb810/irqmap.c b/arch/mips/nxp/pnx8550/stb810/irqmap.c index 5ee11e19975..8c034963ddc 100644 --- a/arch/mips/philips/pnx8550/stb810/irqmap.c +++ b/arch/mips/nxp/pnx8550/stb810/irqmap.c @@ -1,5 +1,5 @@ /* - * Philips STB810 board irqmap. + * NXP STB810 board irqmap. * * Author: MontaVista Software, Inc. * source@mvista.com @@ -20,4 +20,3 @@ char pnx8550_irq_tab[][5] __initdata = { [9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, [10] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, }; - diff --git a/arch/mips/philips/pnx8550/stb810/prom_init.c b/arch/mips/nxp/pnx8550/stb810/prom_init.c index 832dd60b0a7..ca7f4ada064 100644 --- a/arch/mips/philips/pnx8550/stb810/prom_init.c +++ b/arch/mips/nxp/pnx8550/stb810/prom_init.c @@ -28,7 +28,7 @@ extern char *prom_getenv(char *envname); const char *get_system_type(void) { - return "Philips PNX8550/STB810"; + return "NXP PNX8950/STB810"; } void __init prom_init(void) diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index aa52aa146ce..b5f6f71b27b 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -80,6 +80,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) case CPU_24K: case CPU_25KF: case CPU_34K: + case CPU_1004K: case CPU_74K: case CPU_SB1: case CPU_SB1A: diff --git a/arch/mips/oprofile/op_impl.h b/arch/mips/oprofile/op_impl.h index fa6b4aae752..2bfc17c3010 100644 --- a/arch/mips/oprofile/op_impl.h +++ b/arch/mips/oprofile/op_impl.h @@ -10,7 +10,6 @@ #ifndef OP_IMPL_H #define OP_IMPL_H 1 -extern int null_perf_irq(void); extern int (*perf_irq)(void); /* Per-counter configuration as set via oprofilefs. */ diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index ccbea229a0e..da8cbb6899d 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -31,9 +31,14 @@ #define M_COUNTER_OVERFLOW (1UL << 31) +static int (*save_perf_irq)(void); + #ifdef CONFIG_MIPS_MT_SMP -#define WHAT (M_TC_EN_VPE | M_PERFCTL_VPEID(smp_processor_id())) -#define vpe_id() smp_processor_id() +static int cpu_has_mipsmt_pertccounters; +#define WHAT (M_TC_EN_VPE | \ + M_PERFCTL_VPEID(cpu_data[smp_processor_id()].vpe_id)) +#define vpe_id() (cpu_has_mipsmt_pertccounters ? \ + 0 : cpu_data[smp_processor_id()].vpe_id) /* * The number of bits to shift to convert between counters per core and @@ -243,11 +248,11 @@ static inline int __n_counters(void) { if (!(read_c0_config1() & M_CONFIG1_PC)) return 0; - if (!(r_c0_perfctrl0() & M_PERFCTL_MORE)) + if (!(read_c0_perfctrl0() & M_PERFCTL_MORE)) return 1; - if (!(r_c0_perfctrl1() & M_PERFCTL_MORE)) + if (!(read_c0_perfctrl1() & M_PERFCTL_MORE)) return 2; - if (!(r_c0_perfctrl2() & M_PERFCTL_MORE)) + if (!(read_c0_perfctrl2() & M_PERFCTL_MORE)) return 3; return 4; @@ -274,8 +279,9 @@ static inline int n_counters(void) return counters; } -static inline void reset_counters(int counters) +static void reset_counters(void *arg) { + int counters = (int)arg; switch (counters) { case 4: w_c0_perfctrl3(0); @@ -302,9 +308,12 @@ static int __init mipsxx_init(void) return -ENODEV; } - reset_counters(counters); - - counters = counters_total_to_per_cpu(counters); +#ifdef CONFIG_MIPS_MT_SMP + cpu_has_mipsmt_pertccounters = read_c0_config7() & (1<<19); + if (!cpu_has_mipsmt_pertccounters) + counters = counters_total_to_per_cpu(counters); +#endif + on_each_cpu(reset_counters, (void *)counters, 0, 1); op_model_mipsxx_ops.num_counters = counters; switch (current_cpu_type()) { @@ -320,6 +329,13 @@ static int __init mipsxx_init(void) op_model_mipsxx_ops.cpu_type = "mips/25K"; break; + case CPU_1004K: +#if 0 + /* FIXME: report as 34K for now */ + op_model_mipsxx_ops.cpu_type = "mips/1004K"; + break; +#endif + case CPU_34K: op_model_mipsxx_ops.cpu_type = "mips/34K"; break; @@ -355,6 +371,7 @@ static int __init mipsxx_init(void) return -ENODEV; } + save_perf_irq = perf_irq; perf_irq = mipsxx_perfcount_handler; return 0; @@ -365,9 +382,9 @@ static void mipsxx_exit(void) int counters = op_model_mipsxx_ops.num_counters; counters = counters_per_cpu_to_total(counters); - reset_counters(counters); + on_each_cpu(reset_counters, (void *)counters, 0, 1); - perf_irq = null_perf_irq; + perf_irq = save_perf_irq; } struct op_mips_model op_model_mipsxx_ops = { diff --git a/arch/mips/pci/fixup-au1000.c b/arch/mips/pci/fixup-au1000.c index ca0276c8070..00c36c9dbe0 100644 --- a/arch/mips/pci/fixup-au1000.c +++ b/arch/mips/pci/fixup-au1000.c @@ -26,13 +26,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/types.h> + #include <linux/pci.h> -#include <linux/kernel.h> #include <linux/init.h> -#include <asm/mach-au1x00/au1000.h> - extern char irq_tab_alchemy[][5]; int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) diff --git a/arch/mips/pci/ops-pnx8550.c b/arch/mips/pci/ops-pnx8550.c index d6106465249..0e160d9f07c 100644 --- a/arch/mips/pci/ops-pnx8550.c +++ b/arch/mips/pci/ops-pnx8550.c @@ -90,14 +90,14 @@ config_access(unsigned int pci_cmd, struct pci_bus *bus, unsigned int devfn, int loops--; if (loops == 0) { - printk("%s : Arbiter Locked.\n", __FUNCTION__); + printk("%s : Arbiter Locked.\n", __func__); } } clear_status(); if ((pci_cmd == PCI_CMD_IOR) || (pci_cmd == PCI_CMD_IOW)) { printk("%s timeout (GPPM_CTRL=%X) ioaddr %lX pci_cmd %X\n", - __FUNCTION__, inl(PCI_BASE | PCI_GPPM_CTRL), ioaddr, + __func__, inl(PCI_BASE | PCI_GPPM_CTRL), ioaddr, pci_cmd); } diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c index 624bbdbff2a..b6cab089561 100644 --- a/arch/mips/sgi-ip32/ip32-reset.c +++ b/arch/mips/sgi-ip32/ip32-reset.c @@ -142,7 +142,7 @@ static irqreturn_t ip32_rtc_int(int irq, void *dev_id) reg_c = CMOS_READ(RTC_INTR_FLAGS); if (!(reg_c & RTC_IRQF)) { printk(KERN_WARNING - "%s: RTC IRQ without RTC_IRQF\n", __FUNCTION__); + "%s: RTC IRQ without RTC_IRQF\n", __func__); } /* Wait until interrupt goes away */ disable_irq(MACEISA_RTC_IRQ); diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c index 3f808b62924..6d31f2a98ab 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c @@ -173,7 +173,7 @@ static const u32 toshiba_rbtx4927_irq_debug_flag = { \ char tmp[100]; \ sprintf( tmp, str ); \ - printk( "%s(%s:%u)::%s", __FUNCTION__, __FILE__, __LINE__, tmp ); \ + printk( "%s(%s:%u)::%s", __func__, __FILE__, __LINE__, tmp ); \ } #else #define TOSHIBA_RBTX4927_IRQ_DPRINTK(flag, str...) diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c index e466e5e711d..2203c77b2ce 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c @@ -93,7 +93,7 @@ static const u32 toshiba_rbtx4927_setup_debug_flag = { \ char tmp[100]; \ sprintf( tmp, str ); \ - printk( "%s(%s:%u)::%s", __FUNCTION__, __FILE__, __LINE__, tmp ); \ + printk( "%s(%s:%u)::%s", __func__, __FILE__, __LINE__, tmp ); \ } #else #define TOSHIBA_RBTX4927_SETUP_DPRINTK(flag, str...) diff --git a/arch/mips/tx4938/common/dbgio.c b/arch/mips/tx4938/common/dbgio.c index bea59ff1842..33b9c672a32 100644 --- a/arch/mips/tx4938/common/dbgio.c +++ b/arch/mips/tx4938/common/dbgio.c @@ -31,9 +31,7 @@ * Support for TX4938 in 2.6 - Hiroshi DOYU <Hiroshi_DOYU@montavista.co.jp> */ -#include <asm/mipsregs.h> -#include <asm/system.h> -#include <asm/tx4938/tx4938_mips.h> +#include <linux/types> extern u8 txx9_sio_kdbg_rd(void); extern int txx9_sio_kdbg_wr( u8 ch ); diff --git a/arch/mips/tx4938/common/prom.c b/arch/mips/tx4938/common/prom.c index 3189a65f7d7..20baeaeba4c 100644 --- a/arch/mips/tx4938/common/prom.c +++ b/arch/mips/tx4938/common/prom.c @@ -13,13 +13,8 @@ */ #include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/bootmem.h> - -#include <asm/addrspace.h> -#include <asm/bootinfo.h> -#include <asm/tx4938/tx4938.h> +#include <linux/types.h> +#include <linux/io.h> static unsigned int __init tx4938_process_sdccr(u64 * addr) @@ -35,7 +30,7 @@ tx4938_process_sdccr(u64 * addr) unsigned int bc = 4; unsigned int msize = 0; - val = (*((vu64 *) (addr))); + val = ____raw_readq((void __iomem *)addr); /* MVMCP -- need #defs for these bits masks */ sdccr_ce = ((val & (1 << 10)) >> 10); diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c index f00185017e8..4d6a8dc46c7 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c @@ -67,24 +67,7 @@ IRQ Device 63 RBTX4938-IOC/07 SWINT */ #include <linux/init.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/swap.h> -#include <linux/ioport.h> -#include <linux/sched.h> #include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/timex.h> -#include <asm/bootinfo.h> -#include <asm/page.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/processor.h> -#include <asm/reboot.h> -#include <asm/time.h> -#include <asm/wbflush.h> -#include <linux/bootmem.h> #include <asm/tx4938/rbtx4938.h> static void toshiba_rbtx4938_irq_ioc_enable(unsigned int irq); @@ -99,21 +82,16 @@ static struct irq_chip toshiba_rbtx4938_irq_ioc_type = { .unmask = toshiba_rbtx4938_irq_ioc_enable, }; -#define TOSHIBA_RBTX4938_IOC_INTR_ENAB 0xb7f02000 -#define TOSHIBA_RBTX4938_IOC_INTR_STAT 0xb7f0200a - int toshiba_rbtx4938_irq_nested(int sw_irq) { u8 level3; - level3 = reg_rd08(TOSHIBA_RBTX4938_IOC_INTR_STAT) & 0xff; - if (level3) { + level3 = readb(rbtx4938_imstat_addr); + if (level3) /* must use fls so onboard ATA has priority */ sw_irq = TOSHIBA_RBTX4938_IRQ_IOC_BEG + fls(level3) - 1; - } - wbflush(); return sw_irq; } @@ -144,25 +122,23 @@ toshiba_rbtx4938_irq_ioc_init(void) static void toshiba_rbtx4938_irq_ioc_enable(unsigned int irq) { - volatile unsigned char v; + unsigned char v; - v = TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); + v = readb(rbtx4938_imask_addr); v |= (1 << (irq - TOSHIBA_RBTX4938_IRQ_IOC_BEG)); - TX4938_WR08(TOSHIBA_RBTX4938_IOC_INTR_ENAB, v); + writeb(v, rbtx4938_imask_addr); mmiowb(); - TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); } static void toshiba_rbtx4938_irq_ioc_disable(unsigned int irq) { - volatile unsigned char v; + unsigned char v; - v = TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); + v = readb(rbtx4938_imask_addr); v &= ~(1 << (irq - TOSHIBA_RBTX4938_IRQ_IOC_BEG)); - TX4938_WR08(TOSHIBA_RBTX4938_IOC_INTR_ENAB, v); + writeb(v, rbtx4938_imask_addr); mmiowb(); - TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); } void __init arch_init_irq(void) @@ -174,14 +150,12 @@ void __init arch_init_irq(void) /* all IRC interrupt mode are Low Active. */ /* mask all IOC interrupts */ - *rbtx4938_imask_ptr = 0; + writeb(0, rbtx4938_imask_addr); /* clear SoftInt interrupts */ - *rbtx4938_softint_ptr = 0; + writeb(0, rbtx4938_softint_addr); tx4938_irq_init(); toshiba_rbtx4938_irq_ioc_init(); /* Onboard 10M Ether: High Active */ set_irq_type(RBTX4938_IRQ_ETHER, IRQF_TRIGGER_HIGH); - - wbflush(); } diff --git a/arch/mips/tx4938/toshiba_rbtx4938/setup.c b/arch/mips/tx4938/toshiba_rbtx4938/setup.c index 61249f049cd..3a3659e8633 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/setup.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/setup.c @@ -21,8 +21,8 @@ #include <linux/pm.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/gpio.h> -#include <asm/wbflush.h> #include <asm/reboot.h> #include <asm/time.h> #include <asm/txx9tmr.h> @@ -34,7 +34,7 @@ #endif #include <linux/spi/spi.h> #include <asm/tx4938/spi.h> -#include <asm/gpio.h> +#include <asm/txx9pio.h> extern char * __init prom_getcmdline(void); static inline void tx4938_report_pcic_status1(struct tx4938_pcic_reg *pcicptr); @@ -90,12 +90,11 @@ void rbtx4938_machine_restart(char *command) local_irq_disable(); printk("Rebooting..."); - *rbtx4938_softresetlock_ptr = 1; - *rbtx4938_sfvol_ptr = 1; - *rbtx4938_softreset_ptr = 1; - wbflush(); - - while(1); + writeb(1, rbtx4938_softresetlock_addr); + writeb(1, rbtx4938_sfvol_addr); + writeb(1, rbtx4938_softreset_addr); + while(1) + ; } void __init @@ -487,7 +486,7 @@ static int __init tx4938_pcibios_init(void) } /* Reset PCI Bus */ - *rbtx4938_pcireset_ptr = 0; + writeb(0, rbtx4938_pcireset_addr); /* Reset PCIC */ tx4938_ccfgptr->clkctr |= TX4938_CLKCTR_PCIRST; if (txboard_pci66_mode > 0) @@ -495,8 +494,8 @@ static int __init tx4938_pcibios_init(void) mdelay(10); /* clear PCIC reset */ tx4938_ccfgptr->clkctr &= ~TX4938_CLKCTR_PCIRST; - *rbtx4938_pcireset_ptr = 1; - wbflush(); + writeb(1, rbtx4938_pcireset_addr); + mmiowb(); tx4938_report_pcic_status1(tx4938_pcicptr); tx4938_report_pciclk(); @@ -504,15 +503,15 @@ static int __init tx4938_pcibios_init(void) if (txboard_pci66_mode == 0 && txboard_pci66_check(&tx4938_pci_controller[0], 0, 0)) { /* Reset PCI Bus */ - *rbtx4938_pcireset_ptr = 0; + writeb(0, rbtx4938_pcireset_addr); /* Reset PCIC */ tx4938_ccfgptr->clkctr |= TX4938_CLKCTR_PCIRST; tx4938_pciclk66_setup(); mdelay(10); /* clear PCIC reset */ tx4938_ccfgptr->clkctr &= ~TX4938_CLKCTR_PCIRST; - *rbtx4938_pcireset_ptr = 1; - wbflush(); + writeb(1, rbtx4938_pcireset_addr); + mmiowb(); /* Reinitialize PCIC */ tx4938_report_pciclk(); tx4938_pcic_setup(tx4938_pcicptr, &tx4938_pci_controller[0], io_base[0], extarb); @@ -615,9 +614,6 @@ static void __init rbtx4938_spi_setup(void) { /* set SPI_SEL */ tx4938_ccfgptr->pcfg |= TX4938_PCFG_SPI_SEL; - /* chip selects for SPI devices */ - tx4938_pioptr->dout |= (1 << SEEPROM1_CS); - tx4938_pioptr->dir |= (1 << SEEPROM1_CS); } static struct resource rbtx4938_fpga_resource; @@ -776,12 +772,13 @@ void __init tx4938_board_setup(void) txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL); /* enable DMA */ - TX4938_WR64(0xff1fb150, TX4938_DMA_MCR_MSTEN); - TX4938_WR64(0xff1fb950, TX4938_DMA_MCR_MSTEN); + for (i = 0; i < 2; i++) + ____raw_writeq(TX4938_DMA_MCR_MSTEN, + (void __iomem *)(TX4938_DMA_REG(i) + 0x50)); /* PIO */ - tx4938_pioptr->maskcpu = 0; - tx4938_pioptr->maskext = 0; + __raw_writel(0, &tx4938_pioptr->maskcpu); + __raw_writel(0, &tx4938_pioptr->maskext); /* TX4938 internal registers */ if (request_resource(&iomem_resource, &tx4938_reg_resource)) @@ -863,10 +860,6 @@ void __init plat_mem_setup(void) if (txx9_master_clock == 0) txx9_master_clock = 25000000; /* 25MHz */ tx4938_board_setup(); - /* setup serial stuff */ - TX4938_WR(0xff1ff314, 0x00000000); /* h/w flow control off */ - TX4938_WR(0xff1ff414, 0x00000000); /* h/w flow control off */ - #ifndef CONFIG_PCI set_io_port_base(RBTX4938_ETHER_BASE); #endif @@ -932,16 +925,16 @@ void __init plat_mem_setup(void) pcfg = tx4938_ccfgptr->pcfg; /* updated */ /* fixup piosel */ if ((pcfg & (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL)) == - TX4938_PCFG_ATA_SEL) { - *rbtx4938_piosel_ptr = (*rbtx4938_piosel_ptr & 0x03) | 0x04; - } + TX4938_PCFG_ATA_SEL) + writeb((readb(rbtx4938_piosel_addr) & 0x03) | 0x04, + rbtx4938_piosel_addr); else if ((pcfg & (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL)) == - TX4938_PCFG_NDF_SEL) { - *rbtx4938_piosel_ptr = (*rbtx4938_piosel_ptr & 0x03) | 0x08; - } - else { - *rbtx4938_piosel_ptr &= ~(0x08 | 0x04); - } + TX4938_PCFG_NDF_SEL) + writeb((readb(rbtx4938_piosel_addr) & 0x03) | 0x08, + rbtx4938_piosel_addr); + else + writeb(readb(rbtx4938_piosel_addr) & ~(0x08 | 0x04), + rbtx4938_piosel_addr); rbtx4938_fpga_resource.name = "FPGA Registers"; rbtx4938_fpga_resource.start = CPHYSADDR(RBTX4938_FPGA_REG_ADDR); @@ -950,17 +943,14 @@ void __init plat_mem_setup(void) if (request_resource(&iomem_resource, &rbtx4938_fpga_resource)) printk("request resource for fpga failed\n"); - /* disable all OnBoard I/O interrupts */ - *rbtx4938_imask_ptr = 0; - _machine_restart = rbtx4938_machine_restart; _machine_halt = rbtx4938_machine_halt; pm_power_off = rbtx4938_machine_power_off; - *rbtx4938_led_ptr = 0xff; - printk("RBTX4938 --- FPGA(Rev %02x)", *rbtx4938_fpga_rev_ptr); - printk(" DIPSW:%02x,%02x\n", - *rbtx4938_dipsw_ptr, *rbtx4938_bdipsw_ptr); + writeb(0xff, rbtx4938_led_addr); + printk(KERN_INFO "RBTX4938 --- FPGA(Rev %02x) DIPSW:%02x,%02x\n", + readb(rbtx4938_fpga_rev_addr), + readb(rbtx4938_dipsw_addr), readb(rbtx4938_bdipsw_addr)); } static int __init rbtx4938_ne_init(void) @@ -984,106 +974,48 @@ device_initcall(rbtx4938_ne_init); /* GPIO support */ -static DEFINE_SPINLOCK(rbtx4938_spi_gpio_lock); - -static void rbtx4938_spi_gpio_set(unsigned gpio, int value) +int gpio_to_irq(unsigned gpio) { - u8 val; - unsigned long flags; - gpio -= 16; - spin_lock_irqsave(&rbtx4938_spi_gpio_lock, flags); - val = *rbtx4938_spics_ptr; - if (value) - val |= 1 << gpio; - else - val &= ~(1 << gpio); - *rbtx4938_spics_ptr = val; - mmiowb(); - spin_unlock_irqrestore(&rbtx4938_spi_gpio_lock, flags); + return -EINVAL; } -static int rbtx4938_spi_gpio_dir_out(unsigned gpio, int value) +int irq_to_gpio(unsigned irq) { - rbtx4938_spi_gpio_set(gpio, value); - return 0; + return -EINVAL; } -static DEFINE_SPINLOCK(tx4938_gpio_lock); - -static int tx4938_gpio_get(unsigned gpio) -{ - return tx4938_pioptr->din & (1 << gpio); -} +static DEFINE_SPINLOCK(rbtx4938_spi_gpio_lock); -static void tx4938_gpio_set_raw(unsigned gpio, int value) +static void rbtx4938_spi_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { - u32 val; - val = tx4938_pioptr->dout; + u8 val; + unsigned long flags; + spin_lock_irqsave(&rbtx4938_spi_gpio_lock, flags); + val = readb(rbtx4938_spics_addr); if (value) - val |= 1 << gpio; + val |= 1 << offset; else - val &= ~(1 << gpio); - tx4938_pioptr->dout = val; -} - -static void tx4938_gpio_set(unsigned gpio, int value) -{ - unsigned long flags; - spin_lock_irqsave(&tx4938_gpio_lock, flags); - tx4938_gpio_set_raw(gpio, value); - mmiowb(); - spin_unlock_irqrestore(&tx4938_gpio_lock, flags); -} - -static int tx4938_gpio_dir_in(unsigned gpio) -{ - spin_lock_irq(&tx4938_gpio_lock); - tx4938_pioptr->dir &= ~(1 << gpio); + val &= ~(1 << offset); + writeb(val, rbtx4938_spics_addr); mmiowb(); - spin_unlock_irq(&tx4938_gpio_lock); - return 0; -} - -static int tx4938_gpio_dir_out(unsigned int gpio, int value) -{ - spin_lock_irq(&tx4938_gpio_lock); - tx4938_gpio_set_raw(gpio, value); - tx4938_pioptr->dir |= 1 << gpio; - mmiowb(); - spin_unlock_irq(&tx4938_gpio_lock); - return 0; -} - -int gpio_direction_input(unsigned gpio) -{ - if (gpio < 16) - return tx4938_gpio_dir_in(gpio); - return -EINVAL; -} - -int gpio_direction_output(unsigned gpio, int value) -{ - if (gpio < 16) - return tx4938_gpio_dir_out(gpio, value); - if (gpio < 16 + 3) - return rbtx4938_spi_gpio_dir_out(gpio, value); - return -EINVAL; + spin_unlock_irqrestore(&rbtx4938_spi_gpio_lock, flags); } -int gpio_get_value(unsigned gpio) +static int rbtx4938_spi_gpio_dir_out(struct gpio_chip *chip, + unsigned int offset, int value) { - if (gpio < 16) - return tx4938_gpio_get(gpio); + rbtx4938_spi_gpio_set(chip, offset, value); return 0; } -void gpio_set_value(unsigned gpio, int value) -{ - if (gpio < 16) - tx4938_gpio_set(gpio, value); - else - rbtx4938_spi_gpio_set(gpio, value); -} +static struct gpio_chip rbtx4938_spi_gpio_chip = { + .set = rbtx4938_spi_gpio_set, + .direction_output = rbtx4938_spi_gpio_dir_out, + .label = "RBTX4938-SPICS", + .base = 16, + .ngpio = 3, +}; /* SPI support */ @@ -1094,7 +1026,6 @@ static void __init txx9_spi_init(unsigned long base, int irq) .start = base, .end = base + 0x20 - 1, .flags = IORESOURCE_MEM, - .parent = &tx4938_reg_resource, }, { .start = irq, .flags = IORESOURCE_IRQ, @@ -1118,10 +1049,25 @@ static int __init rbtx4938_spi_init(void) spi_eeprom_register(SEEPROM1_CS); spi_eeprom_register(16 + SEEPROM2_CS); spi_eeprom_register(16 + SEEPROM3_CS); + gpio_request(16 + SRTC_CS, "rtc-rs5c348"); + gpio_direction_output(16 + SRTC_CS, 0); + gpio_request(SEEPROM1_CS, "seeprom1"); + gpio_direction_output(SEEPROM1_CS, 1); + gpio_request(16 + SEEPROM2_CS, "seeprom2"); + gpio_direction_output(16 + SEEPROM2_CS, 1); + gpio_request(16 + SEEPROM3_CS, "seeprom3"); + gpio_direction_output(16 + SEEPROM3_CS, 1); txx9_spi_init(TX4938_SPI_REG & 0xfffffffffULL, RBTX4938_IRQ_IRC_SPI); return 0; } -arch_initcall(rbtx4938_spi_init); + +static int __init rbtx4938_arch_init(void) +{ + txx9_gpio_init(TX4938_PIO_REG & 0xfffffffffULL, 0, 16); + gpiochip_add(&rbtx4938_spi_gpio_chip); + return rbtx4938_spi_init(); +} +arch_initcall(rbtx4938_arch_init); /* Watchdog support */ @@ -1131,7 +1077,6 @@ static int __init txx9_wdt_init(unsigned long base) .start = base, .end = base + 0x100 - 1, .flags = IORESOURCE_MEM, - .parent = &tx4938_reg_resource, }; struct platform_device *dev = platform_device_register_simple("txx9wdt", -1, &res, 1); |