diff options
62 files changed, 3432 insertions, 159 deletions
diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index 78439b8a83c4..7ff9b5492041 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | platforms += alchemy | 3 | platforms += alchemy |
| 4 | platforms += ar7 | 4 | platforms += ar7 |
| 5 | platforms += ath79 | ||
| 5 | platforms += bcm47xx | 6 | platforms += bcm47xx |
| 6 | platforms += bcm63xx | 7 | platforms += bcm63xx |
| 7 | platforms += cavium-octeon | 8 | platforms += cavium-octeon |
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index f489ec30e071..548e6cc3bc28 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
| @@ -21,6 +21,7 @@ config MIPS | |||
| 21 | select HAVE_DMA_API_DEBUG | 21 | select HAVE_DMA_API_DEBUG |
| 22 | select HAVE_GENERIC_HARDIRQS | 22 | select HAVE_GENERIC_HARDIRQS |
| 23 | select GENERIC_IRQ_PROBE | 23 | select GENERIC_IRQ_PROBE |
| 24 | select HAVE_ARCH_JUMP_LABEL | ||
| 24 | 25 | ||
| 25 | menu "Machine selection" | 26 | menu "Machine selection" |
| 26 | 27 | ||
| @@ -65,6 +66,22 @@ config AR7 | |||
| 65 | Support for the Texas Instruments AR7 System-on-a-Chip | 66 | Support for the Texas Instruments AR7 System-on-a-Chip |
| 66 | family: TNETD7100, 7200 and 7300. | 67 | family: TNETD7100, 7200 and 7300. |
| 67 | 68 | ||
| 69 | config ATH79 | ||
| 70 | bool "Atheros AR71XX/AR724X/AR913X based boards" | ||
| 71 | select ARCH_REQUIRE_GPIOLIB | ||
| 72 | select BOOT_RAW | ||
| 73 | select CEVT_R4K | ||
| 74 | select CSRC_R4K | ||
| 75 | select DMA_NONCOHERENT | ||
| 76 | select IRQ_CPU | ||
| 77 | select MIPS_MACHINE | ||
| 78 | select SYS_HAS_CPU_MIPS32_R2 | ||
| 79 | select SYS_HAS_EARLY_PRINTK | ||
| 80 | select SYS_SUPPORTS_32BIT_KERNEL | ||
| 81 | select SYS_SUPPORTS_BIG_ENDIAN | ||
| 82 | help | ||
| 83 | Support for the Atheros AR71XX/AR724X/AR913X SoCs. | ||
| 84 | |||
| 68 | config BCM47XX | 85 | config BCM47XX |
| 69 | bool "Broadcom BCM47XX based boards" | 86 | bool "Broadcom BCM47XX based boards" |
| 70 | select CEVT_R4K | 87 | select CEVT_R4K |
| @@ -717,6 +734,7 @@ config CAVIUM_OCTEON_REFERENCE_BOARD | |||
| 717 | endchoice | 734 | endchoice |
| 718 | 735 | ||
| 719 | source "arch/mips/alchemy/Kconfig" | 736 | source "arch/mips/alchemy/Kconfig" |
| 737 | source "arch/mips/ath79/Kconfig" | ||
| 720 | source "arch/mips/bcm63xx/Kconfig" | 738 | source "arch/mips/bcm63xx/Kconfig" |
| 721 | source "arch/mips/jazz/Kconfig" | 739 | source "arch/mips/jazz/Kconfig" |
| 722 | source "arch/mips/jz4740/Kconfig" | 740 | source "arch/mips/jz4740/Kconfig" |
| @@ -883,6 +901,9 @@ config MIPS_DISABLE_OBSOLETE_IDE | |||
| 883 | config SYNC_R4K | 901 | config SYNC_R4K |
| 884 | bool | 902 | bool |
| 885 | 903 | ||
| 904 | config MIPS_MACHINE | ||
| 905 | def_bool n | ||
| 906 | |||
| 886 | config NO_IOPORT | 907 | config NO_IOPORT |
| 887 | def_bool n | 908 | def_bool n |
| 888 | 909 | ||
| @@ -2400,4 +2421,20 @@ source "security/Kconfig" | |||
| 2400 | 2421 | ||
| 2401 | source "crypto/Kconfig" | 2422 | source "crypto/Kconfig" |
| 2402 | 2423 | ||
| 2424 | menuconfig VIRTUALIZATION | ||
| 2425 | bool "Virtualization" | ||
| 2426 | default n | ||
| 2427 | ---help--- | ||
| 2428 | Say Y here to get to see options for using your Linux host to run other | ||
| 2429 | operating systems inside virtual machines (guests). | ||
| 2430 | This option alone does not add any kernel code. | ||
| 2431 | |||
| 2432 | If you say N, all options in this submenu will be skipped and disabled. | ||
| 2433 | |||
| 2434 | if VIRTUALIZATION | ||
| 2435 | |||
| 2436 | source drivers/virtio/Kconfig | ||
| 2437 | |||
| 2438 | endif # VIRTUALIZATION | ||
| 2439 | |||
| 2403 | source "lib/Kconfig" | 2440 | source "lib/Kconfig" |
diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig new file mode 100644 index 000000000000..b05828260f7f --- /dev/null +++ b/arch/mips/ath79/Kconfig | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | if ATH79 | ||
| 2 | |||
| 3 | menu "Atheros AR71XX/AR724X/AR913X machine selection" | ||
| 4 | |||
| 5 | config ATH79_MACH_AP81 | ||
| 6 | bool "Atheros AP81 reference board" | ||
| 7 | select SOC_AR913X | ||
| 8 | select ATH79_DEV_AR913X_WMAC | ||
| 9 | select ATH79_DEV_GPIO_BUTTONS | ||
| 10 | select ATH79_DEV_LEDS_GPIO | ||
| 11 | select ATH79_DEV_SPI | ||
| 12 | help | ||
| 13 | Say 'Y' here if you want your kernel to support the | ||
| 14 | Atheros AP81 reference board. | ||
| 15 | |||
| 16 | config ATH79_MACH_PB44 | ||
| 17 | bool "Atheros PB44 reference board" | ||
| 18 | select SOC_AR71XX | ||
| 19 | select ATH79_DEV_GPIO_BUTTONS | ||
| 20 | select ATH79_DEV_LEDS_GPIO | ||
| 21 | select ATH79_DEV_SPI | ||
| 22 | help | ||
| 23 | Say 'Y' here if you want your kernel to support the | ||
| 24 | Atheros PB44 reference board. | ||
| 25 | |||
| 26 | endmenu | ||
| 27 | |||
| 28 | config SOC_AR71XX | ||
| 29 | def_bool n | ||
| 30 | |||
| 31 | config SOC_AR724X | ||
| 32 | def_bool n | ||
| 33 | |||
| 34 | config SOC_AR913X | ||
| 35 | def_bool n | ||
| 36 | |||
| 37 | config ATH79_DEV_AR913X_WMAC | ||
| 38 | depends on SOC_AR913X | ||
| 39 | def_bool n | ||
| 40 | |||
| 41 | config ATH79_DEV_GPIO_BUTTONS | ||
| 42 | def_bool n | ||
| 43 | |||
| 44 | config ATH79_DEV_LEDS_GPIO | ||
| 45 | def_bool n | ||
| 46 | |||
| 47 | config ATH79_DEV_SPI | ||
| 48 | def_bool n | ||
| 49 | |||
| 50 | endif | ||
diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile new file mode 100644 index 000000000000..c33d4653007c --- /dev/null +++ b/arch/mips/ath79/Makefile | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the Atheros AR71XX/AR724X/AR913X specific parts of the kernel | ||
| 3 | # | ||
| 4 | # Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | # Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify it | ||
| 8 | # under the terms of the GNU General Public License version 2 as published | ||
| 9 | # by the Free Software Foundation. | ||
| 10 | |||
| 11 | obj-y := prom.o setup.o irq.o common.o clock.o gpio.o | ||
| 12 | |||
| 13 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | ||
| 14 | |||
| 15 | # | ||
| 16 | # Devices | ||
| 17 | # | ||
| 18 | obj-y += dev-common.o | ||
| 19 | obj-$(CONFIG_ATH79_DEV_AR913X_WMAC) += dev-ar913x-wmac.o | ||
| 20 | obj-$(CONFIG_ATH79_DEV_GPIO_BUTTONS) += dev-gpio-buttons.o | ||
| 21 | obj-$(CONFIG_ATH79_DEV_LEDS_GPIO) += dev-leds-gpio.o | ||
| 22 | obj-$(CONFIG_ATH79_DEV_SPI) += dev-spi.o | ||
| 23 | |||
| 24 | # | ||
| 25 | # Machines | ||
| 26 | # | ||
| 27 | obj-$(CONFIG_ATH79_MACH_AP81) += mach-ap81.o | ||
| 28 | obj-$(CONFIG_ATH79_MACH_PB44) += mach-pb44.o | ||
diff --git a/arch/mips/ath79/Platform b/arch/mips/ath79/Platform new file mode 100644 index 000000000000..2bd663647d27 --- /dev/null +++ b/arch/mips/ath79/Platform | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | # | ||
| 2 | # Atheros AR71xx/AR724x/AR913x | ||
| 3 | # | ||
| 4 | |||
| 5 | platform-$(CONFIG_ATH79) += ath79/ | ||
| 6 | cflags-$(CONFIG_ATH79) += -I$(srctree)/arch/mips/include/asm/mach-ath79 | ||
| 7 | load-$(CONFIG_ATH79) = 0xffffffff80060000 | ||
diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c new file mode 100644 index 000000000000..680bde99a26c --- /dev/null +++ b/arch/mips/ath79/clock.c | |||
| @@ -0,0 +1,183 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X common routines | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License version 2 as published | ||
| 8 | * by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/err.h> | ||
| 15 | #include <linux/clk.h> | ||
| 16 | |||
| 17 | #include <asm/mach-ath79/ath79.h> | ||
| 18 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
| 19 | #include "common.h" | ||
| 20 | |||
| 21 | #define AR71XX_BASE_FREQ 40000000 | ||
| 22 | #define AR724X_BASE_FREQ 5000000 | ||
| 23 | #define AR913X_BASE_FREQ 5000000 | ||
| 24 | |||
| 25 | struct clk { | ||
| 26 | unsigned long rate; | ||
| 27 | }; | ||
| 28 | |||
| 29 | static struct clk ath79_ref_clk; | ||
| 30 | static struct clk ath79_cpu_clk; | ||
| 31 | static struct clk ath79_ddr_clk; | ||
| 32 | static struct clk ath79_ahb_clk; | ||
| 33 | static struct clk ath79_wdt_clk; | ||
| 34 | static struct clk ath79_uart_clk; | ||
| 35 | |||
| 36 | static void __init ar71xx_clocks_init(void) | ||
| 37 | { | ||
| 38 | u32 pll; | ||
| 39 | u32 freq; | ||
| 40 | u32 div; | ||
| 41 | |||
| 42 | ath79_ref_clk.rate = AR71XX_BASE_FREQ; | ||
| 43 | |||
| 44 | pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG); | ||
| 45 | |||
| 46 | div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1; | ||
| 47 | freq = div * ath79_ref_clk.rate; | ||
| 48 | |||
| 49 | div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1; | ||
| 50 | ath79_cpu_clk.rate = freq / div; | ||
| 51 | |||
| 52 | div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1; | ||
| 53 | ath79_ddr_clk.rate = freq / div; | ||
| 54 | |||
| 55 | div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2; | ||
| 56 | ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; | ||
| 57 | |||
| 58 | ath79_wdt_clk.rate = ath79_ahb_clk.rate; | ||
| 59 | ath79_uart_clk.rate = ath79_ahb_clk.rate; | ||
| 60 | } | ||
| 61 | |||
| 62 | static void __init ar724x_clocks_init(void) | ||
| 63 | { | ||
| 64 | u32 pll; | ||
| 65 | u32 freq; | ||
| 66 | u32 div; | ||
| 67 | |||
| 68 | ath79_ref_clk.rate = AR724X_BASE_FREQ; | ||
| 69 | pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG); | ||
| 70 | |||
| 71 | div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK); | ||
| 72 | freq = div * ath79_ref_clk.rate; | ||
| 73 | |||
| 74 | div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK); | ||
| 75 | freq *= div; | ||
| 76 | |||
| 77 | ath79_cpu_clk.rate = freq; | ||
| 78 | |||
| 79 | div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; | ||
| 80 | ath79_ddr_clk.rate = freq / div; | ||
| 81 | |||
| 82 | div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; | ||
| 83 | ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; | ||
| 84 | |||
| 85 | ath79_wdt_clk.rate = ath79_ahb_clk.rate; | ||
| 86 | ath79_uart_clk.rate = ath79_ahb_clk.rate; | ||
| 87 | } | ||
| 88 | |||
| 89 | static void __init ar913x_clocks_init(void) | ||
| 90 | { | ||
| 91 | u32 pll; | ||
| 92 | u32 freq; | ||
| 93 | u32 div; | ||
| 94 | |||
| 95 | ath79_ref_clk.rate = AR913X_BASE_FREQ; | ||
| 96 | pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG); | ||
| 97 | |||
| 98 | div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK); | ||
| 99 | freq = div * ath79_ref_clk.rate; | ||
| 100 | |||
| 101 | ath79_cpu_clk.rate = freq; | ||
| 102 | |||
| 103 | div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1; | ||
| 104 | ath79_ddr_clk.rate = freq / div; | ||
| 105 | |||
| 106 | div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2; | ||
| 107 | ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; | ||
| 108 | |||
| 109 | ath79_wdt_clk.rate = ath79_ahb_clk.rate; | ||
| 110 | ath79_uart_clk.rate = ath79_ahb_clk.rate; | ||
| 111 | } | ||
| 112 | |||
| 113 | void __init ath79_clocks_init(void) | ||
| 114 | { | ||
| 115 | if (soc_is_ar71xx()) | ||
| 116 | ar71xx_clocks_init(); | ||
| 117 | else if (soc_is_ar724x()) | ||
| 118 | ar724x_clocks_init(); | ||
| 119 | else if (soc_is_ar913x()) | ||
| 120 | ar913x_clocks_init(); | ||
| 121 | else | ||
| 122 | BUG(); | ||
| 123 | |||
| 124 | pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, " | ||
| 125 | "Ref:%lu.%03luMHz", | ||
| 126 | ath79_cpu_clk.rate / 1000000, | ||
| 127 | (ath79_cpu_clk.rate / 1000) % 1000, | ||
| 128 | ath79_ddr_clk.rate / 1000000, | ||
| 129 | (ath79_ddr_clk.rate / 1000) % 1000, | ||
| 130 | ath79_ahb_clk.rate / 1000000, | ||
| 131 | (ath79_ahb_clk.rate / 1000) % 1000, | ||
| 132 | ath79_ref_clk.rate / 1000000, | ||
| 133 | (ath79_ref_clk.rate / 1000) % 1000); | ||
| 134 | } | ||
| 135 | |||
| 136 | /* | ||
| 137 | * Linux clock API | ||
| 138 | */ | ||
| 139 | struct clk *clk_get(struct device *dev, const char *id) | ||
| 140 | { | ||
| 141 | if (!strcmp(id, "ref")) | ||
| 142 | return &ath79_ref_clk; | ||
| 143 | |||
| 144 | if (!strcmp(id, "cpu")) | ||
| 145 | return &ath79_cpu_clk; | ||
| 146 | |||
| 147 | if (!strcmp(id, "ddr")) | ||
| 148 | return &ath79_ddr_clk; | ||
| 149 | |||
| 150 | if (!strcmp(id, "ahb")) | ||
| 151 | return &ath79_ahb_clk; | ||
| 152 | |||
| 153 | if (!strcmp(id, "wdt")) | ||
| 154 | return &ath79_wdt_clk; | ||
| 155 | |||
| 156 | if (!strcmp(id, "uart")) | ||
| 157 | return &ath79_uart_clk; | ||
| 158 | |||
| 159 | return ERR_PTR(-ENOENT); | ||
| 160 | } | ||
| 161 | EXPORT_SYMBOL(clk_get); | ||
| 162 | |||
| 163 | int clk_enable(struct clk *clk) | ||
| 164 | { | ||
| 165 | return 0; | ||
| 166 | } | ||
| 167 | EXPORT_SYMBOL(clk_enable); | ||
| 168 | |||
| 169 | void clk_disable(struct clk *clk) | ||
| 170 | { | ||
| 171 | } | ||
| 172 | EXPORT_SYMBOL(clk_disable); | ||
| 173 | |||
| 174 | unsigned long clk_get_rate(struct clk *clk) | ||
| 175 | { | ||
| 176 | return clk->rate; | ||
| 177 | } | ||
| 178 | EXPORT_SYMBOL(clk_get_rate); | ||
| 179 | |||
| 180 | void clk_put(struct clk *clk) | ||
| 181 | { | ||
| 182 | } | ||
| 183 | EXPORT_SYMBOL(clk_put); | ||
diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c new file mode 100644 index 000000000000..58f60e722a03 --- /dev/null +++ b/arch/mips/ath79/common.c | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X common routines | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/types.h> | ||
| 15 | #include <linux/spinlock.h> | ||
| 16 | |||
| 17 | #include <asm/mach-ath79/ath79.h> | ||
| 18 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
| 19 | #include "common.h" | ||
| 20 | |||
| 21 | static DEFINE_SPINLOCK(ath79_device_reset_lock); | ||
| 22 | |||
| 23 | u32 ath79_cpu_freq; | ||
| 24 | EXPORT_SYMBOL_GPL(ath79_cpu_freq); | ||
| 25 | |||
| 26 | u32 ath79_ahb_freq; | ||
| 27 | EXPORT_SYMBOL_GPL(ath79_ahb_freq); | ||
| 28 | |||
| 29 | u32 ath79_ddr_freq; | ||
| 30 | EXPORT_SYMBOL_GPL(ath79_ddr_freq); | ||
| 31 | |||
| 32 | enum ath79_soc_type ath79_soc; | ||
| 33 | |||
| 34 | void __iomem *ath79_pll_base; | ||
| 35 | void __iomem *ath79_reset_base; | ||
| 36 | EXPORT_SYMBOL_GPL(ath79_reset_base); | ||
| 37 | void __iomem *ath79_ddr_base; | ||
| 38 | |||
| 39 | void ath79_ddr_wb_flush(u32 reg) | ||
| 40 | { | ||
| 41 | void __iomem *flush_reg = ath79_ddr_base + reg; | ||
| 42 | |||
| 43 | /* Flush the DDR write buffer. */ | ||
| 44 | __raw_writel(0x1, flush_reg); | ||
| 45 | while (__raw_readl(flush_reg) & 0x1) | ||
| 46 | ; | ||
| 47 | |||
| 48 | /* It must be run twice. */ | ||
| 49 | __raw_writel(0x1, flush_reg); | ||
| 50 | while (__raw_readl(flush_reg) & 0x1) | ||
| 51 | ; | ||
| 52 | } | ||
| 53 | EXPORT_SYMBOL_GPL(ath79_ddr_wb_flush); | ||
| 54 | |||
| 55 | void ath79_device_reset_set(u32 mask) | ||
| 56 | { | ||
| 57 | unsigned long flags; | ||
| 58 | u32 reg; | ||
| 59 | u32 t; | ||
| 60 | |||
| 61 | if (soc_is_ar71xx()) | ||
| 62 | reg = AR71XX_RESET_REG_RESET_MODULE; | ||
| 63 | else if (soc_is_ar724x()) | ||
| 64 | reg = AR724X_RESET_REG_RESET_MODULE; | ||
| 65 | else if (soc_is_ar913x()) | ||
| 66 | reg = AR913X_RESET_REG_RESET_MODULE; | ||
| 67 | else | ||
| 68 | BUG(); | ||
| 69 | |||
| 70 | spin_lock_irqsave(&ath79_device_reset_lock, flags); | ||
| 71 | t = ath79_reset_rr(reg); | ||
| 72 | ath79_reset_wr(reg, t | mask); | ||
| 73 | spin_unlock_irqrestore(&ath79_device_reset_lock, flags); | ||
| 74 | } | ||
| 75 | EXPORT_SYMBOL_GPL(ath79_device_reset_set); | ||
| 76 | |||
| 77 | void ath79_device_reset_clear(u32 mask) | ||
| 78 | { | ||
| 79 | unsigned long flags; | ||
| 80 | u32 reg; | ||
| 81 | u32 t; | ||
| 82 | |||
| 83 | if (soc_is_ar71xx()) | ||
| 84 | reg = AR71XX_RESET_REG_RESET_MODULE; | ||
| 85 | else if (soc_is_ar724x()) | ||
| 86 | reg = AR724X_RESET_REG_RESET_MODULE; | ||
| 87 | else if (soc_is_ar913x()) | ||
| 88 | reg = AR913X_RESET_REG_RESET_MODULE; | ||
| 89 | else | ||
| 90 | BUG(); | ||
| 91 | |||
| 92 | spin_lock_irqsave(&ath79_device_reset_lock, flags); | ||
| 93 | t = ath79_reset_rr(reg); | ||
| 94 | ath79_reset_wr(reg, t & ~mask); | ||
| 95 | spin_unlock_irqrestore(&ath79_device_reset_lock, flags); | ||
| 96 | } | ||
| 97 | EXPORT_SYMBOL_GPL(ath79_device_reset_clear); | ||
diff --git a/arch/mips/ath79/common.h b/arch/mips/ath79/common.h new file mode 100644 index 000000000000..561906c2345e --- /dev/null +++ b/arch/mips/ath79/common.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X common definitions | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * Parts of this file are based on Atheros' 2.6.15 BSP | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License version 2 as published | ||
| 11 | * by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef __ATH79_COMMON_H | ||
| 15 | #define __ATH79_COMMON_H | ||
| 16 | |||
| 17 | #include <linux/types.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | |||
| 20 | #define ATH79_MEM_SIZE_MIN (2 * 1024 * 1024) | ||
| 21 | #define ATH79_MEM_SIZE_MAX (128 * 1024 * 1024) | ||
| 22 | |||
| 23 | void ath79_clocks_init(void); | ||
| 24 | void ath79_ddr_wb_flush(unsigned int reg); | ||
| 25 | |||
| 26 | void ath79_gpio_function_enable(u32 mask); | ||
| 27 | void ath79_gpio_function_disable(u32 mask); | ||
| 28 | void ath79_gpio_function_setup(u32 set, u32 clear); | ||
| 29 | void ath79_gpio_init(void); | ||
| 30 | |||
| 31 | #endif /* __ATH79_COMMON_H */ | ||
diff --git a/arch/mips/ath79/dev-ar913x-wmac.c b/arch/mips/ath79/dev-ar913x-wmac.c new file mode 100644 index 000000000000..48f425a5ba28 --- /dev/null +++ b/arch/mips/ath79/dev-ar913x-wmac.c | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR913X SoC built-in WMAC device support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/init.h> | ||
| 13 | #include <linux/delay.h> | ||
| 14 | #include <linux/irq.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/ath9k_platform.h> | ||
| 17 | |||
| 18 | #include <asm/mach-ath79/ath79.h> | ||
| 19 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
| 20 | #include "dev-ar913x-wmac.h" | ||
| 21 | |||
| 22 | static struct ath9k_platform_data ar913x_wmac_data; | ||
| 23 | |||
| 24 | static struct resource ar913x_wmac_resources[] = { | ||
| 25 | { | ||
| 26 | .start = AR913X_WMAC_BASE, | ||
| 27 | .end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1, | ||
| 28 | .flags = IORESOURCE_MEM, | ||
| 29 | }, { | ||
| 30 | .start = ATH79_CPU_IRQ_IP2, | ||
| 31 | .end = ATH79_CPU_IRQ_IP2, | ||
| 32 | .flags = IORESOURCE_IRQ, | ||
| 33 | }, | ||
| 34 | }; | ||
| 35 | |||
| 36 | static struct platform_device ar913x_wmac_device = { | ||
| 37 | .name = "ath9k", | ||
| 38 | .id = -1, | ||
| 39 | .resource = ar913x_wmac_resources, | ||
| 40 | .num_resources = ARRAY_SIZE(ar913x_wmac_resources), | ||
| 41 | .dev = { | ||
| 42 | .platform_data = &ar913x_wmac_data, | ||
| 43 | }, | ||
| 44 | }; | ||
| 45 | |||
| 46 | void __init ath79_register_ar913x_wmac(u8 *cal_data) | ||
| 47 | { | ||
| 48 | if (cal_data) | ||
| 49 | memcpy(ar913x_wmac_data.eeprom_data, cal_data, | ||
| 50 | sizeof(ar913x_wmac_data.eeprom_data)); | ||
| 51 | |||
| 52 | /* reset the WMAC */ | ||
| 53 | ath79_device_reset_set(AR913X_RESET_AMBA2WMAC); | ||
| 54 | mdelay(10); | ||
| 55 | |||
| 56 | ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC); | ||
| 57 | mdelay(10); | ||
| 58 | |||
| 59 | platform_device_register(&ar913x_wmac_device); | ||
| 60 | } | ||
diff --git a/arch/mips/ath79/dev-ar913x-wmac.h b/arch/mips/ath79/dev-ar913x-wmac.h new file mode 100644 index 000000000000..579d562bbda8 --- /dev/null +++ b/arch/mips/ath79/dev-ar913x-wmac.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR913X SoC built-in WMAC device support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _ATH79_DEV_AR913X_WMAC_H | ||
| 13 | #define _ATH79_DEV_AR913X_WMAC_H | ||
| 14 | |||
| 15 | void ath79_register_ar913x_wmac(u8 *cal_data); | ||
| 16 | |||
| 17 | #endif /* _ATH79_DEV_AR913X_WMAC_H */ | ||
diff --git a/arch/mips/ath79/dev-common.c b/arch/mips/ath79/dev-common.c new file mode 100644 index 000000000000..3b82e325bebf --- /dev/null +++ b/arch/mips/ath79/dev-common.c | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X common devices | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * Parts of this file are based on Atheros' 2.6.15 BSP | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License version 2 as published | ||
| 11 | * by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/serial_8250.h> | ||
| 18 | #include <linux/clk.h> | ||
| 19 | #include <linux/err.h> | ||
| 20 | |||
| 21 | #include <asm/mach-ath79/ath79.h> | ||
| 22 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
| 23 | #include "common.h" | ||
| 24 | #include "dev-common.h" | ||
| 25 | |||
| 26 | static struct resource ath79_uart_resources[] = { | ||
| 27 | { | ||
| 28 | .start = AR71XX_UART_BASE, | ||
| 29 | .end = AR71XX_UART_BASE + AR71XX_UART_SIZE - 1, | ||
| 30 | .flags = IORESOURCE_MEM, | ||
| 31 | }, | ||
| 32 | }; | ||
| 33 | |||
| 34 | #define AR71XX_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP) | ||
| 35 | static struct plat_serial8250_port ath79_uart_data[] = { | ||
| 36 | { | ||
| 37 | .mapbase = AR71XX_UART_BASE, | ||
| 38 | .irq = ATH79_MISC_IRQ_UART, | ||
| 39 | .flags = AR71XX_UART_FLAGS, | ||
| 40 | .iotype = UPIO_MEM32, | ||
| 41 | .regshift = 2, | ||
| 42 | }, { | ||
| 43 | /* terminating entry */ | ||
| 44 | } | ||
| 45 | }; | ||
| 46 | |||
| 47 | static struct platform_device ath79_uart_device = { | ||
| 48 | .name = "serial8250", | ||
| 49 | .id = PLAT8250_DEV_PLATFORM, | ||
| 50 | .resource = ath79_uart_resources, | ||
| 51 | .num_resources = ARRAY_SIZE(ath79_uart_resources), | ||
| 52 | .dev = { | ||
| 53 | .platform_data = ath79_uart_data | ||
| 54 | }, | ||
| 55 | }; | ||
| 56 | |||
| 57 | void __init ath79_register_uart(void) | ||
| 58 | { | ||
| 59 | struct clk *clk; | ||
| 60 | |||
| 61 | clk = clk_get(NULL, "uart"); | ||
| 62 | if (IS_ERR(clk)) | ||
| 63 | panic("unable to get UART clock, err=%ld", PTR_ERR(clk)); | ||
| 64 | |||
| 65 | ath79_uart_data[0].uartclk = clk_get_rate(clk); | ||
| 66 | platform_device_register(&ath79_uart_device); | ||
| 67 | } | ||
| 68 | |||
| 69 | static struct platform_device ath79_wdt_device = { | ||
| 70 | .name = "ath79-wdt", | ||
| 71 | .id = -1, | ||
| 72 | }; | ||
| 73 | |||
| 74 | void __init ath79_register_wdt(void) | ||
| 75 | { | ||
| 76 | platform_device_register(&ath79_wdt_device); | ||
| 77 | } | ||
diff --git a/arch/mips/ath79/dev-common.h b/arch/mips/ath79/dev-common.h new file mode 100644 index 000000000000..0f514e1affce --- /dev/null +++ b/arch/mips/ath79/dev-common.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X common devices | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _ATH79_DEV_COMMON_H | ||
| 13 | #define _ATH79_DEV_COMMON_H | ||
| 14 | |||
| 15 | void ath79_register_uart(void); | ||
| 16 | void ath79_register_wdt(void); | ||
| 17 | |||
| 18 | #endif /* _ATH79_DEV_COMMON_H */ | ||
diff --git a/arch/mips/ath79/dev-gpio-buttons.c b/arch/mips/ath79/dev-gpio-buttons.c new file mode 100644 index 000000000000..4b0168a11c01 --- /dev/null +++ b/arch/mips/ath79/dev-gpio-buttons.c | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X GPIO button support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include "linux/init.h" | ||
| 13 | #include "linux/slab.h" | ||
| 14 | #include <linux/platform_device.h> | ||
| 15 | |||
| 16 | #include "dev-gpio-buttons.h" | ||
| 17 | |||
| 18 | void __init ath79_register_gpio_keys_polled(int id, | ||
| 19 | unsigned poll_interval, | ||
| 20 | unsigned nbuttons, | ||
| 21 | struct gpio_keys_button *buttons) | ||
| 22 | { | ||
| 23 | struct platform_device *pdev; | ||
| 24 | struct gpio_keys_platform_data pdata; | ||
| 25 | struct gpio_keys_button *p; | ||
| 26 | int err; | ||
| 27 | |||
| 28 | p = kmalloc(nbuttons * sizeof(*p), GFP_KERNEL); | ||
| 29 | if (!p) | ||
| 30 | return; | ||
| 31 | |||
| 32 | memcpy(p, buttons, nbuttons * sizeof(*p)); | ||
| 33 | |||
| 34 | pdev = platform_device_alloc("gpio-keys-polled", id); | ||
| 35 | if (!pdev) | ||
| 36 | goto err_free_buttons; | ||
| 37 | |||
| 38 | memset(&pdata, 0, sizeof(pdata)); | ||
| 39 | pdata.poll_interval = poll_interval; | ||
| 40 | pdata.nbuttons = nbuttons; | ||
| 41 | pdata.buttons = p; | ||
| 42 | |||
| 43 | err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); | ||
| 44 | if (err) | ||
| 45 | goto err_put_pdev; | ||
| 46 | |||
| 47 | err = platform_device_add(pdev); | ||
| 48 | if (err) | ||
| 49 | goto err_put_pdev; | ||
| 50 | |||
| 51 | return; | ||
| 52 | |||
| 53 | err_put_pdev: | ||
| 54 | platform_device_put(pdev); | ||
| 55 | |||
| 56 | err_free_buttons: | ||
| 57 | kfree(p); | ||
| 58 | } | ||
diff --git a/arch/mips/ath79/dev-gpio-buttons.h b/arch/mips/ath79/dev-gpio-buttons.h new file mode 100644 index 000000000000..481847ac1cba --- /dev/null +++ b/arch/mips/ath79/dev-gpio-buttons.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X GPIO button support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _ATH79_DEV_GPIO_BUTTONS_H | ||
| 13 | #define _ATH79_DEV_GPIO_BUTTONS_H | ||
| 14 | |||
| 15 | #include <linux/input.h> | ||
| 16 | #include <linux/gpio_keys.h> | ||
| 17 | |||
| 18 | void ath79_register_gpio_keys_polled(int id, | ||
| 19 | unsigned poll_interval, | ||
| 20 | unsigned nbuttons, | ||
| 21 | struct gpio_keys_button *buttons); | ||
| 22 | |||
| 23 | #endif /* _ATH79_DEV_GPIO_BUTTONS_H */ | ||
diff --git a/arch/mips/ath79/dev-leds-gpio.c b/arch/mips/ath79/dev-leds-gpio.c new file mode 100644 index 000000000000..cdade68dcd17 --- /dev/null +++ b/arch/mips/ath79/dev-leds-gpio.c | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X common GPIO LEDs support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/init.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/platform_device.h> | ||
| 15 | |||
| 16 | #include "dev-leds-gpio.h" | ||
| 17 | |||
| 18 | void __init ath79_register_leds_gpio(int id, | ||
| 19 | unsigned num_leds, | ||
| 20 | struct gpio_led *leds) | ||
| 21 | { | ||
| 22 | struct platform_device *pdev; | ||
| 23 | struct gpio_led_platform_data pdata; | ||
| 24 | struct gpio_led *p; | ||
| 25 | int err; | ||
| 26 | |||
| 27 | p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL); | ||
| 28 | if (!p) | ||
| 29 | return; | ||
| 30 | |||
| 31 | memcpy(p, leds, num_leds * sizeof(*p)); | ||
| 32 | |||
| 33 | pdev = platform_device_alloc("leds-gpio", id); | ||
| 34 | if (!pdev) | ||
| 35 | goto err_free_leds; | ||
| 36 | |||
| 37 | memset(&pdata, 0, sizeof(pdata)); | ||
| 38 | pdata.num_leds = num_leds; | ||
| 39 | pdata.leds = p; | ||
| 40 | |||
| 41 | err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); | ||
| 42 | if (err) | ||
| 43 | goto err_put_pdev; | ||
| 44 | |||
| 45 | err = platform_device_add(pdev); | ||
| 46 | if (err) | ||
| 47 | goto err_put_pdev; | ||
| 48 | |||
| 49 | return; | ||
| 50 | |||
| 51 | err_put_pdev: | ||
| 52 | platform_device_put(pdev); | ||
| 53 | |||
| 54 | err_free_leds: | ||
| 55 | kfree(p); | ||
| 56 | } | ||
diff --git a/arch/mips/ath79/dev-leds-gpio.h b/arch/mips/ath79/dev-leds-gpio.h new file mode 100644 index 000000000000..6e5d8851ebcf --- /dev/null +++ b/arch/mips/ath79/dev-leds-gpio.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X common GPIO LEDs support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _ATH79_DEV_LEDS_GPIO_H | ||
| 13 | #define _ATH79_DEV_LEDS_GPIO_H | ||
| 14 | |||
| 15 | #include <linux/leds.h> | ||
| 16 | |||
| 17 | void ath79_register_leds_gpio(int id, | ||
| 18 | unsigned num_leds, | ||
| 19 | struct gpio_led *leds); | ||
| 20 | |||
| 21 | #endif /* _ATH79_DEV_LEDS_GPIO_H */ | ||
diff --git a/arch/mips/ath79/dev-spi.c b/arch/mips/ath79/dev-spi.c new file mode 100644 index 000000000000..aa30163efbfd --- /dev/null +++ b/arch/mips/ath79/dev-spi.c | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X SPI controller device | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/platform_device.h> | ||
| 13 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
| 14 | #include "dev-spi.h" | ||
| 15 | |||
| 16 | static struct resource ath79_spi_resources[] = { | ||
| 17 | { | ||
| 18 | .start = AR71XX_SPI_BASE, | ||
| 19 | .end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1, | ||
| 20 | .flags = IORESOURCE_MEM, | ||
| 21 | }, | ||
| 22 | }; | ||
| 23 | |||
| 24 | static struct platform_device ath79_spi_device = { | ||
| 25 | .name = "ath79-spi", | ||
| 26 | .id = -1, | ||
| 27 | .resource = ath79_spi_resources, | ||
| 28 | .num_resources = ARRAY_SIZE(ath79_spi_resources), | ||
| 29 | }; | ||
| 30 | |||
| 31 | void __init ath79_register_spi(struct ath79_spi_platform_data *pdata, | ||
| 32 | struct spi_board_info const *info, | ||
| 33 | unsigned n) | ||
| 34 | { | ||
| 35 | spi_register_board_info(info, n); | ||
| 36 | ath79_spi_device.dev.platform_data = pdata; | ||
| 37 | platform_device_register(&ath79_spi_device); | ||
| 38 | } | ||
diff --git a/arch/mips/ath79/dev-spi.h b/arch/mips/ath79/dev-spi.h new file mode 100644 index 000000000000..d732565ca736 --- /dev/null +++ b/arch/mips/ath79/dev-spi.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X SPI controller device | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _ATH79_DEV_SPI_H | ||
| 13 | #define _ATH79_DEV_SPI_H | ||
| 14 | |||
| 15 | #include <linux/spi/spi.h> | ||
| 16 | #include <asm/mach-ath79/ath79_spi_platform.h> | ||
| 17 | |||
| 18 | void ath79_register_spi(struct ath79_spi_platform_data *pdata, | ||
| 19 | struct spi_board_info const *info, | ||
| 20 | unsigned n); | ||
| 21 | |||
| 22 | #endif /* _ATH79_DEV_SPI_H */ | ||
diff --git a/arch/mips/ath79/early_printk.c b/arch/mips/ath79/early_printk.c new file mode 100644 index 000000000000..7499b0e9df26 --- /dev/null +++ b/arch/mips/ath79/early_printk.c | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X SoC early printk support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/io.h> | ||
| 13 | #include <linux/serial_reg.h> | ||
| 14 | #include <asm/addrspace.h> | ||
| 15 | |||
| 16 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
| 17 | |||
| 18 | static inline void prom_wait_thre(void __iomem *base) | ||
| 19 | { | ||
| 20 | u32 lsr; | ||
| 21 | |||
| 22 | do { | ||
| 23 | lsr = __raw_readl(base + UART_LSR * 4); | ||
| 24 | if (lsr & UART_LSR_THRE) | ||
| 25 | break; | ||
| 26 | } while (1); | ||
| 27 | } | ||
| 28 | |||
| 29 | void prom_putchar(unsigned char ch) | ||
| 30 | { | ||
| 31 | void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE)); | ||
| 32 | |||
| 33 | prom_wait_thre(base); | ||
| 34 | __raw_writel(ch, base + UART_TX * 4); | ||
| 35 | prom_wait_thre(base); | ||
| 36 | } | ||
diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c new file mode 100644 index 000000000000..a0c426b82123 --- /dev/null +++ b/arch/mips/ath79/gpio.c | |||
| @@ -0,0 +1,197 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X GPIO API support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/types.h> | ||
| 16 | #include <linux/spinlock.h> | ||
| 17 | #include <linux/io.h> | ||
| 18 | #include <linux/ioport.h> | ||
| 19 | #include <linux/gpio.h> | ||
| 20 | |||
| 21 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
| 22 | #include <asm/mach-ath79/ath79.h> | ||
| 23 | #include "common.h" | ||
| 24 | |||
| 25 | static void __iomem *ath79_gpio_base; | ||
| 26 | static unsigned long ath79_gpio_count; | ||
| 27 | static DEFINE_SPINLOCK(ath79_gpio_lock); | ||
| 28 | |||
| 29 | static void __ath79_gpio_set_value(unsigned gpio, int value) | ||
| 30 | { | ||
| 31 | void __iomem *base = ath79_gpio_base; | ||
| 32 | |||
| 33 | if (value) | ||
| 34 | __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET); | ||
| 35 | else | ||
| 36 | __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR); | ||
| 37 | } | ||
| 38 | |||
| 39 | static int __ath79_gpio_get_value(unsigned gpio) | ||
| 40 | { | ||
| 41 | return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1; | ||
| 42 | } | ||
| 43 | |||
| 44 | static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset) | ||
| 45 | { | ||
| 46 | return __ath79_gpio_get_value(offset); | ||
| 47 | } | ||
| 48 | |||
| 49 | static void ath79_gpio_set_value(struct gpio_chip *chip, | ||
| 50 | unsigned offset, int value) | ||
| 51 | { | ||
| 52 | __ath79_gpio_set_value(offset, value); | ||
| 53 | } | ||
| 54 | |||
| 55 | static int ath79_gpio_direction_input(struct gpio_chip *chip, | ||
| 56 | unsigned offset) | ||
| 57 | { | ||
| 58 | void __iomem *base = ath79_gpio_base; | ||
| 59 | unsigned long flags; | ||
| 60 | |||
| 61 | spin_lock_irqsave(&ath79_gpio_lock, flags); | ||
| 62 | |||
| 63 | __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), | ||
| 64 | base + AR71XX_GPIO_REG_OE); | ||
| 65 | |||
| 66 | spin_unlock_irqrestore(&ath79_gpio_lock, flags); | ||
| 67 | |||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | static int ath79_gpio_direction_output(struct gpio_chip *chip, | ||
| 72 | unsigned offset, int value) | ||
| 73 | { | ||
| 74 | void __iomem *base = ath79_gpio_base; | ||
| 75 | unsigned long flags; | ||
| 76 | |||
| 77 | spin_lock_irqsave(&ath79_gpio_lock, flags); | ||
| 78 | |||
| 79 | if (value) | ||
| 80 | __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); | ||
| 81 | else | ||
| 82 | __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); | ||
| 83 | |||
| 84 | __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), | ||
| 85 | base + AR71XX_GPIO_REG_OE); | ||
| 86 | |||
| 87 | spin_unlock_irqrestore(&ath79_gpio_lock, flags); | ||
| 88 | |||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | |||
| 92 | static struct gpio_chip ath79_gpio_chip = { | ||
| 93 | .label = "ath79", | ||
| 94 | .get = ath79_gpio_get_value, | ||
| 95 | .set = ath79_gpio_set_value, | ||
| 96 | .direction_input = ath79_gpio_direction_input, | ||
| 97 | .direction_output = ath79_gpio_direction_output, | ||
| 98 | .base = 0, | ||
| 99 | }; | ||
| 100 | |||
| 101 | void ath79_gpio_function_enable(u32 mask) | ||
| 102 | { | ||
| 103 | void __iomem *base = ath79_gpio_base; | ||
| 104 | unsigned long flags; | ||
| 105 | |||
| 106 | spin_lock_irqsave(&ath79_gpio_lock, flags); | ||
| 107 | |||
| 108 | __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) | mask, | ||
| 109 | base + AR71XX_GPIO_REG_FUNC); | ||
| 110 | /* flush write */ | ||
| 111 | __raw_readl(base + AR71XX_GPIO_REG_FUNC); | ||
| 112 | |||
| 113 | spin_unlock_irqrestore(&ath79_gpio_lock, flags); | ||
| 114 | } | ||
| 115 | |||
| 116 | void ath79_gpio_function_disable(u32 mask) | ||
| 117 | { | ||
| 118 | void __iomem *base = ath79_gpio_base; | ||
| 119 | unsigned long flags; | ||
| 120 | |||
| 121 | spin_lock_irqsave(&ath79_gpio_lock, flags); | ||
| 122 | |||
| 123 | __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~mask, | ||
| 124 | base + AR71XX_GPIO_REG_FUNC); | ||
| 125 | /* flush write */ | ||
| 126 | __raw_readl(base + AR71XX_GPIO_REG_FUNC); | ||
| 127 | |||
| 128 | spin_unlock_irqrestore(&ath79_gpio_lock, flags); | ||
| 129 | } | ||
| 130 | |||
| 131 | void ath79_gpio_function_setup(u32 set, u32 clear) | ||
| 132 | { | ||
| 133 | void __iomem *base = ath79_gpio_base; | ||
| 134 | unsigned long flags; | ||
| 135 | |||
| 136 | spin_lock_irqsave(&ath79_gpio_lock, flags); | ||
| 137 | |||
| 138 | __raw_writel((__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~clear) | set, | ||
| 139 | base + AR71XX_GPIO_REG_FUNC); | ||
| 140 | /* flush write */ | ||
| 141 | __raw_readl(base + AR71XX_GPIO_REG_FUNC); | ||
| 142 | |||
| 143 | spin_unlock_irqrestore(&ath79_gpio_lock, flags); | ||
| 144 | } | ||
| 145 | |||
| 146 | void __init ath79_gpio_init(void) | ||
| 147 | { | ||
| 148 | int err; | ||
| 149 | |||
| 150 | if (soc_is_ar71xx()) | ||
| 151 | ath79_gpio_count = AR71XX_GPIO_COUNT; | ||
| 152 | else if (soc_is_ar724x()) | ||
| 153 | ath79_gpio_count = AR724X_GPIO_COUNT; | ||
| 154 | else if (soc_is_ar913x()) | ||
| 155 | ath79_gpio_count = AR913X_GPIO_COUNT; | ||
| 156 | else | ||
| 157 | BUG(); | ||
| 158 | |||
| 159 | ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE); | ||
| 160 | ath79_gpio_chip.ngpio = ath79_gpio_count; | ||
| 161 | |||
| 162 | err = gpiochip_add(&ath79_gpio_chip); | ||
| 163 | if (err) | ||
| 164 | panic("cannot add AR71xx GPIO chip, error=%d", err); | ||
| 165 | } | ||
| 166 | |||
| 167 | int gpio_get_value(unsigned gpio) | ||
| 168 | { | ||
| 169 | if (gpio < ath79_gpio_count) | ||
| 170 | return __ath79_gpio_get_value(gpio); | ||
| 171 | |||
| 172 | return __gpio_get_value(gpio); | ||
| 173 | } | ||
| 174 | EXPORT_SYMBOL(gpio_get_value); | ||
| 175 | |||
| 176 | void gpio_set_value(unsigned gpio, int value) | ||
| 177 | { | ||
| 178 | if (gpio < ath79_gpio_count) | ||
| 179 | __ath79_gpio_set_value(gpio, value); | ||
| 180 | else | ||
| 181 | __gpio_set_value(gpio, value); | ||
| 182 | } | ||
| 183 | EXPORT_SYMBOL(gpio_set_value); | ||
| 184 | |||
| 185 | int gpio_to_irq(unsigned gpio) | ||
| 186 | { | ||
| 187 | /* FIXME */ | ||
| 188 | return -EINVAL; | ||
| 189 | } | ||
| 190 | EXPORT_SYMBOL(gpio_to_irq); | ||
| 191 | |||
| 192 | int irq_to_gpio(unsigned irq) | ||
| 193 | { | ||
| 194 | /* FIXME */ | ||
| 195 | return -EINVAL; | ||
| 196 | } | ||
| 197 | EXPORT_SYMBOL(irq_to_gpio); | ||
diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c new file mode 100644 index 000000000000..1bf7f719ba53 --- /dev/null +++ b/arch/mips/ath79/irq.c | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71xx/AR724x/AR913x specific interrupt handling | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * Parts of this file are based on Atheros' 2.6.15 BSP | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License version 2 as published | ||
| 11 | * by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/interrupt.h> | ||
| 17 | #include <linux/irq.h> | ||
| 18 | |||
| 19 | #include <asm/irq_cpu.h> | ||
| 20 | #include <asm/mipsregs.h> | ||
| 21 | |||
| 22 | #include <asm/mach-ath79/ath79.h> | ||
| 23 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
| 24 | #include "common.h" | ||
| 25 | |||
| 26 | static unsigned int ath79_ip2_flush_reg; | ||
| 27 | static unsigned int ath79_ip3_flush_reg; | ||
| 28 | |||
| 29 | static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
| 30 | { | ||
| 31 | void __iomem *base = ath79_reset_base; | ||
| 32 | u32 pending; | ||
| 33 | |||
| 34 | pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) & | ||
| 35 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
| 36 | |||
| 37 | if (pending & MISC_INT_UART) | ||
| 38 | generic_handle_irq(ATH79_MISC_IRQ_UART); | ||
| 39 | |||
| 40 | else if (pending & MISC_INT_DMA) | ||
| 41 | generic_handle_irq(ATH79_MISC_IRQ_DMA); | ||
| 42 | |||
| 43 | else if (pending & MISC_INT_PERFC) | ||
| 44 | generic_handle_irq(ATH79_MISC_IRQ_PERFC); | ||
| 45 | |||
| 46 | else if (pending & MISC_INT_TIMER) | ||
| 47 | generic_handle_irq(ATH79_MISC_IRQ_TIMER); | ||
| 48 | |||
| 49 | else if (pending & MISC_INT_OHCI) | ||
| 50 | generic_handle_irq(ATH79_MISC_IRQ_OHCI); | ||
| 51 | |||
| 52 | else if (pending & MISC_INT_ERROR) | ||
| 53 | generic_handle_irq(ATH79_MISC_IRQ_ERROR); | ||
| 54 | |||
| 55 | else if (pending & MISC_INT_GPIO) | ||
| 56 | generic_handle_irq(ATH79_MISC_IRQ_GPIO); | ||
| 57 | |||
| 58 | else if (pending & MISC_INT_WDOG) | ||
| 59 | generic_handle_irq(ATH79_MISC_IRQ_WDOG); | ||
| 60 | |||
| 61 | else | ||
| 62 | spurious_interrupt(); | ||
| 63 | } | ||
| 64 | |||
| 65 | static void ar71xx_misc_irq_unmask(unsigned int irq) | ||
| 66 | { | ||
| 67 | void __iomem *base = ath79_reset_base; | ||
| 68 | u32 t; | ||
| 69 | |||
| 70 | irq -= ATH79_MISC_IRQ_BASE; | ||
| 71 | |||
| 72 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
| 73 | __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
| 74 | |||
| 75 | /* flush write */ | ||
| 76 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
| 77 | } | ||
| 78 | |||
| 79 | static void ar71xx_misc_irq_mask(unsigned int irq) | ||
| 80 | { | ||
| 81 | void __iomem *base = ath79_reset_base; | ||
| 82 | u32 t; | ||
| 83 | |||
| 84 | irq -= ATH79_MISC_IRQ_BASE; | ||
| 85 | |||
| 86 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
| 87 | __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
| 88 | |||
| 89 | /* flush write */ | ||
| 90 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
| 91 | } | ||
| 92 | |||
| 93 | static void ar724x_misc_irq_ack(unsigned int irq) | ||
| 94 | { | ||
| 95 | void __iomem *base = ath79_reset_base; | ||
| 96 | u32 t; | ||
| 97 | |||
| 98 | irq -= ATH79_MISC_IRQ_BASE; | ||
| 99 | |||
| 100 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); | ||
| 101 | __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS); | ||
| 102 | |||
| 103 | /* flush write */ | ||
| 104 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); | ||
| 105 | } | ||
| 106 | |||
| 107 | static struct irq_chip ath79_misc_irq_chip = { | ||
| 108 | .name = "MISC", | ||
| 109 | .unmask = ar71xx_misc_irq_unmask, | ||
| 110 | .mask = ar71xx_misc_irq_mask, | ||
| 111 | }; | ||
| 112 | |||
| 113 | static void __init ath79_misc_irq_init(void) | ||
| 114 | { | ||
| 115 | void __iomem *base = ath79_reset_base; | ||
| 116 | int i; | ||
| 117 | |||
| 118 | __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE); | ||
| 119 | __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS); | ||
| 120 | |||
| 121 | if (soc_is_ar71xx() || soc_is_ar913x()) | ||
| 122 | ath79_misc_irq_chip.mask_ack = ar71xx_misc_irq_mask; | ||
| 123 | else if (soc_is_ar724x()) | ||
| 124 | ath79_misc_irq_chip.ack = ar724x_misc_irq_ack; | ||
| 125 | else | ||
| 126 | BUG(); | ||
| 127 | |||
| 128 | for (i = ATH79_MISC_IRQ_BASE; | ||
| 129 | i < ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT; i++) { | ||
| 130 | irq_desc[i].status = IRQ_DISABLED; | ||
| 131 | set_irq_chip_and_handler(i, &ath79_misc_irq_chip, | ||
| 132 | handle_level_irq); | ||
| 133 | } | ||
| 134 | |||
| 135 | set_irq_chained_handler(ATH79_CPU_IRQ_MISC, ath79_misc_irq_handler); | ||
| 136 | } | ||
| 137 | |||
| 138 | asmlinkage void plat_irq_dispatch(void) | ||
| 139 | { | ||
| 140 | unsigned long pending; | ||
| 141 | |||
| 142 | pending = read_c0_status() & read_c0_cause() & ST0_IM; | ||
| 143 | |||
| 144 | if (pending & STATUSF_IP7) | ||
| 145 | do_IRQ(ATH79_CPU_IRQ_TIMER); | ||
| 146 | |||
| 147 | else if (pending & STATUSF_IP2) { | ||
| 148 | ath79_ddr_wb_flush(ath79_ip2_flush_reg); | ||
| 149 | do_IRQ(ATH79_CPU_IRQ_IP2); | ||
| 150 | } | ||
| 151 | |||
| 152 | else if (pending & STATUSF_IP4) | ||
| 153 | do_IRQ(ATH79_CPU_IRQ_GE0); | ||
| 154 | |||
| 155 | else if (pending & STATUSF_IP5) | ||
| 156 | do_IRQ(ATH79_CPU_IRQ_GE1); | ||
| 157 | |||
| 158 | else if (pending & STATUSF_IP3) { | ||
| 159 | ath79_ddr_wb_flush(ath79_ip3_flush_reg); | ||
| 160 | do_IRQ(ATH79_CPU_IRQ_USB); | ||
| 161 | } | ||
| 162 | |||
| 163 | else if (pending & STATUSF_IP6) | ||
| 164 | do_IRQ(ATH79_CPU_IRQ_MISC); | ||
| 165 | |||
| 166 | else | ||
| 167 | spurious_interrupt(); | ||
| 168 | } | ||
| 169 | |||
| 170 | void __init arch_init_irq(void) | ||
| 171 | { | ||
| 172 | if (soc_is_ar71xx()) { | ||
| 173 | ath79_ip2_flush_reg = AR71XX_DDR_REG_FLUSH_PCI; | ||
| 174 | ath79_ip3_flush_reg = AR71XX_DDR_REG_FLUSH_USB; | ||
| 175 | } else if (soc_is_ar724x()) { | ||
| 176 | ath79_ip2_flush_reg = AR724X_DDR_REG_FLUSH_PCIE; | ||
| 177 | ath79_ip3_flush_reg = AR724X_DDR_REG_FLUSH_USB; | ||
| 178 | } else if (soc_is_ar913x()) { | ||
| 179 | ath79_ip2_flush_reg = AR913X_DDR_REG_FLUSH_WMAC; | ||
| 180 | ath79_ip3_flush_reg = AR913X_DDR_REG_FLUSH_USB; | ||
| 181 | } else | ||
| 182 | BUG(); | ||
| 183 | |||
| 184 | cp0_perfcount_irq = ATH79_MISC_IRQ_PERFC; | ||
| 185 | mips_cpu_irq_init(); | ||
| 186 | ath79_misc_irq_init(); | ||
| 187 | } | ||
diff --git a/arch/mips/ath79/mach-ap81.c b/arch/mips/ath79/mach-ap81.c new file mode 100644 index 000000000000..eee4c121deb4 --- /dev/null +++ b/arch/mips/ath79/mach-ap81.c | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AP81 board support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2009 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include "machtypes.h" | ||
| 13 | #include "dev-ar913x-wmac.h" | ||
| 14 | #include "dev-gpio-buttons.h" | ||
| 15 | #include "dev-leds-gpio.h" | ||
| 16 | #include "dev-spi.h" | ||
| 17 | |||
| 18 | #define AP81_GPIO_LED_STATUS 1 | ||
| 19 | #define AP81_GPIO_LED_AOSS 3 | ||
| 20 | #define AP81_GPIO_LED_WLAN 6 | ||
| 21 | #define AP81_GPIO_LED_POWER 14 | ||
| 22 | |||
| 23 | #define AP81_GPIO_BTN_SW4 12 | ||
| 24 | #define AP81_GPIO_BTN_SW1 21 | ||
| 25 | |||
| 26 | #define AP81_KEYS_POLL_INTERVAL 20 /* msecs */ | ||
| 27 | #define AP81_KEYS_DEBOUNCE_INTERVAL (3 * AP81_KEYS_POLL_INTERVAL) | ||
| 28 | |||
| 29 | #define AP81_CAL_DATA_ADDR 0x1fff1000 | ||
| 30 | |||
| 31 | static struct gpio_led ap81_leds_gpio[] __initdata = { | ||
| 32 | { | ||
| 33 | .name = "ap81:green:status", | ||
| 34 | .gpio = AP81_GPIO_LED_STATUS, | ||
| 35 | .active_low = 1, | ||
| 36 | }, { | ||
| 37 | .name = "ap81:amber:aoss", | ||
| 38 | .gpio = AP81_GPIO_LED_AOSS, | ||
| 39 | .active_low = 1, | ||
| 40 | }, { | ||
| 41 | .name = "ap81:green:wlan", | ||
| 42 | .gpio = AP81_GPIO_LED_WLAN, | ||
| 43 | .active_low = 1, | ||
| 44 | }, { | ||
| 45 | .name = "ap81:green:power", | ||
| 46 | .gpio = AP81_GPIO_LED_POWER, | ||
| 47 | .active_low = 1, | ||
| 48 | } | ||
| 49 | }; | ||
| 50 | |||
| 51 | static struct gpio_keys_button ap81_gpio_keys[] __initdata = { | ||
| 52 | { | ||
| 53 | .desc = "sw1", | ||
| 54 | .type = EV_KEY, | ||
| 55 | .code = BTN_0, | ||
| 56 | .debounce_interval = AP81_KEYS_DEBOUNCE_INTERVAL, | ||
| 57 | .gpio = AP81_GPIO_BTN_SW1, | ||
| 58 | .active_low = 1, | ||
| 59 | } , { | ||
| 60 | .desc = "sw4", | ||
| 61 | .type = EV_KEY, | ||
| 62 | .code = BTN_1, | ||
| 63 | .debounce_interval = AP81_KEYS_DEBOUNCE_INTERVAL, | ||
| 64 | .gpio = AP81_GPIO_BTN_SW4, | ||
| 65 | .active_low = 1, | ||
| 66 | } | ||
| 67 | }; | ||
| 68 | |||
| 69 | static struct spi_board_info ap81_spi_info[] = { | ||
| 70 | { | ||
| 71 | .bus_num = 0, | ||
| 72 | .chip_select = 0, | ||
| 73 | .max_speed_hz = 25000000, | ||
| 74 | .modalias = "m25p64", | ||
| 75 | } | ||
| 76 | }; | ||
| 77 | |||
| 78 | static struct ath79_spi_platform_data ap81_spi_data = { | ||
| 79 | .bus_num = 0, | ||
| 80 | .num_chipselect = 1, | ||
| 81 | }; | ||
| 82 | |||
| 83 | static void __init ap81_setup(void) | ||
| 84 | { | ||
| 85 | u8 *cal_data = (u8 *) KSEG1ADDR(AP81_CAL_DATA_ADDR); | ||
| 86 | |||
| 87 | ath79_register_leds_gpio(-1, ARRAY_SIZE(ap81_leds_gpio), | ||
| 88 | ap81_leds_gpio); | ||
| 89 | ath79_register_gpio_keys_polled(-1, AP81_KEYS_POLL_INTERVAL, | ||
| 90 | ARRAY_SIZE(ap81_gpio_keys), | ||
| 91 | ap81_gpio_keys); | ||
| 92 | ath79_register_spi(&ap81_spi_data, ap81_spi_info, | ||
| 93 | ARRAY_SIZE(ap81_spi_info)); | ||
| 94 | ath79_register_ar913x_wmac(cal_data); | ||
| 95 | } | ||
| 96 | |||
| 97 | MIPS_MACHINE(ATH79_MACH_AP81, "AP81", "Atheros AP81 reference board", | ||
| 98 | ap81_setup); | ||
diff --git a/arch/mips/ath79/mach-pb44.c b/arch/mips/ath79/mach-pb44.c new file mode 100644 index 000000000000..ec7b7a135d53 --- /dev/null +++ b/arch/mips/ath79/mach-pb44.c | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | /* | ||
| 2 | * Atheros PB44 reference board support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License version 2 as published | ||
| 8 | * by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/platform_device.h> | ||
| 13 | #include <linux/i2c.h> | ||
| 14 | #include <linux/i2c-gpio.h> | ||
| 15 | #include <linux/i2c/pcf857x.h> | ||
| 16 | |||
| 17 | #include "machtypes.h" | ||
| 18 | #include "dev-gpio-buttons.h" | ||
| 19 | #include "dev-leds-gpio.h" | ||
| 20 | #include "dev-spi.h" | ||
| 21 | |||
| 22 | #define PB44_GPIO_I2C_SCL 0 | ||
| 23 | #define PB44_GPIO_I2C_SDA 1 | ||
| 24 | |||
| 25 | #define PB44_GPIO_EXP_BASE 16 | ||
| 26 | #define PB44_GPIO_SW_RESET (PB44_GPIO_EXP_BASE + 6) | ||
| 27 | #define PB44_GPIO_SW_JUMP (PB44_GPIO_EXP_BASE + 8) | ||
| 28 | #define PB44_GPIO_LED_JUMP1 (PB44_GPIO_EXP_BASE + 9) | ||
| 29 | #define PB44_GPIO_LED_JUMP2 (PB44_GPIO_EXP_BASE + 10) | ||
| 30 | |||
| 31 | #define PB44_KEYS_POLL_INTERVAL 20 /* msecs */ | ||
| 32 | #define PB44_KEYS_DEBOUNCE_INTERVAL (3 * PB44_KEYS_POLL_INTERVAL) | ||
| 33 | |||
| 34 | static struct i2c_gpio_platform_data pb44_i2c_gpio_data = { | ||
| 35 | .sda_pin = PB44_GPIO_I2C_SDA, | ||
| 36 | .scl_pin = PB44_GPIO_I2C_SCL, | ||
| 37 | }; | ||
| 38 | |||
| 39 | static struct platform_device pb44_i2c_gpio_device = { | ||
| 40 | .name = "i2c-gpio", | ||
| 41 | .id = 0, | ||
| 42 | .dev = { | ||
| 43 | .platform_data = &pb44_i2c_gpio_data, | ||
| 44 | } | ||
| 45 | }; | ||
| 46 | |||
| 47 | static struct pcf857x_platform_data pb44_pcf857x_data = { | ||
| 48 | .gpio_base = PB44_GPIO_EXP_BASE, | ||
| 49 | }; | ||
| 50 | |||
| 51 | static struct i2c_board_info pb44_i2c_board_info[] __initdata = { | ||
| 52 | { | ||
| 53 | I2C_BOARD_INFO("pcf8575", 0x20), | ||
| 54 | .platform_data = &pb44_pcf857x_data, | ||
| 55 | }, | ||
| 56 | }; | ||
| 57 | |||
| 58 | static struct gpio_led pb44_leds_gpio[] __initdata = { | ||
| 59 | { | ||
| 60 | .name = "pb44:amber:jump1", | ||
| 61 | .gpio = PB44_GPIO_LED_JUMP1, | ||
| 62 | .active_low = 1, | ||
| 63 | }, { | ||
| 64 | .name = "pb44:green:jump2", | ||
| 65 | .gpio = PB44_GPIO_LED_JUMP2, | ||
| 66 | .active_low = 1, | ||
| 67 | }, | ||
| 68 | }; | ||
| 69 | |||
| 70 | static struct gpio_keys_button pb44_gpio_keys[] __initdata = { | ||
| 71 | { | ||
| 72 | .desc = "soft_reset", | ||
| 73 | .type = EV_KEY, | ||
| 74 | .code = KEY_RESTART, | ||
| 75 | .debounce_interval = PB44_KEYS_DEBOUNCE_INTERVAL, | ||
| 76 | .gpio = PB44_GPIO_SW_RESET, | ||
| 77 | .active_low = 1, | ||
| 78 | } , { | ||
| 79 | .desc = "jumpstart", | ||
| 80 | .type = EV_KEY, | ||
| 81 | .code = KEY_WPS_BUTTON, | ||
| 82 | .debounce_interval = PB44_KEYS_DEBOUNCE_INTERVAL, | ||
| 83 | .gpio = PB44_GPIO_SW_JUMP, | ||
| 84 | .active_low = 1, | ||
| 85 | } | ||
| 86 | }; | ||
| 87 | |||
| 88 | static struct spi_board_info pb44_spi_info[] = { | ||
| 89 | { | ||
| 90 | .bus_num = 0, | ||
| 91 | .chip_select = 0, | ||
| 92 | .max_speed_hz = 25000000, | ||
| 93 | .modalias = "m25p64", | ||
| 94 | }, | ||
| 95 | }; | ||
| 96 | |||
| 97 | static struct ath79_spi_platform_data pb44_spi_data = { | ||
| 98 | .bus_num = 0, | ||
| 99 | .num_chipselect = 1, | ||
| 100 | }; | ||
| 101 | |||
| 102 | static void __init pb44_init(void) | ||
| 103 | { | ||
| 104 | i2c_register_board_info(0, pb44_i2c_board_info, | ||
| 105 | ARRAY_SIZE(pb44_i2c_board_info)); | ||
| 106 | platform_device_register(&pb44_i2c_gpio_device); | ||
| 107 | |||
| 108 | ath79_register_leds_gpio(-1, ARRAY_SIZE(pb44_leds_gpio), | ||
| 109 | pb44_leds_gpio); | ||
| 110 | ath79_register_gpio_keys_polled(-1, PB44_KEYS_POLL_INTERVAL, | ||
| 111 | ARRAY_SIZE(pb44_gpio_keys), | ||
| 112 | pb44_gpio_keys); | ||
| 113 | ath79_register_spi(&pb44_spi_data, pb44_spi_info, | ||
| 114 | ARRAY_SIZE(pb44_spi_info)); | ||
| 115 | } | ||
| 116 | |||
| 117 | MIPS_MACHINE(ATH79_MACH_PB44, "PB44", "Atheros PB44 reference board", | ||
| 118 | pb44_init); | ||
diff --git a/arch/mips/ath79/machtypes.h b/arch/mips/ath79/machtypes.h new file mode 100644 index 000000000000..3940fe470b2d --- /dev/null +++ b/arch/mips/ath79/machtypes.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X machine type definitions | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _ATH79_MACHTYPE_H | ||
| 13 | #define _ATH79_MACHTYPE_H | ||
| 14 | |||
| 15 | #include <asm/mips_machine.h> | ||
| 16 | |||
| 17 | enum ath79_mach_type { | ||
| 18 | ATH79_MACH_GENERIC = 0, | ||
| 19 | ATH79_MACH_AP81, /* Atheros AP81 reference board */ | ||
| 20 | ATH79_MACH_PB44, /* Atheros PB44 reference board */ | ||
| 21 | }; | ||
| 22 | |||
| 23 | #endif /* _ATH79_MACHTYPE_H */ | ||
diff --git a/arch/mips/ath79/prom.c b/arch/mips/ath79/prom.c new file mode 100644 index 000000000000..e9cbd7c2918f --- /dev/null +++ b/arch/mips/ath79/prom.c | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X specific prom routines | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/io.h> | ||
| 15 | #include <linux/string.h> | ||
| 16 | |||
| 17 | #include <asm/bootinfo.h> | ||
| 18 | #include <asm/addrspace.h> | ||
| 19 | |||
| 20 | #include "common.h" | ||
| 21 | |||
| 22 | static inline int is_valid_ram_addr(void *addr) | ||
| 23 | { | ||
| 24 | if (((u32) addr > KSEG0) && | ||
| 25 | ((u32) addr < (KSEG0 + ATH79_MEM_SIZE_MAX))) | ||
| 26 | return 1; | ||
| 27 | |||
| 28 | if (((u32) addr > KSEG1) && | ||
| 29 | ((u32) addr < (KSEG1 + ATH79_MEM_SIZE_MAX))) | ||
| 30 | return 1; | ||
| 31 | |||
| 32 | return 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | static __init void ath79_prom_init_cmdline(int argc, char **argv) | ||
| 36 | { | ||
| 37 | int i; | ||
| 38 | |||
| 39 | if (!is_valid_ram_addr(argv)) | ||
| 40 | return; | ||
| 41 | |||
| 42 | for (i = 0; i < argc; i++) | ||
| 43 | if (is_valid_ram_addr(argv[i])) { | ||
| 44 | strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); | ||
| 45 | strlcat(arcs_cmdline, argv[i], sizeof(arcs_cmdline)); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | void __init prom_init(void) | ||
| 50 | { | ||
| 51 | ath79_prom_init_cmdline(fw_arg0, (char **)fw_arg1); | ||
| 52 | } | ||
| 53 | |||
| 54 | void __init prom_free_prom_memory(void) | ||
| 55 | { | ||
| 56 | /* We do not have to prom memory to free */ | ||
| 57 | } | ||
diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c new file mode 100644 index 000000000000..159b42f106b0 --- /dev/null +++ b/arch/mips/ath79/setup.c | |||
| @@ -0,0 +1,206 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X specific setup | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * Parts of this file are based on Atheros' 2.6.15 BSP | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License version 2 as published | ||
| 11 | * by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/bootmem.h> | ||
| 17 | #include <linux/err.h> | ||
| 18 | #include <linux/clk.h> | ||
| 19 | |||
| 20 | #include <asm/bootinfo.h> | ||
| 21 | #include <asm/time.h> /* for mips_hpt_frequency */ | ||
| 22 | #include <asm/reboot.h> /* for _machine_{restart,halt} */ | ||
| 23 | #include <asm/mips_machine.h> | ||
| 24 | |||
| 25 | #include <asm/mach-ath79/ath79.h> | ||
| 26 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
| 27 | #include "common.h" | ||
| 28 | #include "dev-common.h" | ||
| 29 | #include "machtypes.h" | ||
| 30 | |||
| 31 | #define ATH79_SYS_TYPE_LEN 64 | ||
| 32 | |||
| 33 | #define AR71XX_BASE_FREQ 40000000 | ||
| 34 | #define AR724X_BASE_FREQ 5000000 | ||
| 35 | #define AR913X_BASE_FREQ 5000000 | ||
| 36 | |||
| 37 | static char ath79_sys_type[ATH79_SYS_TYPE_LEN]; | ||
| 38 | |||
| 39 | static void ath79_restart(char *command) | ||
| 40 | { | ||
| 41 | ath79_device_reset_set(AR71XX_RESET_FULL_CHIP); | ||
| 42 | for (;;) | ||
| 43 | if (cpu_wait) | ||
| 44 | cpu_wait(); | ||
| 45 | } | ||
| 46 | |||
| 47 | static void ath79_halt(void) | ||
| 48 | { | ||
| 49 | while (1) | ||
| 50 | cpu_wait(); | ||
| 51 | } | ||
| 52 | |||
| 53 | static void __init ath79_detect_mem_size(void) | ||
| 54 | { | ||
| 55 | unsigned long size; | ||
| 56 | |||
| 57 | for (size = ATH79_MEM_SIZE_MIN; size < ATH79_MEM_SIZE_MAX; | ||
| 58 | size <<= 1) { | ||
| 59 | if (!memcmp(ath79_detect_mem_size, | ||
| 60 | ath79_detect_mem_size + size, 1024)) | ||
| 61 | break; | ||
| 62 | } | ||
| 63 | |||
| 64 | add_memory_region(0, size, BOOT_MEM_RAM); | ||
| 65 | } | ||
| 66 | |||
| 67 | static void __init ath79_detect_sys_type(void) | ||
| 68 | { | ||
| 69 | char *chip = "????"; | ||
| 70 | u32 id; | ||
| 71 | u32 major; | ||
| 72 | u32 minor; | ||
| 73 | u32 rev = 0; | ||
| 74 | |||
| 75 | id = ath79_reset_rr(AR71XX_RESET_REG_REV_ID); | ||
| 76 | major = id & REV_ID_MAJOR_MASK; | ||
| 77 | |||
| 78 | switch (major) { | ||
| 79 | case REV_ID_MAJOR_AR71XX: | ||
| 80 | minor = id & AR71XX_REV_ID_MINOR_MASK; | ||
| 81 | rev = id >> AR71XX_REV_ID_REVISION_SHIFT; | ||
| 82 | rev &= AR71XX_REV_ID_REVISION_MASK; | ||
| 83 | switch (minor) { | ||
| 84 | case AR71XX_REV_ID_MINOR_AR7130: | ||
| 85 | ath79_soc = ATH79_SOC_AR7130; | ||
| 86 | chip = "7130"; | ||
| 87 | break; | ||
| 88 | |||
| 89 | case AR71XX_REV_ID_MINOR_AR7141: | ||
| 90 | ath79_soc = ATH79_SOC_AR7141; | ||
| 91 | chip = "7141"; | ||
| 92 | break; | ||
| 93 | |||
| 94 | case AR71XX_REV_ID_MINOR_AR7161: | ||
| 95 | ath79_soc = ATH79_SOC_AR7161; | ||
| 96 | chip = "7161"; | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | break; | ||
| 100 | |||
| 101 | case REV_ID_MAJOR_AR7240: | ||
| 102 | ath79_soc = ATH79_SOC_AR7240; | ||
| 103 | chip = "7240"; | ||
| 104 | rev = (id & AR724X_REV_ID_REVISION_MASK); | ||
| 105 | break; | ||
| 106 | |||
| 107 | case REV_ID_MAJOR_AR7241: | ||
| 108 | ath79_soc = ATH79_SOC_AR7241; | ||
| 109 | chip = "7241"; | ||
| 110 | rev = (id & AR724X_REV_ID_REVISION_MASK); | ||
| 111 | break; | ||
| 112 | |||
| 113 | case REV_ID_MAJOR_AR7242: | ||
| 114 | ath79_soc = ATH79_SOC_AR7242; | ||
| 115 | chip = "7242"; | ||
| 116 | rev = (id & AR724X_REV_ID_REVISION_MASK); | ||
| 117 | break; | ||
| 118 | |||
| 119 | case REV_ID_MAJOR_AR913X: | ||
| 120 | minor = id & AR913X_REV_ID_MINOR_MASK; | ||
| 121 | rev = id >> AR913X_REV_ID_REVISION_SHIFT; | ||
| 122 | rev &= AR913X_REV_ID_REVISION_MASK; | ||
| 123 | switch (minor) { | ||
| 124 | case AR913X_REV_ID_MINOR_AR9130: | ||
| 125 | ath79_soc = ATH79_SOC_AR9130; | ||
| 126 | chip = "9130"; | ||
| 127 | break; | ||
| 128 | |||
| 129 | case AR913X_REV_ID_MINOR_AR9132: | ||
| 130 | ath79_soc = ATH79_SOC_AR9132; | ||
| 131 | chip = "9132"; | ||
| 132 | break; | ||
| 133 | } | ||
| 134 | break; | ||
| 135 | |||
| 136 | default: | ||
| 137 | panic("ath79: unknown SoC, id:0x%08x\n", id); | ||
| 138 | } | ||
| 139 | |||
| 140 | sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev); | ||
| 141 | pr_info("SoC: %s\n", ath79_sys_type); | ||
| 142 | } | ||
| 143 | |||
| 144 | const char *get_system_type(void) | ||
| 145 | { | ||
| 146 | return ath79_sys_type; | ||
| 147 | } | ||
| 148 | |||
| 149 | unsigned int __cpuinit get_c0_compare_int(void) | ||
| 150 | { | ||
| 151 | return CP0_LEGACY_COMPARE_IRQ; | ||
| 152 | } | ||
| 153 | |||
| 154 | void __init plat_mem_setup(void) | ||
| 155 | { | ||
| 156 | set_io_port_base(KSEG1); | ||
| 157 | |||
| 158 | ath79_reset_base = ioremap_nocache(AR71XX_RESET_BASE, | ||
| 159 | AR71XX_RESET_SIZE); | ||
| 160 | ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE, | ||
| 161 | AR71XX_PLL_SIZE); | ||
| 162 | ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE, | ||
| 163 | AR71XX_DDR_CTRL_SIZE); | ||
| 164 | |||
| 165 | ath79_detect_sys_type(); | ||
| 166 | ath79_detect_mem_size(); | ||
| 167 | ath79_clocks_init(); | ||
| 168 | |||
| 169 | _machine_restart = ath79_restart; | ||
| 170 | _machine_halt = ath79_halt; | ||
| 171 | pm_power_off = ath79_halt; | ||
| 172 | } | ||
| 173 | |||
| 174 | void __init plat_time_init(void) | ||
| 175 | { | ||
| 176 | struct clk *clk; | ||
| 177 | |||
| 178 | clk = clk_get(NULL, "cpu"); | ||
| 179 | if (IS_ERR(clk)) | ||
| 180 | panic("unable to get CPU clock, err=%ld", PTR_ERR(clk)); | ||
| 181 | |||
| 182 | mips_hpt_frequency = clk_get_rate(clk) / 2; | ||
| 183 | } | ||
| 184 | |||
| 185 | static int __init ath79_setup(void) | ||
| 186 | { | ||
| 187 | ath79_gpio_init(); | ||
| 188 | ath79_register_uart(); | ||
| 189 | ath79_register_wdt(); | ||
| 190 | |||
| 191 | mips_machine_setup(); | ||
| 192 | |||
| 193 | return 0; | ||
| 194 | } | ||
| 195 | |||
| 196 | arch_initcall(ath79_setup); | ||
| 197 | |||
| 198 | static void __init ath79_generic_init(void) | ||
| 199 | { | ||
| 200 | /* Nothing to do */ | ||
| 201 | } | ||
| 202 | |||
| 203 | MIPS_MACHINE(ATH79_MACH_GENERIC, | ||
| 204 | "Generic", | ||
| 205 | "Generic AR71XX/AR724X/AR913X based board", | ||
| 206 | ath79_generic_init); | ||
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index b455d0f36486..9d03b68aece8 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig | |||
| @@ -369,7 +369,10 @@ CONFIG_VT_HW_CONSOLE_BINDING=y | |||
| 369 | CONFIG_SERIAL_8250=y | 369 | CONFIG_SERIAL_8250=y |
| 370 | CONFIG_SERIAL_8250_CONSOLE=y | 370 | CONFIG_SERIAL_8250_CONSOLE=y |
| 371 | # CONFIG_HWMON is not set | 371 | # CONFIG_HWMON is not set |
| 372 | CONFIG_FB=y | ||
| 373 | CONFIG_FB_CIRRUS=y | ||
| 372 | # CONFIG_VGA_CONSOLE is not set | 374 | # CONFIG_VGA_CONSOLE is not set |
| 375 | CONFIG_FRAMEBUFFER_CONSOLE=y | ||
| 373 | CONFIG_HID=m | 376 | CONFIG_HID=m |
| 374 | CONFIG_LEDS_CLASS=m | 377 | CONFIG_LEDS_CLASS=m |
| 375 | CONFIG_LEDS_TRIGGER_TIMER=m | 378 | CONFIG_LEDS_TRIGGER_TIMER=m |
diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h index 37f175c42bb5..650ac9ba734c 100644 --- a/arch/mips/include/asm/cache.h +++ b/arch/mips/include/asm/cache.h | |||
| @@ -17,4 +17,6 @@ | |||
| 17 | #define SMP_CACHE_SHIFT L1_CACHE_SHIFT | 17 | #define SMP_CACHE_SHIFT L1_CACHE_SHIFT |
| 18 | #define SMP_CACHE_BYTES L1_CACHE_BYTES | 18 | #define SMP_CACHE_BYTES L1_CACHE_BYTES |
| 19 | 19 | ||
| 20 | #define __read_mostly __attribute__((__section__(".data.read_mostly"))) | ||
| 21 | |||
| 20 | #endif /* _ASM_CACHE_H */ | 22 | #endif /* _ASM_CACHE_H */ |
diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h index b39def3f6e03..c454550eb0c0 100644 --- a/arch/mips/include/asm/cpu-info.h +++ b/arch/mips/include/asm/cpu-info.h | |||
| @@ -78,6 +78,7 @@ struct cpuinfo_mips { | |||
| 78 | unsigned int watch_reg_use_cnt; /* Usable by ptrace */ | 78 | unsigned int watch_reg_use_cnt; /* Usable by ptrace */ |
| 79 | #define NUM_WATCH_REGS 4 | 79 | #define NUM_WATCH_REGS 4 |
| 80 | u16 watch_reg_masks[NUM_WATCH_REGS]; | 80 | u16 watch_reg_masks[NUM_WATCH_REGS]; |
| 81 | unsigned int kscratch_mask; /* Usable KScratch mask. */ | ||
| 81 | } __attribute__((aligned(SMP_CACHE_BYTES))); | 82 | } __attribute__((aligned(SMP_CACHE_BYTES))); |
| 82 | 83 | ||
| 83 | extern struct cpuinfo_mips cpu_data[]; | 84 | extern struct cpuinfo_mips cpu_data[]; |
diff --git a/arch/mips/include/asm/inst.h b/arch/mips/include/asm/inst.h index 444ff71aa0e8..7ebfc392e58d 100644 --- a/arch/mips/include/asm/inst.h +++ b/arch/mips/include/asm/inst.h | |||
| @@ -72,6 +72,7 @@ enum spec2_op { | |||
| 72 | enum spec3_op { | 72 | enum spec3_op { |
| 73 | ext_op, dextm_op, dextu_op, dext_op, | 73 | ext_op, dextm_op, dextu_op, dext_op, |
| 74 | ins_op, dinsm_op, dinsu_op, dins_op, | 74 | ins_op, dinsm_op, dinsu_op, dins_op, |
| 75 | lx_op = 0x0a, | ||
| 75 | bshfl_op = 0x20, | 76 | bshfl_op = 0x20, |
| 76 | dbshfl_op = 0x24, | 77 | dbshfl_op = 0x24, |
| 77 | rdhwr_op = 0x3b | 78 | rdhwr_op = 0x3b |
| @@ -179,6 +180,19 @@ enum mad_func { | |||
| 179 | }; | 180 | }; |
| 180 | 181 | ||
| 181 | /* | 182 | /* |
| 183 | * func field for special3 lx opcodes (Cavium Octeon). | ||
| 184 | */ | ||
| 185 | enum lx_func { | ||
| 186 | lwx_op = 0x00, | ||
| 187 | lhx_op = 0x04, | ||
| 188 | lbux_op = 0x06, | ||
| 189 | ldx_op = 0x08, | ||
| 190 | lwux_op = 0x10, | ||
| 191 | lhux_op = 0x14, | ||
| 192 | lbx_op = 0x16, | ||
| 193 | }; | ||
| 194 | |||
| 195 | /* | ||
| 182 | * Damn ... bitfields depend from byteorder :-( | 196 | * Damn ... bitfields depend from byteorder :-( |
| 183 | */ | 197 | */ |
| 184 | #ifdef __MIPSEB__ | 198 | #ifdef __MIPSEB__ |
diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h new file mode 100644 index 000000000000..7622ccf75076 --- /dev/null +++ b/arch/mips/include/asm/jump_label.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | /* | ||
| 2 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 3 | * License. See the file "COPYING" in the main directory of this archive | ||
| 4 | * for more details. | ||
| 5 | * | ||
| 6 | * Copyright (c) 2010 Cavium Networks, Inc. | ||
| 7 | */ | ||
| 8 | #ifndef _ASM_MIPS_JUMP_LABEL_H | ||
| 9 | #define _ASM_MIPS_JUMP_LABEL_H | ||
| 10 | |||
| 11 | #include <linux/types.h> | ||
| 12 | |||
| 13 | #ifdef __KERNEL__ | ||
| 14 | |||
| 15 | #define JUMP_LABEL_NOP_SIZE 4 | ||
| 16 | |||
| 17 | #ifdef CONFIG_64BIT | ||
| 18 | #define WORD_INSN ".dword" | ||
| 19 | #else | ||
| 20 | #define WORD_INSN ".word" | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #define JUMP_LABEL(key, label) \ | ||
| 24 | do { \ | ||
| 25 | asm goto("1:\tnop\n\t" \ | ||
| 26 | "nop\n\t" \ | ||
| 27 | ".pushsection __jump_table, \"a\"\n\t" \ | ||
| 28 | WORD_INSN " 1b, %l[" #label "], %0\n\t" \ | ||
| 29 | ".popsection\n\t" \ | ||
| 30 | : : "i" (key) : : label); \ | ||
| 31 | } while (0) | ||
| 32 | |||
| 33 | |||
| 34 | #endif /* __KERNEL__ */ | ||
| 35 | |||
| 36 | #ifdef CONFIG_64BIT | ||
| 37 | typedef u64 jump_label_t; | ||
| 38 | #else | ||
| 39 | typedef u32 jump_label_t; | ||
| 40 | #endif | ||
| 41 | |||
| 42 | struct jump_entry { | ||
| 43 | jump_label_t code; | ||
| 44 | jump_label_t target; | ||
| 45 | jump_label_t key; | ||
| 46 | }; | ||
| 47 | |||
| 48 | #endif /* _ASM_MIPS_JUMP_LABEL_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h new file mode 100644 index 000000000000..cda1c8070b27 --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h | |||
| @@ -0,0 +1,233 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X SoC register definitions | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * Parts of this file are based on Atheros' 2.6.15 BSP | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License version 2 as published | ||
| 11 | * by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef __ASM_MACH_AR71XX_REGS_H | ||
| 15 | #define __ASM_MACH_AR71XX_REGS_H | ||
| 16 | |||
| 17 | #include <linux/types.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/io.h> | ||
| 20 | #include <linux/bitops.h> | ||
| 21 | |||
| 22 | #define AR71XX_APB_BASE 0x18000000 | ||
| 23 | #define AR71XX_SPI_BASE 0x1f000000 | ||
| 24 | #define AR71XX_SPI_SIZE 0x01000000 | ||
| 25 | |||
| 26 | #define AR71XX_DDR_CTRL_BASE (AR71XX_APB_BASE + 0x00000000) | ||
| 27 | #define AR71XX_DDR_CTRL_SIZE 0x100 | ||
| 28 | #define AR71XX_UART_BASE (AR71XX_APB_BASE + 0x00020000) | ||
| 29 | #define AR71XX_UART_SIZE 0x100 | ||
| 30 | #define AR71XX_GPIO_BASE (AR71XX_APB_BASE + 0x00040000) | ||
| 31 | #define AR71XX_GPIO_SIZE 0x100 | ||
| 32 | #define AR71XX_PLL_BASE (AR71XX_APB_BASE + 0x00050000) | ||
| 33 | #define AR71XX_PLL_SIZE 0x100 | ||
| 34 | #define AR71XX_RESET_BASE (AR71XX_APB_BASE + 0x00060000) | ||
| 35 | #define AR71XX_RESET_SIZE 0x100 | ||
| 36 | |||
| 37 | #define AR913X_WMAC_BASE (AR71XX_APB_BASE + 0x000C0000) | ||
| 38 | #define AR913X_WMAC_SIZE 0x30000 | ||
| 39 | |||
| 40 | /* | ||
| 41 | * DDR_CTRL block | ||
| 42 | */ | ||
| 43 | #define AR71XX_DDR_REG_PCI_WIN0 0x7c | ||
| 44 | #define AR71XX_DDR_REG_PCI_WIN1 0x80 | ||
| 45 | #define AR71XX_DDR_REG_PCI_WIN2 0x84 | ||
| 46 | #define AR71XX_DDR_REG_PCI_WIN3 0x88 | ||
| 47 | #define AR71XX_DDR_REG_PCI_WIN4 0x8c | ||
| 48 | #define AR71XX_DDR_REG_PCI_WIN5 0x90 | ||
| 49 | #define AR71XX_DDR_REG_PCI_WIN6 0x94 | ||
| 50 | #define AR71XX_DDR_REG_PCI_WIN7 0x98 | ||
| 51 | #define AR71XX_DDR_REG_FLUSH_GE0 0x9c | ||
| 52 | #define AR71XX_DDR_REG_FLUSH_GE1 0xa0 | ||
| 53 | #define AR71XX_DDR_REG_FLUSH_USB 0xa4 | ||
| 54 | #define AR71XX_DDR_REG_FLUSH_PCI 0xa8 | ||
| 55 | |||
| 56 | #define AR724X_DDR_REG_FLUSH_GE0 0x7c | ||
| 57 | #define AR724X_DDR_REG_FLUSH_GE1 0x80 | ||
| 58 | #define AR724X_DDR_REG_FLUSH_USB 0x84 | ||
| 59 | #define AR724X_DDR_REG_FLUSH_PCIE 0x88 | ||
| 60 | |||
| 61 | #define AR913X_DDR_REG_FLUSH_GE0 0x7c | ||
| 62 | #define AR913X_DDR_REG_FLUSH_GE1 0x80 | ||
| 63 | #define AR913X_DDR_REG_FLUSH_USB 0x84 | ||
| 64 | #define AR913X_DDR_REG_FLUSH_WMAC 0x88 | ||
| 65 | |||
| 66 | /* | ||
| 67 | * PLL block | ||
| 68 | */ | ||
| 69 | #define AR71XX_PLL_REG_CPU_CONFIG 0x00 | ||
| 70 | #define AR71XX_PLL_REG_SEC_CONFIG 0x04 | ||
| 71 | #define AR71XX_PLL_REG_ETH0_INT_CLOCK 0x10 | ||
| 72 | #define AR71XX_PLL_REG_ETH1_INT_CLOCK 0x14 | ||
| 73 | |||
| 74 | #define AR71XX_PLL_DIV_SHIFT 3 | ||
| 75 | #define AR71XX_PLL_DIV_MASK 0x1f | ||
| 76 | #define AR71XX_CPU_DIV_SHIFT 16 | ||
| 77 | #define AR71XX_CPU_DIV_MASK 0x3 | ||
| 78 | #define AR71XX_DDR_DIV_SHIFT 18 | ||
| 79 | #define AR71XX_DDR_DIV_MASK 0x3 | ||
| 80 | #define AR71XX_AHB_DIV_SHIFT 20 | ||
| 81 | #define AR71XX_AHB_DIV_MASK 0x7 | ||
| 82 | |||
| 83 | #define AR724X_PLL_REG_CPU_CONFIG 0x00 | ||
| 84 | #define AR724X_PLL_REG_PCIE_CONFIG 0x18 | ||
| 85 | |||
| 86 | #define AR724X_PLL_DIV_SHIFT 0 | ||
| 87 | #define AR724X_PLL_DIV_MASK 0x3ff | ||
| 88 | #define AR724X_PLL_REF_DIV_SHIFT 10 | ||
| 89 | #define AR724X_PLL_REF_DIV_MASK 0xf | ||
| 90 | #define AR724X_AHB_DIV_SHIFT 19 | ||
| 91 | #define AR724X_AHB_DIV_MASK 0x1 | ||
| 92 | #define AR724X_DDR_DIV_SHIFT 22 | ||
| 93 | #define AR724X_DDR_DIV_MASK 0x3 | ||
| 94 | |||
| 95 | #define AR913X_PLL_REG_CPU_CONFIG 0x00 | ||
| 96 | #define AR913X_PLL_REG_ETH_CONFIG 0x04 | ||
| 97 | #define AR913X_PLL_REG_ETH0_INT_CLOCK 0x14 | ||
| 98 | #define AR913X_PLL_REG_ETH1_INT_CLOCK 0x18 | ||
| 99 | |||
| 100 | #define AR913X_PLL_DIV_SHIFT 0 | ||
| 101 | #define AR913X_PLL_DIV_MASK 0x3ff | ||
| 102 | #define AR913X_DDR_DIV_SHIFT 22 | ||
| 103 | #define AR913X_DDR_DIV_MASK 0x3 | ||
| 104 | #define AR913X_AHB_DIV_SHIFT 19 | ||
| 105 | #define AR913X_AHB_DIV_MASK 0x1 | ||
| 106 | |||
| 107 | /* | ||
| 108 | * RESET block | ||
| 109 | */ | ||
| 110 | #define AR71XX_RESET_REG_TIMER 0x00 | ||
| 111 | #define AR71XX_RESET_REG_TIMER_RELOAD 0x04 | ||
| 112 | #define AR71XX_RESET_REG_WDOG_CTRL 0x08 | ||
| 113 | #define AR71XX_RESET_REG_WDOG 0x0c | ||
| 114 | #define AR71XX_RESET_REG_MISC_INT_STATUS 0x10 | ||
| 115 | #define AR71XX_RESET_REG_MISC_INT_ENABLE 0x14 | ||
| 116 | #define AR71XX_RESET_REG_PCI_INT_STATUS 0x18 | ||
| 117 | #define AR71XX_RESET_REG_PCI_INT_ENABLE 0x1c | ||
| 118 | #define AR71XX_RESET_REG_GLOBAL_INT_STATUS 0x20 | ||
| 119 | #define AR71XX_RESET_REG_RESET_MODULE 0x24 | ||
| 120 | #define AR71XX_RESET_REG_PERFC_CTRL 0x2c | ||
| 121 | #define AR71XX_RESET_REG_PERFC0 0x30 | ||
| 122 | #define AR71XX_RESET_REG_PERFC1 0x34 | ||
| 123 | #define AR71XX_RESET_REG_REV_ID 0x90 | ||
| 124 | |||
| 125 | #define AR913X_RESET_REG_GLOBAL_INT_STATUS 0x18 | ||
| 126 | #define AR913X_RESET_REG_RESET_MODULE 0x1c | ||
| 127 | #define AR913X_RESET_REG_PERF_CTRL 0x20 | ||
| 128 | #define AR913X_RESET_REG_PERFC0 0x24 | ||
| 129 | #define AR913X_RESET_REG_PERFC1 0x28 | ||
| 130 | |||
| 131 | #define AR724X_RESET_REG_RESET_MODULE 0x1c | ||
| 132 | |||
| 133 | #define MISC_INT_DMA BIT(7) | ||
| 134 | #define MISC_INT_OHCI BIT(6) | ||
| 135 | #define MISC_INT_PERFC BIT(5) | ||
| 136 | #define MISC_INT_WDOG BIT(4) | ||
| 137 | #define MISC_INT_UART BIT(3) | ||
| 138 | #define MISC_INT_GPIO BIT(2) | ||
| 139 | #define MISC_INT_ERROR BIT(1) | ||
| 140 | #define MISC_INT_TIMER BIT(0) | ||
| 141 | |||
| 142 | #define AR71XX_RESET_EXTERNAL BIT(28) | ||
| 143 | #define AR71XX_RESET_FULL_CHIP BIT(24) | ||
| 144 | #define AR71XX_RESET_CPU_NMI BIT(21) | ||
| 145 | #define AR71XX_RESET_CPU_COLD BIT(20) | ||
| 146 | #define AR71XX_RESET_DMA BIT(19) | ||
| 147 | #define AR71XX_RESET_SLIC BIT(18) | ||
| 148 | #define AR71XX_RESET_STEREO BIT(17) | ||
| 149 | #define AR71XX_RESET_DDR BIT(16) | ||
| 150 | #define AR71XX_RESET_GE1_MAC BIT(13) | ||
| 151 | #define AR71XX_RESET_GE1_PHY BIT(12) | ||
| 152 | #define AR71XX_RESET_USBSUS_OVERRIDE BIT(10) | ||
| 153 | #define AR71XX_RESET_GE0_MAC BIT(9) | ||
| 154 | #define AR71XX_RESET_GE0_PHY BIT(8) | ||
| 155 | #define AR71XX_RESET_USB_OHCI_DLL BIT(6) | ||
| 156 | #define AR71XX_RESET_USB_HOST BIT(5) | ||
| 157 | #define AR71XX_RESET_USB_PHY BIT(4) | ||
| 158 | #define AR71XX_RESET_PCI_BUS BIT(1) | ||
| 159 | #define AR71XX_RESET_PCI_CORE BIT(0) | ||
| 160 | |||
| 161 | #define AR724X_RESET_GE1_MDIO BIT(23) | ||
| 162 | #define AR724X_RESET_GE0_MDIO BIT(22) | ||
| 163 | #define AR724X_RESET_PCIE_PHY_SERIAL BIT(10) | ||
| 164 | #define AR724X_RESET_PCIE_PHY BIT(7) | ||
| 165 | #define AR724X_RESET_PCIE BIT(6) | ||
| 166 | #define AR724X_RESET_OHCI_DLL BIT(3) | ||
| 167 | |||
| 168 | #define AR913X_RESET_AMBA2WMAC BIT(22) | ||
| 169 | |||
| 170 | #define REV_ID_MAJOR_MASK 0xfff0 | ||
| 171 | #define REV_ID_MAJOR_AR71XX 0x00a0 | ||
| 172 | #define REV_ID_MAJOR_AR913X 0x00b0 | ||
| 173 | #define REV_ID_MAJOR_AR7240 0x00c0 | ||
| 174 | #define REV_ID_MAJOR_AR7241 0x0100 | ||
| 175 | #define REV_ID_MAJOR_AR7242 0x1100 | ||
| 176 | |||
| 177 | #define AR71XX_REV_ID_MINOR_MASK 0x3 | ||
| 178 | #define AR71XX_REV_ID_MINOR_AR7130 0x0 | ||
| 179 | #define AR71XX_REV_ID_MINOR_AR7141 0x1 | ||
| 180 | #define AR71XX_REV_ID_MINOR_AR7161 0x2 | ||
| 181 | #define AR71XX_REV_ID_REVISION_MASK 0x3 | ||
| 182 | #define AR71XX_REV_ID_REVISION_SHIFT 2 | ||
| 183 | |||
| 184 | #define AR913X_REV_ID_MINOR_MASK 0x3 | ||
| 185 | #define AR913X_REV_ID_MINOR_AR9130 0x0 | ||
| 186 | #define AR913X_REV_ID_MINOR_AR9132 0x1 | ||
| 187 | #define AR913X_REV_ID_REVISION_MASK 0x3 | ||
| 188 | #define AR913X_REV_ID_REVISION_SHIFT 2 | ||
| 189 | |||
| 190 | #define AR724X_REV_ID_REVISION_MASK 0x3 | ||
| 191 | |||
| 192 | /* | ||
| 193 | * SPI block | ||
| 194 | */ | ||
| 195 | #define AR71XX_SPI_REG_FS 0x00 /* Function Select */ | ||
| 196 | #define AR71XX_SPI_REG_CTRL 0x04 /* SPI Control */ | ||
| 197 | #define AR71XX_SPI_REG_IOC 0x08 /* SPI I/O Control */ | ||
| 198 | #define AR71XX_SPI_REG_RDS 0x0c /* Read Data Shift */ | ||
| 199 | |||
| 200 | #define AR71XX_SPI_FS_GPIO BIT(0) /* Enable GPIO mode */ | ||
| 201 | |||
| 202 | #define AR71XX_SPI_CTRL_RD BIT(6) /* Remap Disable */ | ||
| 203 | #define AR71XX_SPI_CTRL_DIV_MASK 0x3f | ||
| 204 | |||
| 205 | #define AR71XX_SPI_IOC_DO BIT(0) /* Data Out pin */ | ||
| 206 | #define AR71XX_SPI_IOC_CLK BIT(8) /* CLK pin */ | ||
| 207 | #define AR71XX_SPI_IOC_CS(n) BIT(16 + (n)) | ||
| 208 | #define AR71XX_SPI_IOC_CS0 AR71XX_SPI_IOC_CS(0) | ||
| 209 | #define AR71XX_SPI_IOC_CS1 AR71XX_SPI_IOC_CS(1) | ||
| 210 | #define AR71XX_SPI_IOC_CS2 AR71XX_SPI_IOC_CS(2) | ||
| 211 | #define AR71XX_SPI_IOC_CS_ALL (AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1 | \ | ||
| 212 | AR71XX_SPI_IOC_CS2) | ||
| 213 | |||
| 214 | /* | ||
| 215 | * GPIO block | ||
| 216 | */ | ||
| 217 | #define AR71XX_GPIO_REG_OE 0x00 | ||
| 218 | #define AR71XX_GPIO_REG_IN 0x04 | ||
| 219 | #define AR71XX_GPIO_REG_OUT 0x08 | ||
| 220 | #define AR71XX_GPIO_REG_SET 0x0c | ||
| 221 | #define AR71XX_GPIO_REG_CLEAR 0x10 | ||
| 222 | #define AR71XX_GPIO_REG_INT_MODE 0x14 | ||
| 223 | #define AR71XX_GPIO_REG_INT_TYPE 0x18 | ||
| 224 | #define AR71XX_GPIO_REG_INT_POLARITY 0x1c | ||
| 225 | #define AR71XX_GPIO_REG_INT_PENDING 0x20 | ||
| 226 | #define AR71XX_GPIO_REG_INT_ENABLE 0x24 | ||
| 227 | #define AR71XX_GPIO_REG_FUNC 0x28 | ||
| 228 | |||
| 229 | #define AR71XX_GPIO_COUNT 16 | ||
| 230 | #define AR724X_GPIO_COUNT 18 | ||
| 231 | #define AR913X_GPIO_COUNT 22 | ||
| 232 | |||
| 233 | #endif /* __ASM_MACH_AR71XX_REGS_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/ath79.h b/arch/mips/include/asm/mach-ath79/ath79.h new file mode 100644 index 000000000000..6a9f168506fe --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/ath79.h | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X common definitions | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * Parts of this file are based on Atheros' 2.6.15 BSP | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License version 2 as published | ||
| 11 | * by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef __ASM_MACH_ATH79_H | ||
| 15 | #define __ASM_MACH_ATH79_H | ||
| 16 | |||
| 17 | #include <linux/types.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | |||
| 20 | enum ath79_soc_type { | ||
| 21 | ATH79_SOC_UNKNOWN, | ||
| 22 | ATH79_SOC_AR7130, | ||
| 23 | ATH79_SOC_AR7141, | ||
| 24 | ATH79_SOC_AR7161, | ||
| 25 | ATH79_SOC_AR7240, | ||
| 26 | ATH79_SOC_AR7241, | ||
| 27 | ATH79_SOC_AR7242, | ||
| 28 | ATH79_SOC_AR9130, | ||
| 29 | ATH79_SOC_AR9132 | ||
| 30 | }; | ||
| 31 | |||
| 32 | extern enum ath79_soc_type ath79_soc; | ||
| 33 | |||
| 34 | static inline int soc_is_ar71xx(void) | ||
| 35 | { | ||
| 36 | return (ath79_soc == ATH79_SOC_AR7130 || | ||
| 37 | ath79_soc == ATH79_SOC_AR7141 || | ||
| 38 | ath79_soc == ATH79_SOC_AR7161); | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline int soc_is_ar724x(void) | ||
| 42 | { | ||
| 43 | return (ath79_soc == ATH79_SOC_AR7240 || | ||
| 44 | ath79_soc == ATH79_SOC_AR7241 || | ||
| 45 | ath79_soc == ATH79_SOC_AR7242); | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline int soc_is_ar7240(void) | ||
| 49 | { | ||
| 50 | return (ath79_soc == ATH79_SOC_AR7240); | ||
| 51 | } | ||
| 52 | |||
| 53 | static inline int soc_is_ar7241(void) | ||
| 54 | { | ||
| 55 | return (ath79_soc == ATH79_SOC_AR7241); | ||
| 56 | } | ||
| 57 | |||
| 58 | static inline int soc_is_ar7242(void) | ||
| 59 | { | ||
| 60 | return (ath79_soc == ATH79_SOC_AR7242); | ||
| 61 | } | ||
| 62 | |||
| 63 | static inline int soc_is_ar913x(void) | ||
| 64 | { | ||
| 65 | return (ath79_soc == ATH79_SOC_AR9130 || | ||
| 66 | ath79_soc == ATH79_SOC_AR9132); | ||
| 67 | } | ||
| 68 | |||
| 69 | extern void __iomem *ath79_ddr_base; | ||
| 70 | extern void __iomem *ath79_pll_base; | ||
| 71 | extern void __iomem *ath79_reset_base; | ||
| 72 | |||
| 73 | static inline void ath79_pll_wr(unsigned reg, u32 val) | ||
| 74 | { | ||
| 75 | __raw_writel(val, ath79_pll_base + reg); | ||
| 76 | } | ||
| 77 | |||
| 78 | static inline u32 ath79_pll_rr(unsigned reg) | ||
| 79 | { | ||
| 80 | return __raw_readl(ath79_pll_base + reg); | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline void ath79_reset_wr(unsigned reg, u32 val) | ||
| 84 | { | ||
| 85 | __raw_writel(val, ath79_reset_base + reg); | ||
| 86 | } | ||
| 87 | |||
| 88 | static inline u32 ath79_reset_rr(unsigned reg) | ||
| 89 | { | ||
| 90 | return __raw_readl(ath79_reset_base + reg); | ||
| 91 | } | ||
| 92 | |||
| 93 | void ath79_device_reset_set(u32 mask); | ||
| 94 | void ath79_device_reset_clear(u32 mask); | ||
| 95 | |||
| 96 | #endif /* __ASM_MACH_ATH79_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h new file mode 100644 index 000000000000..aa2283e602fc --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Platform data definition for Atheros AR71XX/AR724X/AR913X SPI controller | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License version 2 as published | ||
| 8 | * by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef _ATH79_SPI_PLATFORM_H | ||
| 12 | #define _ATH79_SPI_PLATFORM_H | ||
| 13 | |||
| 14 | struct ath79_spi_platform_data { | ||
| 15 | unsigned bus_num; | ||
| 16 | unsigned num_chipselect; | ||
| 17 | }; | ||
| 18 | |||
| 19 | struct ath79_spi_controller_data { | ||
| 20 | unsigned gpio; | ||
| 21 | }; | ||
| 22 | |||
| 23 | #endif /* _ATH79_SPI_PLATFORM_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h new file mode 100644 index 000000000000..4476fa03bf36 --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X specific CPU feature overrides | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This file was derived from: include/asm-mips/cpu-features.h | ||
| 8 | * Copyright (C) 2003, 2004 Ralf Baechle | ||
| 9 | * Copyright (C) 2004 Maciej W. Rozycki | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify it | ||
| 12 | * under the terms of the GNU General Public License version 2 as published | ||
| 13 | * by the Free Software Foundation. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H | ||
| 17 | #define __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H | ||
| 18 | |||
| 19 | #define cpu_has_tlb 1 | ||
| 20 | #define cpu_has_4kex 1 | ||
| 21 | #define cpu_has_3k_cache 0 | ||
| 22 | #define cpu_has_4k_cache 1 | ||
| 23 | #define cpu_has_tx39_cache 0 | ||
| 24 | #define cpu_has_sb1_cache 0 | ||
| 25 | #define cpu_has_fpu 0 | ||
| 26 | #define cpu_has_32fpr 0 | ||
| 27 | #define cpu_has_counter 1 | ||
| 28 | #define cpu_has_watch 1 | ||
| 29 | #define cpu_has_divec 1 | ||
| 30 | |||
| 31 | #define cpu_has_prefetch 1 | ||
| 32 | #define cpu_has_ejtag 1 | ||
| 33 | #define cpu_has_llsc 1 | ||
| 34 | |||
| 35 | #define cpu_has_mips16 1 | ||
| 36 | #define cpu_has_mdmx 0 | ||
| 37 | #define cpu_has_mips3d 0 | ||
| 38 | #define cpu_has_smartmips 0 | ||
| 39 | |||
| 40 | #define cpu_has_mips32r1 1 | ||
| 41 | #define cpu_has_mips32r2 1 | ||
| 42 | #define cpu_has_mips64r1 0 | ||
| 43 | #define cpu_has_mips64r2 0 | ||
| 44 | |||
| 45 | #define cpu_has_dsp 0 | ||
| 46 | #define cpu_has_mipsmt 0 | ||
| 47 | |||
| 48 | #define cpu_has_64bits 0 | ||
| 49 | #define cpu_has_64bit_zero_reg 0 | ||
| 50 | #define cpu_has_64bit_gp_regs 0 | ||
| 51 | #define cpu_has_64bit_addresses 0 | ||
| 52 | |||
| 53 | #define cpu_dcache_line_size() 32 | ||
| 54 | #define cpu_icache_line_size() 32 | ||
| 55 | |||
| 56 | #endif /* __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/gpio.h b/arch/mips/include/asm/mach-ath79/gpio.h new file mode 100644 index 000000000000..60dcb62785b4 --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/gpio.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X GPIO API definitions | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #ifndef __ASM_MACH_ATH79_GPIO_H | ||
| 14 | #define __ASM_MACH_ATH79_GPIO_H | ||
| 15 | |||
| 16 | #define ARCH_NR_GPIOS 64 | ||
| 17 | #include <asm-generic/gpio.h> | ||
| 18 | |||
| 19 | int gpio_to_irq(unsigned gpio); | ||
| 20 | int irq_to_gpio(unsigned irq); | ||
| 21 | int gpio_get_value(unsigned gpio); | ||
| 22 | void gpio_set_value(unsigned gpio, int value); | ||
| 23 | |||
| 24 | #define gpio_cansleep __gpio_cansleep | ||
| 25 | |||
| 26 | #endif /* __ASM_MACH_ATH79_GPIO_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/irq.h b/arch/mips/include/asm/mach-ath79/irq.h new file mode 100644 index 000000000000..189bc6eb9c10 --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/irq.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 3 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published | ||
| 7 | * by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | #ifndef __ASM_MACH_ATH79_IRQ_H | ||
| 10 | #define __ASM_MACH_ATH79_IRQ_H | ||
| 11 | |||
| 12 | #define MIPS_CPU_IRQ_BASE 0 | ||
| 13 | #define NR_IRQS 16 | ||
| 14 | |||
| 15 | #define ATH79_MISC_IRQ_BASE 8 | ||
| 16 | #define ATH79_MISC_IRQ_COUNT 8 | ||
| 17 | |||
| 18 | #define ATH79_CPU_IRQ_IP2 (MIPS_CPU_IRQ_BASE + 2) | ||
| 19 | #define ATH79_CPU_IRQ_USB (MIPS_CPU_IRQ_BASE + 3) | ||
| 20 | #define ATH79_CPU_IRQ_GE0 (MIPS_CPU_IRQ_BASE + 4) | ||
| 21 | #define ATH79_CPU_IRQ_GE1 (MIPS_CPU_IRQ_BASE + 5) | ||
| 22 | #define ATH79_CPU_IRQ_MISC (MIPS_CPU_IRQ_BASE + 6) | ||
| 23 | #define ATH79_CPU_IRQ_TIMER (MIPS_CPU_IRQ_BASE + 7) | ||
| 24 | |||
| 25 | #define ATH79_MISC_IRQ_TIMER (ATH79_MISC_IRQ_BASE + 0) | ||
| 26 | #define ATH79_MISC_IRQ_ERROR (ATH79_MISC_IRQ_BASE + 1) | ||
| 27 | #define ATH79_MISC_IRQ_GPIO (ATH79_MISC_IRQ_BASE + 2) | ||
| 28 | #define ATH79_MISC_IRQ_UART (ATH79_MISC_IRQ_BASE + 3) | ||
| 29 | #define ATH79_MISC_IRQ_WDOG (ATH79_MISC_IRQ_BASE + 4) | ||
| 30 | #define ATH79_MISC_IRQ_PERFC (ATH79_MISC_IRQ_BASE + 5) | ||
| 31 | #define ATH79_MISC_IRQ_OHCI (ATH79_MISC_IRQ_BASE + 6) | ||
| 32 | #define ATH79_MISC_IRQ_DMA (ATH79_MISC_IRQ_BASE + 7) | ||
| 33 | |||
| 34 | #include_next <irq.h> | ||
| 35 | |||
| 36 | #endif /* __ASM_MACH_ATH79_IRQ_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/kernel-entry-init.h b/arch/mips/include/asm/mach-ath79/kernel-entry-init.h new file mode 100644 index 000000000000..d8d046bccc8e --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/kernel-entry-init.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X specific kernel entry setup | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License version 2 as published | ||
| 8 | * by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | #ifndef __ASM_MACH_ATH79_KERNEL_ENTRY_H | ||
| 12 | #define __ASM_MACH_ATH79_KERNEL_ENTRY_H | ||
| 13 | |||
| 14 | /* | ||
| 15 | * Some bootloaders set the 'Kseg0 coherency algorithm' to | ||
| 16 | * 'Cacheable, noncoherent, write-through, no write allocate' | ||
| 17 | * and this cause performance issues. Let's go and change it to | ||
| 18 | * 'Cacheable, noncoherent, write-back, write allocate' | ||
| 19 | */ | ||
| 20 | .macro kernel_entry_setup | ||
| 21 | mfc0 t0, CP0_CONFIG | ||
| 22 | li t1, ~CONF_CM_CMASK | ||
| 23 | and t0, t1 | ||
| 24 | ori t0, CONF_CM_CACHABLE_NONCOHERENT | ||
| 25 | mtc0 t0, CP0_CONFIG | ||
| 26 | nop | ||
| 27 | .endm | ||
| 28 | |||
| 29 | .macro smp_slave_setup | ||
| 30 | .endm | ||
| 31 | |||
| 32 | #endif /* __ASM_MACH_ATH79_KERNEL_ENTRY_H */ | ||
diff --git a/arch/mips/include/asm/mach-ath79/war.h b/arch/mips/include/asm/mach-ath79/war.h new file mode 100644 index 000000000000..323d9f1d8c45 --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/war.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | /* | ||
| 2 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 3 | * License. See the file "COPYING" in the main directory of this archive | ||
| 4 | * for more details. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org> | ||
| 7 | */ | ||
| 8 | #ifndef __ASM_MACH_ATH79_WAR_H | ||
| 9 | #define __ASM_MACH_ATH79_WAR_H | ||
| 10 | |||
| 11 | #define R4600_V1_INDEX_ICACHEOP_WAR 0 | ||
| 12 | #define R4600_V1_HIT_CACHEOP_WAR 0 | ||
| 13 | #define R4600_V2_HIT_CACHEOP_WAR 0 | ||
| 14 | #define R5432_CP0_INTERRUPT_WAR 0 | ||
| 15 | #define BCM1250_M3_WAR 0 | ||
| 16 | #define SIBYTE_1956_WAR 0 | ||
| 17 | #define MIPS4K_ICACHE_REFILL_WAR 0 | ||
| 18 | #define MIPS_CACHE_SYNC_WAR 0 | ||
| 19 | #define TX49XX_ICACHE_INDEX_INV_WAR 0 | ||
| 20 | #define RM9000_CDEX_SMP_WAR 0 | ||
| 21 | #define ICACHE_REFILLS_WORKAROUND_WAR 0 | ||
| 22 | #define R10000_LLSC_WAR 0 | ||
| 23 | #define MIPS34K_MISSED_ITLB_WAR 0 | ||
| 24 | |||
| 25 | #endif /* __ASM_MACH_ATH79_WAR_H */ | ||
diff --git a/arch/mips/include/asm/mips_machine.h b/arch/mips/include/asm/mips_machine.h new file mode 100644 index 000000000000..363bb352c7f7 --- /dev/null +++ b/arch/mips/include/asm/mips_machine.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms of the GNU General Public License version 2 as published | ||
| 6 | * by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef __ASM_MIPS_MACHINE_H | ||
| 11 | #define __ASM_MIPS_MACHINE_H | ||
| 12 | |||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/stddef.h> | ||
| 15 | |||
| 16 | #include <asm/bootinfo.h> | ||
| 17 | |||
| 18 | struct mips_machine { | ||
| 19 | unsigned long mach_type; | ||
| 20 | const char *mach_id; | ||
| 21 | const char *mach_name; | ||
| 22 | void (*mach_setup)(void); | ||
| 23 | }; | ||
| 24 | |||
| 25 | #define MIPS_MACHINE(_type, _id, _name, _setup) \ | ||
| 26 | static const char machine_name_##_type[] __initconst \ | ||
| 27 | __aligned(1) = _name; \ | ||
| 28 | static const char machine_id_##_type[] __initconst \ | ||
| 29 | __aligned(1) = _id; \ | ||
| 30 | static struct mips_machine machine_##_type \ | ||
| 31 | __used __section(.mips.machines.init) = \ | ||
| 32 | { \ | ||
| 33 | .mach_type = _type, \ | ||
| 34 | .mach_id = machine_id_##_type, \ | ||
| 35 | .mach_name = machine_name_##_type, \ | ||
| 36 | .mach_setup = _setup, \ | ||
| 37 | }; | ||
| 38 | |||
| 39 | extern long __mips_machines_start; | ||
| 40 | extern long __mips_machines_end; | ||
| 41 | |||
| 42 | #ifdef CONFIG_MIPS_MACHINE | ||
| 43 | int mips_machtype_setup(char *id) __init; | ||
| 44 | void mips_machine_setup(void) __init; | ||
| 45 | void mips_set_machine_name(const char *name) __init; | ||
| 46 | char *mips_get_machine_name(void); | ||
| 47 | #else | ||
| 48 | static inline int mips_machtype_setup(char *id) { return 1; } | ||
| 49 | static inline void mips_machine_setup(void) { } | ||
| 50 | static inline void mips_set_machine_name(const char *name) { } | ||
| 51 | static inline char *mips_get_machine_name(void) { return NULL; } | ||
| 52 | #endif /* CONFIG_MIPS_MACHINE */ | ||
| 53 | |||
| 54 | #endif /* __ASM_MIPS_MACHINE_H */ | ||
diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h index d9592733a7ba..73c0d45798de 100644 --- a/arch/mips/include/asm/mmu_context.h +++ b/arch/mips/include/asm/mmu_context.h | |||
| @@ -29,13 +29,7 @@ | |||
| 29 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ | 29 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ |
| 30 | tlbmiss_handler_setup_pgd((unsigned long)(pgd)) | 30 | tlbmiss_handler_setup_pgd((unsigned long)(pgd)) |
| 31 | 31 | ||
| 32 | static inline void tlbmiss_handler_setup_pgd(unsigned long pgd) | 32 | extern void tlbmiss_handler_setup_pgd(unsigned long pgd); |
| 33 | { | ||
| 34 | /* Check for swapper_pg_dir and convert to physical address. */ | ||
| 35 | if ((pgd & CKSEG3) == CKSEG0) | ||
| 36 | pgd = CPHYSADDR(pgd); | ||
| 37 | write_c0_context(pgd << 11); | ||
| 38 | } | ||
| 39 | 33 | ||
| 40 | #define TLBMISS_HANDLER_SETUP() \ | 34 | #define TLBMISS_HANDLER_SETUP() \ |
| 41 | do { \ | 35 | do { \ |
diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h index 892062d6d748..dcbd4bb417ec 100644 --- a/arch/mips/include/asm/uasm.h +++ b/arch/mips/include/asm/uasm.h | |||
| @@ -115,7 +115,12 @@ Ip_0(_tlbwr); | |||
| 115 | Ip_u3u1u2(_xor); | 115 | Ip_u3u1u2(_xor); |
| 116 | Ip_u2u1u3(_xori); | 116 | Ip_u2u1u3(_xori); |
| 117 | Ip_u2u1msbu3(_dins); | 117 | Ip_u2u1msbu3(_dins); |
| 118 | Ip_u2u1msbu3(_dinsm); | ||
| 118 | Ip_u1(_syscall); | 119 | Ip_u1(_syscall); |
| 120 | Ip_u1u2s3(_bbit0); | ||
| 121 | Ip_u1u2s3(_bbit1); | ||
| 122 | Ip_u3u1u2(_lwx); | ||
| 123 | Ip_u3u1u2(_ldx); | ||
| 119 | 124 | ||
| 120 | /* Handle labels. */ | 125 | /* Handle labels. */ |
| 121 | struct uasm_label { | 126 | struct uasm_label { |
| @@ -153,6 +158,7 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \ | |||
| 153 | # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd) | 158 | # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd) |
| 154 | # define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off) | 159 | # define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off) |
| 155 | # define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off) | 160 | # define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off) |
| 161 | # define UASM_i_LWX(buf, rs, rt, rd) uasm_i_ldx(buf, rs, rt, rd) | ||
| 156 | #else | 162 | #else |
| 157 | # define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off) | 163 | # define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off) |
| 158 | # define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off) | 164 | # define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off) |
| @@ -167,6 +173,7 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \ | |||
| 167 | # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd) | 173 | # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd) |
| 168 | # define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off) | 174 | # define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off) |
| 169 | # define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off) | 175 | # define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off) |
| 176 | # define UASM_i_LWX(buf, rs, rt, rd) uasm_i_lwx(buf, rs, rt, rd) | ||
| 170 | #endif | 177 | #endif |
| 171 | 178 | ||
| 172 | #define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off) | 179 | #define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off) |
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 22b2e0e38617..cedee2bcbd18 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile | |||
| @@ -95,6 +95,7 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o | |||
| 95 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 95 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
| 96 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 96 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
| 97 | obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o | 97 | obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o |
| 98 | obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o | ||
| 98 | 99 | ||
| 99 | obj-$(CONFIG_OF) += prom.o | 100 | obj-$(CONFIG_OF) += prom.o |
| 100 | 101 | ||
| @@ -106,4 +107,6 @@ obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/ | |||
| 106 | 107 | ||
| 107 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o | 108 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o |
| 108 | 109 | ||
| 110 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o | ||
| 111 | |||
| 109 | CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS) | 112 | CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS) |
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 68dae7b6b5db..f65d4c8c65a6 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c | |||
| @@ -739,6 +739,8 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) | |||
| 739 | && cpu_has_tlb) | 739 | && cpu_has_tlb) |
| 740 | c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; | 740 | c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; |
| 741 | 741 | ||
| 742 | c->kscratch_mask = (config4 >> 16) & 0xff; | ||
| 743 | |||
| 742 | return config4 & MIPS_CONF_M; | 744 | return config4 & MIPS_CONF_M; |
| 743 | } | 745 | } |
| 744 | 746 | ||
diff --git a/arch/mips/kernel/jump_label.c b/arch/mips/kernel/jump_label.c new file mode 100644 index 000000000000..6001610cfe55 --- /dev/null +++ b/arch/mips/kernel/jump_label.c | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* | ||
| 2 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 3 | * License. See the file "COPYING" in the main directory of this archive | ||
| 4 | * for more details. | ||
| 5 | * | ||
| 6 | * Copyright (c) 2010 Cavium Networks, Inc. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/jump_label.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/memory.h> | ||
| 12 | #include <linux/mutex.h> | ||
| 13 | #include <linux/types.h> | ||
| 14 | #include <linux/cpu.h> | ||
| 15 | |||
| 16 | #include <asm/cacheflush.h> | ||
| 17 | #include <asm/inst.h> | ||
| 18 | |||
| 19 | #ifdef HAVE_JUMP_LABEL | ||
| 20 | |||
| 21 | #define J_RANGE_MASK ((1ul << 28) - 1) | ||
| 22 | |||
| 23 | void arch_jump_label_transform(struct jump_entry *e, | ||
| 24 | enum jump_label_type type) | ||
| 25 | { | ||
| 26 | union mips_instruction insn; | ||
| 27 | union mips_instruction *insn_p = | ||
| 28 | (union mips_instruction *)(unsigned long)e->code; | ||
| 29 | |||
| 30 | /* Jump only works within a 256MB aligned region. */ | ||
| 31 | BUG_ON((e->target & ~J_RANGE_MASK) != (e->code & ~J_RANGE_MASK)); | ||
| 32 | |||
| 33 | /* Target must have 4 byte alignment. */ | ||
| 34 | BUG_ON((e->target & 3) != 0); | ||
| 35 | |||
| 36 | if (type == JUMP_LABEL_ENABLE) { | ||
| 37 | insn.j_format.opcode = j_op; | ||
| 38 | insn.j_format.target = (e->target & J_RANGE_MASK) >> 2; | ||
| 39 | } else { | ||
| 40 | insn.word = 0; /* nop */ | ||
| 41 | } | ||
| 42 | |||
| 43 | get_online_cpus(); | ||
| 44 | mutex_lock(&text_mutex); | ||
| 45 | *insn_p = insn; | ||
| 46 | |||
| 47 | flush_icache_range((unsigned long)insn_p, | ||
| 48 | (unsigned long)insn_p + sizeof(*insn_p)); | ||
| 49 | |||
| 50 | mutex_unlock(&text_mutex); | ||
| 51 | put_online_cpus(); | ||
| 52 | } | ||
| 53 | |||
| 54 | #endif /* HAVE_JUMP_LABEL */ | ||
diff --git a/arch/mips/kernel/mips_machine.c b/arch/mips/kernel/mips_machine.c new file mode 100644 index 000000000000..411a058d2c53 --- /dev/null +++ b/arch/mips/kernel/mips_machine.c | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms of the GNU General Public License version 2 as published | ||
| 6 | * by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | */ | ||
| 9 | #include <linux/mm.h> | ||
| 10 | #include <linux/string.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | |||
| 13 | #include <asm/mips_machine.h> | ||
| 14 | |||
| 15 | static struct mips_machine *mips_machine __initdata; | ||
| 16 | static char *mips_machine_name = "Unknown"; | ||
| 17 | |||
| 18 | #define for_each_machine(mach) \ | ||
| 19 | for ((mach) = (struct mips_machine *)&__mips_machines_start; \ | ||
| 20 | (mach) && \ | ||
| 21 | (unsigned long)(mach) < (unsigned long)&__mips_machines_end; \ | ||
| 22 | (mach)++) | ||
| 23 | |||
| 24 | __init void mips_set_machine_name(const char *name) | ||
| 25 | { | ||
| 26 | char *p; | ||
| 27 | |||
| 28 | if (name == NULL) | ||
| 29 | return; | ||
| 30 | |||
| 31 | p = kstrdup(name, GFP_KERNEL); | ||
| 32 | if (!p) | ||
| 33 | pr_err("MIPS: no memory for machine_name\n"); | ||
| 34 | |||
| 35 | mips_machine_name = p; | ||
| 36 | } | ||
| 37 | |||
| 38 | char *mips_get_machine_name(void) | ||
| 39 | { | ||
| 40 | return mips_machine_name; | ||
| 41 | } | ||
| 42 | |||
| 43 | __init int mips_machtype_setup(char *id) | ||
| 44 | { | ||
| 45 | struct mips_machine *mach; | ||
| 46 | |||
| 47 | for_each_machine(mach) { | ||
| 48 | if (mach->mach_id == NULL) | ||
| 49 | continue; | ||
| 50 | |||
| 51 | if (strcmp(mach->mach_id, id) == 0) { | ||
| 52 | mips_machtype = mach->mach_type; | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | pr_err("MIPS: no machine found for id '%s', supported machines:\n", id); | ||
| 58 | pr_err("%-24s %s\n", "id", "name"); | ||
| 59 | for_each_machine(mach) | ||
| 60 | pr_err("%-24s %s\n", mach->mach_id, mach->mach_name); | ||
| 61 | |||
| 62 | return 1; | ||
| 63 | } | ||
| 64 | |||
| 65 | __setup("machtype=", mips_machtype_setup); | ||
| 66 | |||
| 67 | __init void mips_machine_setup(void) | ||
| 68 | { | ||
| 69 | struct mips_machine *mach; | ||
| 70 | |||
| 71 | for_each_machine(mach) { | ||
| 72 | if (mips_machtype == mach->mach_type) { | ||
| 73 | mips_machine = mach; | ||
| 74 | break; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | if (!mips_machine) | ||
| 79 | return; | ||
| 80 | |||
| 81 | mips_set_machine_name(mips_machine->mach_name); | ||
| 82 | pr_info("MIPS: machine is %s\n", mips_machine_name); | ||
| 83 | |||
| 84 | if (mips_machine->mach_setup) | ||
| 85 | mips_machine->mach_setup(); | ||
| 86 | } | ||
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index d87a72e9fac7..dd940b701963 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c | |||
| @@ -30,6 +30,8 @@ | |||
| 30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
| 31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
| 32 | #include <linux/spinlock.h> | 32 | #include <linux/spinlock.h> |
| 33 | #include <linux/jump_label.h> | ||
| 34 | |||
| 33 | #include <asm/pgtable.h> /* MODULE_START */ | 35 | #include <asm/pgtable.h> /* MODULE_START */ |
| 34 | 36 | ||
| 35 | struct mips_hi16 { | 37 | struct mips_hi16 { |
| @@ -382,6 +384,9 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
| 382 | const Elf_Shdr *s; | 384 | const Elf_Shdr *s; |
| 383 | char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 385 | char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
| 384 | 386 | ||
| 387 | /* Make jump label nops. */ | ||
| 388 | jump_label_apply_nops(me); | ||
| 389 | |||
| 385 | INIT_LIST_HEAD(&me->arch.dbe_list); | 390 | INIT_LIST_HEAD(&me->arch.dbe_list); |
| 386 | for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { | 391 | for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { |
| 387 | if (strcmp("__dbe_table", secstrings + s->sh_name) != 0) | 392 | if (strcmp("__dbe_table", secstrings + s->sh_name) != 0) |
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 26109c4d5170..e309665b6c81 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <asm/cpu-features.h> | 12 | #include <asm/cpu-features.h> |
| 13 | #include <asm/mipsregs.h> | 13 | #include <asm/mipsregs.h> |
| 14 | #include <asm/processor.h> | 14 | #include <asm/processor.h> |
| 15 | #include <asm/mips_machine.h> | ||
| 15 | 16 | ||
| 16 | unsigned int vced_count, vcei_count; | 17 | unsigned int vced_count, vcei_count; |
| 17 | 18 | ||
| @@ -31,8 +32,12 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
| 31 | /* | 32 | /* |
| 32 | * For the first processor also print the system type | 33 | * For the first processor also print the system type |
| 33 | */ | 34 | */ |
| 34 | if (n == 0) | 35 | if (n == 0) { |
| 35 | seq_printf(m, "system type\t\t: %s\n", get_system_type()); | 36 | seq_printf(m, "system type\t\t: %s\n", get_system_type()); |
| 37 | if (mips_get_machine_name()) | ||
| 38 | seq_printf(m, "machine\t\t\t: %s\n", | ||
| 39 | mips_get_machine_name()); | ||
| 40 | } | ||
| 36 | 41 | ||
| 37 | seq_printf(m, "processor\t\t: %ld\n", n); | 42 | seq_printf(m, "processor\t\t: %ld\n", n); |
| 38 | sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", | 43 | sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", |
| @@ -69,6 +74,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
| 69 | ); | 74 | ); |
| 70 | seq_printf(m, "shadow register sets\t: %d\n", | 75 | seq_printf(m, "shadow register sets\t: %d\n", |
| 71 | cpu_data[n].srsets); | 76 | cpu_data[n].srsets); |
| 77 | seq_printf(m, "kscratch registers\t: %d\n", | ||
| 78 | hweight8(cpu_data[n].kscratch_mask)); | ||
| 72 | seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); | 79 | seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); |
| 73 | 80 | ||
| 74 | sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", | 81 | sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", |
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index acd3f2c49c06..8ad1d5679f14 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c | |||
| @@ -70,7 +70,7 @@ static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; | |||
| 70 | * mips_io_port_base is the begin of the address space to which x86 style | 70 | * mips_io_port_base is the begin of the address space to which x86 style |
| 71 | * I/O ports are mapped. | 71 | * I/O ports are mapped. |
| 72 | */ | 72 | */ |
| 73 | const unsigned long mips_io_port_base __read_mostly = -1; | 73 | const unsigned long mips_io_port_base = -1; |
| 74 | EXPORT_SYMBOL(mips_io_port_base); | 74 | EXPORT_SYMBOL(mips_io_port_base); |
| 75 | 75 | ||
| 76 | static struct resource code_resource = { .name = "Kernel code", }; | 76 | static struct resource code_resource = { .name = "Kernel code", }; |
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index e97104302541..71350f7f2d88 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
| @@ -1592,7 +1592,6 @@ void __cpuinit per_cpu_trap_init(void) | |||
| 1592 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1592 | #endif /* CONFIG_MIPS_MT_SMTC */ |
| 1593 | 1593 | ||
| 1594 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; | 1594 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; |
| 1595 | TLBMISS_HANDLER_SETUP(); | ||
| 1596 | 1595 | ||
| 1597 | atomic_inc(&init_mm.mm_count); | 1596 | atomic_inc(&init_mm.mm_count); |
| 1598 | current->active_mm = &init_mm; | 1597 | current->active_mm = &init_mm; |
| @@ -1614,6 +1613,7 @@ void __cpuinit per_cpu_trap_init(void) | |||
| 1614 | write_c0_wired(0); | 1613 | write_c0_wired(0); |
| 1615 | } | 1614 | } |
| 1616 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1615 | #endif /* CONFIG_MIPS_MT_SMTC */ |
| 1616 | TLBMISS_HANDLER_SETUP(); | ||
| 1617 | } | 1617 | } |
| 1618 | 1618 | ||
| 1619 | /* Install CPU exception handler */ | 1619 | /* Install CPU exception handler */ |
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index f25df73db923..570607b376b5 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S | |||
| @@ -98,6 +98,13 @@ SECTIONS | |||
| 98 | INIT_TEXT_SECTION(PAGE_SIZE) | 98 | INIT_TEXT_SECTION(PAGE_SIZE) |
| 99 | INIT_DATA_SECTION(16) | 99 | INIT_DATA_SECTION(16) |
| 100 | 100 | ||
| 101 | . = ALIGN(4); | ||
| 102 | .mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) { | ||
| 103 | __mips_machines_start = .; | ||
| 104 | *(.mips.machines.init) | ||
| 105 | __mips_machines_end = .; | ||
| 106 | } | ||
| 107 | |||
| 101 | /* .exit.text is discarded at runtime, not link time, to deal with | 108 | /* .exit.text is discarded at runtime, not link time, to deal with |
| 102 | * references from .rodata | 109 | * references from .rodata |
| 103 | */ | 110 | */ |
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 93816f3bca67..083d3412d0bc 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
| @@ -26,8 +26,10 @@ | |||
| 26 | #include <linux/smp.h> | 26 | #include <linux/smp.h> |
| 27 | #include <linux/string.h> | 27 | #include <linux/string.h> |
| 28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
| 29 | #include <linux/cache.h> | ||
| 29 | 30 | ||
| 30 | #include <asm/mmu_context.h> | 31 | #include <asm/cacheflush.h> |
| 32 | #include <asm/pgtable.h> | ||
| 31 | #include <asm/war.h> | 33 | #include <asm/war.h> |
| 32 | #include <asm/uasm.h> | 34 | #include <asm/uasm.h> |
| 33 | 35 | ||
| @@ -63,6 +65,52 @@ static inline int __maybe_unused r10000_llsc_war(void) | |||
| 63 | return R10000_LLSC_WAR; | 65 | return R10000_LLSC_WAR; |
| 64 | } | 66 | } |
| 65 | 67 | ||
| 68 | static int use_bbit_insns(void) | ||
| 69 | { | ||
| 70 | switch (current_cpu_type()) { | ||
| 71 | case CPU_CAVIUM_OCTEON: | ||
| 72 | case CPU_CAVIUM_OCTEON_PLUS: | ||
| 73 | case CPU_CAVIUM_OCTEON2: | ||
| 74 | return 1; | ||
| 75 | default: | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | static int use_lwx_insns(void) | ||
| 81 | { | ||
| 82 | switch (current_cpu_type()) { | ||
| 83 | case CPU_CAVIUM_OCTEON2: | ||
| 84 | return 1; | ||
| 85 | default: | ||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | #if defined(CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE) && \ | ||
| 90 | CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 | ||
| 91 | static bool scratchpad_available(void) | ||
| 92 | { | ||
| 93 | return true; | ||
| 94 | } | ||
| 95 | static int scratchpad_offset(int i) | ||
| 96 | { | ||
| 97 | /* | ||
| 98 | * CVMSEG starts at address -32768 and extends for | ||
| 99 | * CAVIUM_OCTEON_CVMSEG_SIZE 128 byte cache lines. | ||
| 100 | */ | ||
| 101 | i += 1; /* Kernel use starts at the top and works down. */ | ||
| 102 | return CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128 - (8 * i) - 32768; | ||
| 103 | } | ||
| 104 | #else | ||
| 105 | static bool scratchpad_available(void) | ||
| 106 | { | ||
| 107 | return false; | ||
| 108 | } | ||
| 109 | static int scratchpad_offset(int i) | ||
| 110 | { | ||
| 111 | BUG(); | ||
| 112 | } | ||
| 113 | #endif | ||
| 66 | /* | 114 | /* |
| 67 | * Found by experiment: At least some revisions of the 4kc throw under | 115 | * Found by experiment: At least some revisions of the 4kc throw under |
| 68 | * some circumstances a machine check exception, triggered by invalid | 116 | * some circumstances a machine check exception, triggered by invalid |
| @@ -173,11 +221,41 @@ static struct uasm_reloc relocs[128] __cpuinitdata; | |||
| 173 | static int check_for_high_segbits __cpuinitdata; | 221 | static int check_for_high_segbits __cpuinitdata; |
| 174 | #endif | 222 | #endif |
| 175 | 223 | ||
| 224 | static int check_for_high_segbits __cpuinitdata; | ||
| 225 | |||
| 226 | static unsigned int kscratch_used_mask __cpuinitdata; | ||
| 227 | |||
| 228 | static int __cpuinit allocate_kscratch(void) | ||
| 229 | { | ||
| 230 | int r; | ||
| 231 | unsigned int a = cpu_data[0].kscratch_mask & ~kscratch_used_mask; | ||
| 232 | |||
| 233 | r = ffs(a); | ||
| 234 | |||
| 235 | if (r == 0) | ||
| 236 | return -1; | ||
| 237 | |||
| 238 | r--; /* make it zero based */ | ||
| 239 | |||
| 240 | kscratch_used_mask |= (1 << r); | ||
| 241 | |||
| 242 | return r; | ||
| 243 | } | ||
| 244 | |||
| 245 | static int scratch_reg __cpuinitdata; | ||
| 246 | static int pgd_reg __cpuinitdata; | ||
| 247 | enum vmalloc64_mode {not_refill, refill_scratch, refill_noscratch}; | ||
| 248 | |||
| 176 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT | 249 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT |
| 250 | |||
| 177 | /* | 251 | /* |
| 178 | * CONFIG_MIPS_PGD_C0_CONTEXT implies 64 bit and lack of pgd_current, | 252 | * CONFIG_MIPS_PGD_C0_CONTEXT implies 64 bit and lack of pgd_current, |
| 179 | * we cannot do r3000 under these circumstances. | 253 | * we cannot do r3000 under these circumstances. |
| 254 | * | ||
| 255 | * Declare pgd_current here instead of including mmu_context.h to avoid type | ||
| 256 | * conflicts for tlbmiss_handler_setup_pgd | ||
| 180 | */ | 257 | */ |
| 258 | extern unsigned long pgd_current[]; | ||
| 181 | 259 | ||
| 182 | /* | 260 | /* |
| 183 | * The R3000 TLB handler is simple. | 261 | * The R3000 TLB handler is simple. |
| @@ -440,21 +518,43 @@ static __cpuinit __maybe_unused void build_convert_pte_to_entrylo(u32 **p, | |||
| 440 | static __cpuinit void build_restore_pagemask(u32 **p, | 518 | static __cpuinit void build_restore_pagemask(u32 **p, |
| 441 | struct uasm_reloc **r, | 519 | struct uasm_reloc **r, |
| 442 | unsigned int tmp, | 520 | unsigned int tmp, |
| 443 | enum label_id lid) | 521 | enum label_id lid, |
| 522 | int restore_scratch) | ||
| 444 | { | 523 | { |
| 445 | /* Reset default page size */ | 524 | if (restore_scratch) { |
| 446 | if (PM_DEFAULT_MASK >> 16) { | 525 | /* Reset default page size */ |
| 447 | uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16); | 526 | if (PM_DEFAULT_MASK >> 16) { |
| 448 | uasm_i_ori(p, tmp, tmp, PM_DEFAULT_MASK & 0xffff); | 527 | uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16); |
| 449 | uasm_il_b(p, r, lid); | 528 | uasm_i_ori(p, tmp, tmp, PM_DEFAULT_MASK & 0xffff); |
| 450 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); | 529 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); |
| 451 | } else if (PM_DEFAULT_MASK) { | 530 | uasm_il_b(p, r, lid); |
| 452 | uasm_i_ori(p, tmp, 0, PM_DEFAULT_MASK); | 531 | } else if (PM_DEFAULT_MASK) { |
| 453 | uasm_il_b(p, r, lid); | 532 | uasm_i_ori(p, tmp, 0, PM_DEFAULT_MASK); |
| 454 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); | 533 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); |
| 534 | uasm_il_b(p, r, lid); | ||
| 535 | } else { | ||
| 536 | uasm_i_mtc0(p, 0, C0_PAGEMASK); | ||
| 537 | uasm_il_b(p, r, lid); | ||
| 538 | } | ||
| 539 | if (scratch_reg > 0) | ||
| 540 | UASM_i_MFC0(p, 1, 31, scratch_reg); | ||
| 541 | else | ||
| 542 | UASM_i_LW(p, 1, scratchpad_offset(0), 0); | ||
| 455 | } else { | 543 | } else { |
| 456 | uasm_il_b(p, r, lid); | 544 | /* Reset default page size */ |
| 457 | uasm_i_mtc0(p, 0, C0_PAGEMASK); | 545 | if (PM_DEFAULT_MASK >> 16) { |
| 546 | uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16); | ||
| 547 | uasm_i_ori(p, tmp, tmp, PM_DEFAULT_MASK & 0xffff); | ||
| 548 | uasm_il_b(p, r, lid); | ||
| 549 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); | ||
| 550 | } else if (PM_DEFAULT_MASK) { | ||
| 551 | uasm_i_ori(p, tmp, 0, PM_DEFAULT_MASK); | ||
| 552 | uasm_il_b(p, r, lid); | ||
| 553 | uasm_i_mtc0(p, tmp, C0_PAGEMASK); | ||
| 554 | } else { | ||
| 555 | uasm_il_b(p, r, lid); | ||
| 556 | uasm_i_mtc0(p, 0, C0_PAGEMASK); | ||
| 557 | } | ||
| 458 | } | 558 | } |
| 459 | } | 559 | } |
| 460 | 560 | ||
| @@ -462,7 +562,8 @@ static __cpuinit void build_huge_tlb_write_entry(u32 **p, | |||
| 462 | struct uasm_label **l, | 562 | struct uasm_label **l, |
| 463 | struct uasm_reloc **r, | 563 | struct uasm_reloc **r, |
| 464 | unsigned int tmp, | 564 | unsigned int tmp, |
| 465 | enum tlb_write_entry wmode) | 565 | enum tlb_write_entry wmode, |
| 566 | int restore_scratch) | ||
| 466 | { | 567 | { |
| 467 | /* Set huge page tlb entry size */ | 568 | /* Set huge page tlb entry size */ |
| 468 | uasm_i_lui(p, tmp, PM_HUGE_MASK >> 16); | 569 | uasm_i_lui(p, tmp, PM_HUGE_MASK >> 16); |
| @@ -471,7 +572,7 @@ static __cpuinit void build_huge_tlb_write_entry(u32 **p, | |||
| 471 | 572 | ||
| 472 | build_tlb_write_entry(p, l, r, wmode); | 573 | build_tlb_write_entry(p, l, r, wmode); |
| 473 | 574 | ||
| 474 | build_restore_pagemask(p, r, tmp, label_leave); | 575 | build_restore_pagemask(p, r, tmp, label_leave, restore_scratch); |
| 475 | } | 576 | } |
| 476 | 577 | ||
| 477 | /* | 578 | /* |
| @@ -482,8 +583,12 @@ build_is_huge_pte(u32 **p, struct uasm_reloc **r, unsigned int tmp, | |||
| 482 | unsigned int pmd, int lid) | 583 | unsigned int pmd, int lid) |
| 483 | { | 584 | { |
| 484 | UASM_i_LW(p, tmp, 0, pmd); | 585 | UASM_i_LW(p, tmp, 0, pmd); |
| 485 | uasm_i_andi(p, tmp, tmp, _PAGE_HUGE); | 586 | if (use_bbit_insns()) { |
| 486 | uasm_il_bnez(p, r, tmp, lid); | 587 | uasm_il_bbit1(p, r, tmp, ilog2(_PAGE_HUGE), lid); |
| 588 | } else { | ||
| 589 | uasm_i_andi(p, tmp, tmp, _PAGE_HUGE); | ||
| 590 | uasm_il_bnez(p, r, tmp, lid); | ||
| 591 | } | ||
| 487 | } | 592 | } |
| 488 | 593 | ||
| 489 | static __cpuinit void build_huge_update_entries(u32 **p, | 594 | static __cpuinit void build_huge_update_entries(u32 **p, |
| @@ -532,7 +637,7 @@ static __cpuinit void build_huge_handler_tail(u32 **p, | |||
| 532 | UASM_i_SW(p, pte, 0, ptr); | 637 | UASM_i_SW(p, pte, 0, ptr); |
| 533 | #endif | 638 | #endif |
| 534 | build_huge_update_entries(p, pte, ptr); | 639 | build_huge_update_entries(p, pte, ptr); |
| 535 | build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed); | 640 | build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed, 0); |
| 536 | } | 641 | } |
| 537 | #endif /* CONFIG_HUGETLB_PAGE */ | 642 | #endif /* CONFIG_HUGETLB_PAGE */ |
| 538 | 643 | ||
| @@ -573,13 +678,22 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
| 573 | /* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */ | 678 | /* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */ |
| 574 | 679 | ||
| 575 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | 680 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT |
| 576 | /* | 681 | if (pgd_reg != -1) { |
| 577 | * &pgd << 11 stored in CONTEXT [23..63]. | 682 | /* pgd is in pgd_reg */ |
| 578 | */ | 683 | UASM_i_MFC0(p, ptr, 31, pgd_reg); |
| 579 | UASM_i_MFC0(p, ptr, C0_CONTEXT); | 684 | } else { |
| 580 | uasm_i_dins(p, ptr, 0, 0, 23); /* Clear lower 23 bits of context. */ | 685 | /* |
| 581 | uasm_i_ori(p, ptr, ptr, 0x540); /* 1 0 1 0 1 << 6 xkphys cached */ | 686 | * &pgd << 11 stored in CONTEXT [23..63]. |
| 582 | uasm_i_drotr(p, ptr, ptr, 11); | 687 | */ |
| 688 | UASM_i_MFC0(p, ptr, C0_CONTEXT); | ||
| 689 | |||
| 690 | /* Clear lower 23 bits of context. */ | ||
| 691 | uasm_i_dins(p, ptr, 0, 0, 23); | ||
| 692 | |||
| 693 | /* 1 0 1 0 1 << 6 xkphys cached */ | ||
| 694 | uasm_i_ori(p, ptr, ptr, 0x540); | ||
| 695 | uasm_i_drotr(p, ptr, ptr, 11); | ||
| 696 | } | ||
| 583 | #elif defined(CONFIG_SMP) | 697 | #elif defined(CONFIG_SMP) |
| 584 | # ifdef CONFIG_MIPS_MT_SMTC | 698 | # ifdef CONFIG_MIPS_MT_SMTC |
| 585 | /* | 699 | /* |
| @@ -620,7 +734,6 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
| 620 | #endif | 734 | #endif |
| 621 | } | 735 | } |
| 622 | 736 | ||
| 623 | enum vmalloc64_mode {not_refill, refill}; | ||
| 624 | /* | 737 | /* |
| 625 | * BVADDR is the faulting address, PTR is scratch. | 738 | * BVADDR is the faulting address, PTR is scratch. |
| 626 | * PTR will hold the pgd for vmalloc. | 739 | * PTR will hold the pgd for vmalloc. |
| @@ -638,7 +751,7 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
| 638 | 751 | ||
| 639 | uasm_l_vmalloc(l, *p); | 752 | uasm_l_vmalloc(l, *p); |
| 640 | 753 | ||
| 641 | if (mode == refill && check_for_high_segbits) { | 754 | if (mode != not_refill && check_for_high_segbits) { |
| 642 | if (single_insn_swpd) { | 755 | if (single_insn_swpd) { |
| 643 | uasm_il_bltz(p, r, bvaddr, label_vmalloc_done); | 756 | uasm_il_bltz(p, r, bvaddr, label_vmalloc_done); |
| 644 | uasm_i_lui(p, ptr, uasm_rel_hi(swpd)); | 757 | uasm_i_lui(p, ptr, uasm_rel_hi(swpd)); |
| @@ -661,7 +774,7 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
| 661 | uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(swpd)); | 774 | uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(swpd)); |
| 662 | } | 775 | } |
| 663 | } | 776 | } |
| 664 | if (mode == refill && check_for_high_segbits) { | 777 | if (mode != not_refill && check_for_high_segbits) { |
| 665 | uasm_l_large_segbits_fault(l, *p); | 778 | uasm_l_large_segbits_fault(l, *p); |
| 666 | /* | 779 | /* |
| 667 | * We get here if we are an xsseg address, or if we are | 780 | * We get here if we are an xsseg address, or if we are |
| @@ -677,7 +790,15 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
| 677 | */ | 790 | */ |
| 678 | UASM_i_LA(p, ptr, (unsigned long)tlb_do_page_fault_0); | 791 | UASM_i_LA(p, ptr, (unsigned long)tlb_do_page_fault_0); |
| 679 | uasm_i_jr(p, ptr); | 792 | uasm_i_jr(p, ptr); |
| 680 | uasm_i_nop(p); | 793 | |
| 794 | if (mode == refill_scratch) { | ||
| 795 | if (scratch_reg > 0) | ||
| 796 | UASM_i_MFC0(p, 1, 31, scratch_reg); | ||
| 797 | else | ||
| 798 | UASM_i_LW(p, 1, scratchpad_offset(0), 0); | ||
| 799 | } else { | ||
| 800 | uasm_i_nop(p); | ||
| 801 | } | ||
| 681 | } | 802 | } |
| 682 | } | 803 | } |
| 683 | 804 | ||
| @@ -834,6 +955,185 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp, | |||
| 834 | #endif | 955 | #endif |
| 835 | } | 956 | } |
| 836 | 957 | ||
| 958 | struct mips_huge_tlb_info { | ||
| 959 | int huge_pte; | ||
| 960 | int restore_scratch; | ||
| 961 | }; | ||
| 962 | |||
| 963 | static struct mips_huge_tlb_info __cpuinit | ||
| 964 | build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l, | ||
| 965 | struct uasm_reloc **r, unsigned int tmp, | ||
| 966 | unsigned int ptr, int c0_scratch) | ||
| 967 | { | ||
| 968 | struct mips_huge_tlb_info rv; | ||
| 969 | unsigned int even, odd; | ||
| 970 | int vmalloc_branch_delay_filled = 0; | ||
| 971 | const int scratch = 1; /* Our extra working register */ | ||
| 972 | |||
| 973 | rv.huge_pte = scratch; | ||
| 974 | rv.restore_scratch = 0; | ||
| 975 | |||
| 976 | if (check_for_high_segbits) { | ||
| 977 | UASM_i_MFC0(p, tmp, C0_BADVADDR); | ||
| 978 | |||
| 979 | if (pgd_reg != -1) | ||
| 980 | UASM_i_MFC0(p, ptr, 31, pgd_reg); | ||
| 981 | else | ||
| 982 | UASM_i_MFC0(p, ptr, C0_CONTEXT); | ||
| 983 | |||
| 984 | if (c0_scratch >= 0) | ||
| 985 | UASM_i_MTC0(p, scratch, 31, c0_scratch); | ||
| 986 | else | ||
| 987 | UASM_i_SW(p, scratch, scratchpad_offset(0), 0); | ||
| 988 | |||
| 989 | uasm_i_dsrl_safe(p, scratch, tmp, | ||
| 990 | PGDIR_SHIFT + PGD_ORDER + PAGE_SHIFT - 3); | ||
| 991 | uasm_il_bnez(p, r, scratch, label_vmalloc); | ||
| 992 | |||
| 993 | if (pgd_reg == -1) { | ||
| 994 | vmalloc_branch_delay_filled = 1; | ||
| 995 | /* Clear lower 23 bits of context. */ | ||
| 996 | uasm_i_dins(p, ptr, 0, 0, 23); | ||
| 997 | } | ||
| 998 | } else { | ||
| 999 | if (pgd_reg != -1) | ||
| 1000 | UASM_i_MFC0(p, ptr, 31, pgd_reg); | ||
| 1001 | else | ||
| 1002 | UASM_i_MFC0(p, ptr, C0_CONTEXT); | ||
| 1003 | |||
| 1004 | UASM_i_MFC0(p, tmp, C0_BADVADDR); | ||
| 1005 | |||
| 1006 | if (c0_scratch >= 0) | ||
| 1007 | UASM_i_MTC0(p, scratch, 31, c0_scratch); | ||
| 1008 | else | ||
| 1009 | UASM_i_SW(p, scratch, scratchpad_offset(0), 0); | ||
| 1010 | |||
| 1011 | if (pgd_reg == -1) | ||
| 1012 | /* Clear lower 23 bits of context. */ | ||
| 1013 | uasm_i_dins(p, ptr, 0, 0, 23); | ||
| 1014 | |||
| 1015 | uasm_il_bltz(p, r, tmp, label_vmalloc); | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | if (pgd_reg == -1) { | ||
| 1019 | vmalloc_branch_delay_filled = 1; | ||
| 1020 | /* 1 0 1 0 1 << 6 xkphys cached */ | ||
| 1021 | uasm_i_ori(p, ptr, ptr, 0x540); | ||
| 1022 | uasm_i_drotr(p, ptr, ptr, 11); | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | #ifdef __PAGETABLE_PMD_FOLDED | ||
| 1026 | #define LOC_PTEP scratch | ||
| 1027 | #else | ||
| 1028 | #define LOC_PTEP ptr | ||
| 1029 | #endif | ||
| 1030 | |||
| 1031 | if (!vmalloc_branch_delay_filled) | ||
| 1032 | /* get pgd offset in bytes */ | ||
| 1033 | uasm_i_dsrl_safe(p, scratch, tmp, PGDIR_SHIFT - 3); | ||
| 1034 | |||
| 1035 | uasm_l_vmalloc_done(l, *p); | ||
| 1036 | |||
| 1037 | /* | ||
| 1038 | * tmp ptr | ||
| 1039 | * fall-through case = badvaddr *pgd_current | ||
| 1040 | * vmalloc case = badvaddr swapper_pg_dir | ||
| 1041 | */ | ||
| 1042 | |||
| 1043 | if (vmalloc_branch_delay_filled) | ||
| 1044 | /* get pgd offset in bytes */ | ||
| 1045 | uasm_i_dsrl_safe(p, scratch, tmp, PGDIR_SHIFT - 3); | ||
| 1046 | |||
| 1047 | #ifdef __PAGETABLE_PMD_FOLDED | ||
| 1048 | GET_CONTEXT(p, tmp); /* get context reg */ | ||
| 1049 | #endif | ||
| 1050 | uasm_i_andi(p, scratch, scratch, (PTRS_PER_PGD - 1) << 3); | ||
| 1051 | |||
| 1052 | if (use_lwx_insns()) { | ||
| 1053 | UASM_i_LWX(p, LOC_PTEP, scratch, ptr); | ||
| 1054 | } else { | ||
| 1055 | uasm_i_daddu(p, ptr, ptr, scratch); /* add in pgd offset */ | ||
| 1056 | uasm_i_ld(p, LOC_PTEP, 0, ptr); /* get pmd pointer */ | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | #ifndef __PAGETABLE_PMD_FOLDED | ||
| 1060 | /* get pmd offset in bytes */ | ||
| 1061 | uasm_i_dsrl_safe(p, scratch, tmp, PMD_SHIFT - 3); | ||
| 1062 | uasm_i_andi(p, scratch, scratch, (PTRS_PER_PMD - 1) << 3); | ||
| 1063 | GET_CONTEXT(p, tmp); /* get context reg */ | ||
| 1064 | |||
| 1065 | if (use_lwx_insns()) { | ||
| 1066 | UASM_i_LWX(p, scratch, scratch, ptr); | ||
| 1067 | } else { | ||
| 1068 | uasm_i_daddu(p, ptr, ptr, scratch); /* add in pmd offset */ | ||
| 1069 | UASM_i_LW(p, scratch, 0, ptr); | ||
| 1070 | } | ||
| 1071 | #endif | ||
| 1072 | /* Adjust the context during the load latency. */ | ||
| 1073 | build_adjust_context(p, tmp); | ||
| 1074 | |||
| 1075 | #ifdef CONFIG_HUGETLB_PAGE | ||
| 1076 | uasm_il_bbit1(p, r, scratch, ilog2(_PAGE_HUGE), label_tlb_huge_update); | ||
| 1077 | /* | ||
| 1078 | * The in the LWX case we don't want to do the load in the | ||
| 1079 | * delay slot. It cannot issue in the same cycle and may be | ||
| 1080 | * speculative and unneeded. | ||
| 1081 | */ | ||
| 1082 | if (use_lwx_insns()) | ||
| 1083 | uasm_i_nop(p); | ||
| 1084 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
| 1085 | |||
| 1086 | |||
| 1087 | /* build_update_entries */ | ||
| 1088 | if (use_lwx_insns()) { | ||
| 1089 | even = ptr; | ||
| 1090 | odd = tmp; | ||
| 1091 | UASM_i_LWX(p, even, scratch, tmp); | ||
| 1092 | UASM_i_ADDIU(p, tmp, tmp, sizeof(pte_t)); | ||
| 1093 | UASM_i_LWX(p, odd, scratch, tmp); | ||
| 1094 | } else { | ||
| 1095 | UASM_i_ADDU(p, ptr, scratch, tmp); /* add in offset */ | ||
| 1096 | even = tmp; | ||
| 1097 | odd = ptr; | ||
| 1098 | UASM_i_LW(p, even, 0, ptr); /* get even pte */ | ||
| 1099 | UASM_i_LW(p, odd, sizeof(pte_t), ptr); /* get odd pte */ | ||
| 1100 | } | ||
| 1101 | if (kernel_uses_smartmips_rixi) { | ||
| 1102 | uasm_i_dsrl_safe(p, even, even, ilog2(_PAGE_NO_EXEC)); | ||
| 1103 | uasm_i_dsrl_safe(p, odd, odd, ilog2(_PAGE_NO_EXEC)); | ||
| 1104 | uasm_i_drotr(p, even, even, | ||
| 1105 | ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC)); | ||
| 1106 | UASM_i_MTC0(p, even, C0_ENTRYLO0); /* load it */ | ||
| 1107 | uasm_i_drotr(p, odd, odd, | ||
| 1108 | ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC)); | ||
| 1109 | } else { | ||
| 1110 | uasm_i_dsrl_safe(p, even, even, ilog2(_PAGE_GLOBAL)); | ||
| 1111 | UASM_i_MTC0(p, even, C0_ENTRYLO0); /* load it */ | ||
| 1112 | uasm_i_dsrl_safe(p, odd, odd, ilog2(_PAGE_GLOBAL)); | ||
| 1113 | } | ||
| 1114 | UASM_i_MTC0(p, odd, C0_ENTRYLO1); /* load it */ | ||
| 1115 | |||
| 1116 | if (c0_scratch >= 0) { | ||
| 1117 | UASM_i_MFC0(p, scratch, 31, c0_scratch); | ||
| 1118 | build_tlb_write_entry(p, l, r, tlb_random); | ||
| 1119 | uasm_l_leave(l, *p); | ||
| 1120 | rv.restore_scratch = 1; | ||
| 1121 | } else if (PAGE_SHIFT == 14 || PAGE_SHIFT == 13) { | ||
| 1122 | build_tlb_write_entry(p, l, r, tlb_random); | ||
| 1123 | uasm_l_leave(l, *p); | ||
| 1124 | UASM_i_LW(p, scratch, scratchpad_offset(0), 0); | ||
| 1125 | } else { | ||
| 1126 | UASM_i_LW(p, scratch, scratchpad_offset(0), 0); | ||
| 1127 | build_tlb_write_entry(p, l, r, tlb_random); | ||
| 1128 | uasm_l_leave(l, *p); | ||
| 1129 | rv.restore_scratch = 1; | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | uasm_i_eret(p); /* return from trap */ | ||
| 1133 | |||
| 1134 | return rv; | ||
| 1135 | } | ||
| 1136 | |||
| 837 | /* | 1137 | /* |
| 838 | * For a 64-bit kernel, we are using the 64-bit XTLB refill exception | 1138 | * For a 64-bit kernel, we are using the 64-bit XTLB refill exception |
| 839 | * because EXL == 0. If we wrap, we can also use the 32 instruction | 1139 | * because EXL == 0. If we wrap, we can also use the 32 instruction |
| @@ -849,54 +1149,67 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) | |||
| 849 | struct uasm_reloc *r = relocs; | 1149 | struct uasm_reloc *r = relocs; |
| 850 | u32 *f; | 1150 | u32 *f; |
| 851 | unsigned int final_len; | 1151 | unsigned int final_len; |
| 1152 | struct mips_huge_tlb_info htlb_info; | ||
| 1153 | enum vmalloc64_mode vmalloc_mode; | ||
| 852 | 1154 | ||
| 853 | memset(tlb_handler, 0, sizeof(tlb_handler)); | 1155 | memset(tlb_handler, 0, sizeof(tlb_handler)); |
| 854 | memset(labels, 0, sizeof(labels)); | 1156 | memset(labels, 0, sizeof(labels)); |
| 855 | memset(relocs, 0, sizeof(relocs)); | 1157 | memset(relocs, 0, sizeof(relocs)); |
| 856 | memset(final_handler, 0, sizeof(final_handler)); | 1158 | memset(final_handler, 0, sizeof(final_handler)); |
| 857 | 1159 | ||
| 858 | /* | 1160 | if (scratch_reg == 0) |
| 859 | * create the plain linear handler | 1161 | scratch_reg = allocate_kscratch(); |
| 860 | */ | ||
| 861 | if (bcm1250_m3_war()) { | ||
| 862 | unsigned int segbits = 44; | ||
| 863 | 1162 | ||
| 864 | uasm_i_dmfc0(&p, K0, C0_BADVADDR); | 1163 | if ((scratch_reg > 0 || scratchpad_available()) && use_bbit_insns()) { |
| 865 | uasm_i_dmfc0(&p, K1, C0_ENTRYHI); | 1164 | htlb_info = build_fast_tlb_refill_handler(&p, &l, &r, K0, K1, |
| 866 | uasm_i_xor(&p, K0, K0, K1); | 1165 | scratch_reg); |
| 867 | uasm_i_dsrl_safe(&p, K1, K0, 62); | 1166 | vmalloc_mode = refill_scratch; |
| 868 | uasm_i_dsrl_safe(&p, K0, K0, 12 + 1); | 1167 | } else { |
| 869 | uasm_i_dsll_safe(&p, K0, K0, 64 + 12 + 1 - segbits); | 1168 | htlb_info.huge_pte = K0; |
| 870 | uasm_i_or(&p, K0, K0, K1); | 1169 | htlb_info.restore_scratch = 0; |
| 871 | uasm_il_bnez(&p, &r, K0, label_leave); | 1170 | vmalloc_mode = refill_noscratch; |
| 872 | /* No need for uasm_i_nop */ | 1171 | /* |
| 873 | } | 1172 | * create the plain linear handler |
| 1173 | */ | ||
| 1174 | if (bcm1250_m3_war()) { | ||
| 1175 | unsigned int segbits = 44; | ||
| 1176 | |||
| 1177 | uasm_i_dmfc0(&p, K0, C0_BADVADDR); | ||
| 1178 | uasm_i_dmfc0(&p, K1, C0_ENTRYHI); | ||
| 1179 | uasm_i_xor(&p, K0, K0, K1); | ||
| 1180 | uasm_i_dsrl_safe(&p, K1, K0, 62); | ||
| 1181 | uasm_i_dsrl_safe(&p, K0, K0, 12 + 1); | ||
| 1182 | uasm_i_dsll_safe(&p, K0, K0, 64 + 12 + 1 - segbits); | ||
| 1183 | uasm_i_or(&p, K0, K0, K1); | ||
| 1184 | uasm_il_bnez(&p, &r, K0, label_leave); | ||
| 1185 | /* No need for uasm_i_nop */ | ||
| 1186 | } | ||
| 874 | 1187 | ||
| 875 | #ifdef CONFIG_64BIT | 1188 | #ifdef CONFIG_64BIT |
| 876 | build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */ | 1189 | build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */ |
| 877 | #else | 1190 | #else |
| 878 | build_get_pgde32(&p, K0, K1); /* get pgd in K1 */ | 1191 | build_get_pgde32(&p, K0, K1); /* get pgd in K1 */ |
| 879 | #endif | 1192 | #endif |
| 880 | 1193 | ||
| 881 | #ifdef CONFIG_HUGETLB_PAGE | 1194 | #ifdef CONFIG_HUGETLB_PAGE |
| 882 | build_is_huge_pte(&p, &r, K0, K1, label_tlb_huge_update); | 1195 | build_is_huge_pte(&p, &r, K0, K1, label_tlb_huge_update); |
| 883 | #endif | 1196 | #endif |
| 884 | 1197 | ||
| 885 | build_get_ptep(&p, K0, K1); | 1198 | build_get_ptep(&p, K0, K1); |
| 886 | build_update_entries(&p, K0, K1); | 1199 | build_update_entries(&p, K0, K1); |
| 887 | build_tlb_write_entry(&p, &l, &r, tlb_random); | 1200 | build_tlb_write_entry(&p, &l, &r, tlb_random); |
| 888 | uasm_l_leave(&l, p); | 1201 | uasm_l_leave(&l, p); |
| 889 | uasm_i_eret(&p); /* return from trap */ | 1202 | uasm_i_eret(&p); /* return from trap */ |
| 890 | 1203 | } | |
| 891 | #ifdef CONFIG_HUGETLB_PAGE | 1204 | #ifdef CONFIG_HUGETLB_PAGE |
| 892 | uasm_l_tlb_huge_update(&l, p); | 1205 | uasm_l_tlb_huge_update(&l, p); |
| 893 | UASM_i_LW(&p, K0, 0, K1); | 1206 | build_huge_update_entries(&p, htlb_info.huge_pte, K1); |
| 894 | build_huge_update_entries(&p, K0, K1); | 1207 | build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random, |
| 895 | build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random); | 1208 | htlb_info.restore_scratch); |
| 896 | #endif | 1209 | #endif |
| 897 | 1210 | ||
| 898 | #ifdef CONFIG_64BIT | 1211 | #ifdef CONFIG_64BIT |
| 899 | build_get_pgd_vmalloc64(&p, &l, &r, K0, K1, refill); | 1212 | build_get_pgd_vmalloc64(&p, &l, &r, K0, K1, vmalloc_mode); |
| 900 | #endif | 1213 | #endif |
| 901 | 1214 | ||
| 902 | /* | 1215 | /* |
| @@ -1014,6 +1327,55 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) | |||
| 1014 | u32 handle_tlbl[FASTPATH_SIZE] __cacheline_aligned; | 1327 | u32 handle_tlbl[FASTPATH_SIZE] __cacheline_aligned; |
| 1015 | u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned; | 1328 | u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned; |
| 1016 | u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned; | 1329 | u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned; |
| 1330 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
| 1331 | u32 tlbmiss_handler_setup_pgd[16] __cacheline_aligned; | ||
| 1332 | |||
| 1333 | static void __cpuinit build_r4000_setup_pgd(void) | ||
| 1334 | { | ||
| 1335 | const int a0 = 4; | ||
| 1336 | const int a1 = 5; | ||
| 1337 | u32 *p = tlbmiss_handler_setup_pgd; | ||
| 1338 | struct uasm_label *l = labels; | ||
| 1339 | struct uasm_reloc *r = relocs; | ||
| 1340 | |||
| 1341 | memset(tlbmiss_handler_setup_pgd, 0, sizeof(tlbmiss_handler_setup_pgd)); | ||
| 1342 | memset(labels, 0, sizeof(labels)); | ||
| 1343 | memset(relocs, 0, sizeof(relocs)); | ||
| 1344 | |||
| 1345 | pgd_reg = allocate_kscratch(); | ||
| 1346 | |||
| 1347 | if (pgd_reg == -1) { | ||
| 1348 | /* PGD << 11 in c0_Context */ | ||
| 1349 | /* | ||
| 1350 | * If it is a ckseg0 address, convert to a physical | ||
| 1351 | * address. Shifting right by 29 and adding 4 will | ||
| 1352 | * result in zero for these addresses. | ||
| 1353 | * | ||
| 1354 | */ | ||
| 1355 | UASM_i_SRA(&p, a1, a0, 29); | ||
| 1356 | UASM_i_ADDIU(&p, a1, a1, 4); | ||
| 1357 | uasm_il_bnez(&p, &r, a1, label_tlbl_goaround1); | ||
| 1358 | uasm_i_nop(&p); | ||
| 1359 | uasm_i_dinsm(&p, a0, 0, 29, 64 - 29); | ||
| 1360 | uasm_l_tlbl_goaround1(&l, p); | ||
| 1361 | UASM_i_SLL(&p, a0, a0, 11); | ||
| 1362 | uasm_i_jr(&p, 31); | ||
| 1363 | UASM_i_MTC0(&p, a0, C0_CONTEXT); | ||
| 1364 | } else { | ||
| 1365 | /* PGD in c0_KScratch */ | ||
| 1366 | uasm_i_jr(&p, 31); | ||
| 1367 | UASM_i_MTC0(&p, a0, 31, pgd_reg); | ||
| 1368 | } | ||
| 1369 | if (p - tlbmiss_handler_setup_pgd > ARRAY_SIZE(tlbmiss_handler_setup_pgd)) | ||
| 1370 | panic("tlbmiss_handler_setup_pgd space exceeded"); | ||
| 1371 | uasm_resolve_relocs(relocs, labels); | ||
| 1372 | pr_debug("Wrote tlbmiss_handler_setup_pgd (%u instructions).\n", | ||
| 1373 | (unsigned int)(p - tlbmiss_handler_setup_pgd)); | ||
| 1374 | |||
| 1375 | dump_handler(tlbmiss_handler_setup_pgd, | ||
| 1376 | ARRAY_SIZE(tlbmiss_handler_setup_pgd)); | ||
| 1377 | } | ||
| 1378 | #endif | ||
| 1017 | 1379 | ||
| 1018 | static void __cpuinit | 1380 | static void __cpuinit |
| 1019 | iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) | 1381 | iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) |
| @@ -1100,14 +1462,20 @@ build_pte_present(u32 **p, struct uasm_reloc **r, | |||
| 1100 | unsigned int pte, unsigned int ptr, enum label_id lid) | 1462 | unsigned int pte, unsigned int ptr, enum label_id lid) |
| 1101 | { | 1463 | { |
| 1102 | if (kernel_uses_smartmips_rixi) { | 1464 | if (kernel_uses_smartmips_rixi) { |
| 1103 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT); | 1465 | if (use_bbit_insns()) { |
| 1104 | uasm_il_beqz(p, r, pte, lid); | 1466 | uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid); |
| 1467 | uasm_i_nop(p); | ||
| 1468 | } else { | ||
| 1469 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT); | ||
| 1470 | uasm_il_beqz(p, r, pte, lid); | ||
| 1471 | iPTE_LW(p, pte, ptr); | ||
| 1472 | } | ||
| 1105 | } else { | 1473 | } else { |
| 1106 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); | 1474 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); |
| 1107 | uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); | 1475 | uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ); |
| 1108 | uasm_il_bnez(p, r, pte, lid); | 1476 | uasm_il_bnez(p, r, pte, lid); |
| 1477 | iPTE_LW(p, pte, ptr); | ||
| 1109 | } | 1478 | } |
| 1110 | iPTE_LW(p, pte, ptr); | ||
| 1111 | } | 1479 | } |
| 1112 | 1480 | ||
| 1113 | /* Make PTE valid, store result in PTR. */ | 1481 | /* Make PTE valid, store result in PTR. */ |
| @@ -1128,10 +1496,17 @@ static void __cpuinit | |||
| 1128 | build_pte_writable(u32 **p, struct uasm_reloc **r, | 1496 | build_pte_writable(u32 **p, struct uasm_reloc **r, |
| 1129 | unsigned int pte, unsigned int ptr, enum label_id lid) | 1497 | unsigned int pte, unsigned int ptr, enum label_id lid) |
| 1130 | { | 1498 | { |
| 1131 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); | 1499 | if (use_bbit_insns()) { |
| 1132 | uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); | 1500 | uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid); |
| 1133 | uasm_il_bnez(p, r, pte, lid); | 1501 | uasm_i_nop(p); |
| 1134 | iPTE_LW(p, pte, ptr); | 1502 | uasm_il_bbit0(p, r, pte, ilog2(_PAGE_WRITE), lid); |
| 1503 | uasm_i_nop(p); | ||
| 1504 | } else { | ||
| 1505 | uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); | ||
| 1506 | uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE); | ||
| 1507 | uasm_il_bnez(p, r, pte, lid); | ||
| 1508 | iPTE_LW(p, pte, ptr); | ||
| 1509 | } | ||
| 1135 | } | 1510 | } |
| 1136 | 1511 | ||
| 1137 | /* Make PTE writable, update software status bits as well, then store | 1512 | /* Make PTE writable, update software status bits as well, then store |
| @@ -1155,12 +1530,19 @@ static void __cpuinit | |||
| 1155 | build_pte_modifiable(u32 **p, struct uasm_reloc **r, | 1530 | build_pte_modifiable(u32 **p, struct uasm_reloc **r, |
| 1156 | unsigned int pte, unsigned int ptr, enum label_id lid) | 1531 | unsigned int pte, unsigned int ptr, enum label_id lid) |
| 1157 | { | 1532 | { |
| 1158 | uasm_i_andi(p, pte, pte, _PAGE_WRITE); | 1533 | if (use_bbit_insns()) { |
| 1159 | uasm_il_beqz(p, r, pte, lid); | 1534 | uasm_il_bbit0(p, r, pte, ilog2(_PAGE_WRITE), lid); |
| 1160 | iPTE_LW(p, pte, ptr); | 1535 | uasm_i_nop(p); |
| 1536 | } else { | ||
| 1537 | uasm_i_andi(p, pte, pte, _PAGE_WRITE); | ||
| 1538 | uasm_il_beqz(p, r, pte, lid); | ||
| 1539 | iPTE_LW(p, pte, ptr); | ||
| 1540 | } | ||
| 1161 | } | 1541 | } |
| 1162 | 1542 | ||
| 1163 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT | 1543 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT |
| 1544 | |||
| 1545 | |||
| 1164 | /* | 1546 | /* |
| 1165 | * R3000 style TLB load/store/modify handlers. | 1547 | * R3000 style TLB load/store/modify handlers. |
| 1166 | */ | 1548 | */ |
| @@ -1402,14 +1784,23 @@ static void __cpuinit build_r4000_tlb_load_handler(void) | |||
| 1402 | * If the page is not _PAGE_VALID, RI or XI could not | 1784 | * If the page is not _PAGE_VALID, RI or XI could not |
| 1403 | * have triggered it. Skip the expensive test.. | 1785 | * have triggered it. Skip the expensive test.. |
| 1404 | */ | 1786 | */ |
| 1405 | uasm_i_andi(&p, K0, K0, _PAGE_VALID); | 1787 | if (use_bbit_insns()) { |
| 1406 | uasm_il_beqz(&p, &r, K0, label_tlbl_goaround1); | 1788 | uasm_il_bbit0(&p, &r, K0, ilog2(_PAGE_VALID), |
| 1789 | label_tlbl_goaround1); | ||
| 1790 | } else { | ||
| 1791 | uasm_i_andi(&p, K0, K0, _PAGE_VALID); | ||
| 1792 | uasm_il_beqz(&p, &r, K0, label_tlbl_goaround1); | ||
| 1793 | } | ||
| 1407 | uasm_i_nop(&p); | 1794 | uasm_i_nop(&p); |
| 1408 | 1795 | ||
| 1409 | uasm_i_tlbr(&p); | 1796 | uasm_i_tlbr(&p); |
| 1410 | /* Examine entrylo 0 or 1 based on ptr. */ | 1797 | /* Examine entrylo 0 or 1 based on ptr. */ |
| 1411 | uasm_i_andi(&p, K0, K1, sizeof(pte_t)); | 1798 | if (use_bbit_insns()) { |
| 1412 | uasm_i_beqz(&p, K0, 8); | 1799 | uasm_i_bbit0(&p, K1, ilog2(sizeof(pte_t)), 8); |
| 1800 | } else { | ||
| 1801 | uasm_i_andi(&p, K0, K1, sizeof(pte_t)); | ||
| 1802 | uasm_i_beqz(&p, K0, 8); | ||
| 1803 | } | ||
| 1413 | 1804 | ||
| 1414 | UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/ | 1805 | UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/ |
| 1415 | UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */ | 1806 | UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */ |
| @@ -1417,12 +1808,18 @@ static void __cpuinit build_r4000_tlb_load_handler(void) | |||
| 1417 | * If the entryLo (now in K0) is valid (bit 1), RI or | 1808 | * If the entryLo (now in K0) is valid (bit 1), RI or |
| 1418 | * XI must have triggered it. | 1809 | * XI must have triggered it. |
| 1419 | */ | 1810 | */ |
| 1420 | uasm_i_andi(&p, K0, K0, 2); | 1811 | if (use_bbit_insns()) { |
| 1421 | uasm_il_bnez(&p, &r, K0, label_nopage_tlbl); | 1812 | uasm_il_bbit1(&p, &r, K0, 1, label_nopage_tlbl); |
| 1422 | 1813 | /* Reload the PTE value */ | |
| 1423 | uasm_l_tlbl_goaround1(&l, p); | 1814 | iPTE_LW(&p, K0, K1); |
| 1424 | /* Reload the PTE value */ | 1815 | uasm_l_tlbl_goaround1(&l, p); |
| 1425 | iPTE_LW(&p, K0, K1); | 1816 | } else { |
| 1817 | uasm_i_andi(&p, K0, K0, 2); | ||
| 1818 | uasm_il_bnez(&p, &r, K0, label_nopage_tlbl); | ||
| 1819 | uasm_l_tlbl_goaround1(&l, p); | ||
| 1820 | /* Reload the PTE value */ | ||
| 1821 | iPTE_LW(&p, K0, K1); | ||
| 1822 | } | ||
| 1426 | } | 1823 | } |
| 1427 | build_make_valid(&p, &r, K0, K1); | 1824 | build_make_valid(&p, &r, K0, K1); |
| 1428 | build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1); | 1825 | build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1); |
| @@ -1442,23 +1839,35 @@ static void __cpuinit build_r4000_tlb_load_handler(void) | |||
| 1442 | * If the page is not _PAGE_VALID, RI or XI could not | 1839 | * If the page is not _PAGE_VALID, RI or XI could not |
| 1443 | * have triggered it. Skip the expensive test.. | 1840 | * have triggered it. Skip the expensive test.. |
| 1444 | */ | 1841 | */ |
| 1445 | uasm_i_andi(&p, K0, K0, _PAGE_VALID); | 1842 | if (use_bbit_insns()) { |
| 1446 | uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2); | 1843 | uasm_il_bbit0(&p, &r, K0, ilog2(_PAGE_VALID), |
| 1844 | label_tlbl_goaround2); | ||
| 1845 | } else { | ||
| 1846 | uasm_i_andi(&p, K0, K0, _PAGE_VALID); | ||
| 1847 | uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2); | ||
| 1848 | } | ||
| 1447 | uasm_i_nop(&p); | 1849 | uasm_i_nop(&p); |
| 1448 | 1850 | ||
| 1449 | uasm_i_tlbr(&p); | 1851 | uasm_i_tlbr(&p); |
| 1450 | /* Examine entrylo 0 or 1 based on ptr. */ | 1852 | /* Examine entrylo 0 or 1 based on ptr. */ |
| 1451 | uasm_i_andi(&p, K0, K1, sizeof(pte_t)); | 1853 | if (use_bbit_insns()) { |
| 1452 | uasm_i_beqz(&p, K0, 8); | 1854 | uasm_i_bbit0(&p, K1, ilog2(sizeof(pte_t)), 8); |
| 1453 | 1855 | } else { | |
| 1856 | uasm_i_andi(&p, K0, K1, sizeof(pte_t)); | ||
| 1857 | uasm_i_beqz(&p, K0, 8); | ||
| 1858 | } | ||
| 1454 | UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/ | 1859 | UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/ |
| 1455 | UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */ | 1860 | UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */ |
| 1456 | /* | 1861 | /* |
| 1457 | * If the entryLo (now in K0) is valid (bit 1), RI or | 1862 | * If the entryLo (now in K0) is valid (bit 1), RI or |
| 1458 | * XI must have triggered it. | 1863 | * XI must have triggered it. |
| 1459 | */ | 1864 | */ |
| 1460 | uasm_i_andi(&p, K0, K0, 2); | 1865 | if (use_bbit_insns()) { |
| 1461 | uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2); | 1866 | uasm_il_bbit0(&p, &r, K0, 1, label_tlbl_goaround2); |
| 1867 | } else { | ||
| 1868 | uasm_i_andi(&p, K0, K0, 2); | ||
| 1869 | uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2); | ||
| 1870 | } | ||
| 1462 | /* Reload the PTE value */ | 1871 | /* Reload the PTE value */ |
| 1463 | iPTE_LW(&p, K0, K1); | 1872 | iPTE_LW(&p, K0, K1); |
| 1464 | 1873 | ||
| @@ -1466,7 +1875,7 @@ static void __cpuinit build_r4000_tlb_load_handler(void) | |||
| 1466 | * We clobbered C0_PAGEMASK, restore it. On the other branch | 1875 | * We clobbered C0_PAGEMASK, restore it. On the other branch |
| 1467 | * it is restored in build_huge_tlb_write_entry. | 1876 | * it is restored in build_huge_tlb_write_entry. |
| 1468 | */ | 1877 | */ |
| 1469 | build_restore_pagemask(&p, &r, K0, label_nopage_tlbl); | 1878 | build_restore_pagemask(&p, &r, K0, label_nopage_tlbl, 0); |
| 1470 | 1879 | ||
| 1471 | uasm_l_tlbl_goaround2(&l, p); | 1880 | uasm_l_tlbl_goaround2(&l, p); |
| 1472 | } | 1881 | } |
| @@ -1623,13 +2032,16 @@ void __cpuinit build_tlb_refill_handler(void) | |||
| 1623 | break; | 2032 | break; |
| 1624 | 2033 | ||
| 1625 | default: | 2034 | default: |
| 1626 | build_r4000_tlb_refill_handler(); | ||
| 1627 | if (!run_once) { | 2035 | if (!run_once) { |
| 2036 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
| 2037 | build_r4000_setup_pgd(); | ||
| 2038 | #endif | ||
| 1628 | build_r4000_tlb_load_handler(); | 2039 | build_r4000_tlb_load_handler(); |
| 1629 | build_r4000_tlb_store_handler(); | 2040 | build_r4000_tlb_store_handler(); |
| 1630 | build_r4000_tlb_modify_handler(); | 2041 | build_r4000_tlb_modify_handler(); |
| 1631 | run_once++; | 2042 | run_once++; |
| 1632 | } | 2043 | } |
| 2044 | build_r4000_tlb_refill_handler(); | ||
| 1633 | } | 2045 | } |
| 1634 | } | 2046 | } |
| 1635 | 2047 | ||
| @@ -1641,4 +2053,8 @@ void __cpuinit flush_tlb_handlers(void) | |||
| 1641 | (unsigned long)handle_tlbs + sizeof(handle_tlbs)); | 2053 | (unsigned long)handle_tlbs + sizeof(handle_tlbs)); |
| 1642 | local_flush_icache_range((unsigned long)handle_tlbm, | 2054 | local_flush_icache_range((unsigned long)handle_tlbm, |
| 1643 | (unsigned long)handle_tlbm + sizeof(handle_tlbm)); | 2055 | (unsigned long)handle_tlbm + sizeof(handle_tlbm)); |
| 2056 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
| 2057 | local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd, | ||
| 2058 | (unsigned long)tlbmiss_handler_setup_pgd + sizeof(handle_tlbm)); | ||
| 2059 | #endif | ||
| 1644 | } | 2060 | } |
diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index 23afdebc8e5c..5fa185151fc8 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c | |||
| @@ -68,7 +68,8 @@ enum opcode { | |||
| 68 | insn_pref, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll, | 68 | insn_pref, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll, |
| 69 | insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, insn_tlbp, | 69 | insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, insn_tlbp, |
| 70 | insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori, | 70 | insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori, |
| 71 | insn_dins, insn_syscall, insn_bbit0, insn_bbit1 | 71 | insn_dins, insn_dinsm, insn_syscall, insn_bbit0, insn_bbit1, |
| 72 | insn_lwx, insn_ldx | ||
| 72 | }; | 73 | }; |
| 73 | 74 | ||
| 74 | struct insn { | 75 | struct insn { |
| @@ -142,9 +143,12 @@ static struct insn insn_table[] __uasminitdata = { | |||
| 142 | { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD }, | 143 | { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD }, |
| 143 | { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, | 144 | { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, |
| 144 | { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE }, | 145 | { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE }, |
| 146 | { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE }, | ||
| 145 | { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM}, | 147 | { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM}, |
| 146 | { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, | 148 | { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, |
| 147 | { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, | 149 | { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, |
| 150 | { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD }, | ||
| 151 | { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD }, | ||
| 148 | { insn_invalid, 0, 0 } | 152 | { insn_invalid, 0, 0 } |
| 149 | }; | 153 | }; |
| 150 | 154 | ||
| @@ -152,91 +156,83 @@ static struct insn insn_table[] __uasminitdata = { | |||
| 152 | 156 | ||
| 153 | static inline __uasminit u32 build_rs(u32 arg) | 157 | static inline __uasminit u32 build_rs(u32 arg) |
| 154 | { | 158 | { |
| 155 | if (arg & ~RS_MASK) | 159 | WARN(arg & ~RS_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
| 156 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
| 157 | 160 | ||
| 158 | return (arg & RS_MASK) << RS_SH; | 161 | return (arg & RS_MASK) << RS_SH; |
| 159 | } | 162 | } |
| 160 | 163 | ||
| 161 | static inline __uasminit u32 build_rt(u32 arg) | 164 | static inline __uasminit u32 build_rt(u32 arg) |
| 162 | { | 165 | { |
| 163 | if (arg & ~RT_MASK) | 166 | WARN(arg & ~RT_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
| 164 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
| 165 | 167 | ||
| 166 | return (arg & RT_MASK) << RT_SH; | 168 | return (arg & RT_MASK) << RT_SH; |
| 167 | } | 169 | } |
| 168 | 170 | ||
| 169 | static inline __uasminit u32 build_rd(u32 arg) | 171 | static inline __uasminit u32 build_rd(u32 arg) |
| 170 | { | 172 | { |
| 171 | if (arg & ~RD_MASK) | 173 | WARN(arg & ~RD_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
| 172 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
| 173 | 174 | ||
| 174 | return (arg & RD_MASK) << RD_SH; | 175 | return (arg & RD_MASK) << RD_SH; |
| 175 | } | 176 | } |
| 176 | 177 | ||
| 177 | static inline __uasminit u32 build_re(u32 arg) | 178 | static inline __uasminit u32 build_re(u32 arg) |
| 178 | { | 179 | { |
| 179 | if (arg & ~RE_MASK) | 180 | WARN(arg & ~RE_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
| 180 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
| 181 | 181 | ||
| 182 | return (arg & RE_MASK) << RE_SH; | 182 | return (arg & RE_MASK) << RE_SH; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | static inline __uasminit u32 build_simm(s32 arg) | 185 | static inline __uasminit u32 build_simm(s32 arg) |
| 186 | { | 186 | { |
| 187 | if (arg > 0x7fff || arg < -0x8000) | 187 | WARN(arg > 0x7fff || arg < -0x8000, |
| 188 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | 188 | KERN_WARNING "Micro-assembler field overflow\n"); |
| 189 | 189 | ||
| 190 | return arg & 0xffff; | 190 | return arg & 0xffff; |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | static inline __uasminit u32 build_uimm(u32 arg) | 193 | static inline __uasminit u32 build_uimm(u32 arg) |
| 194 | { | 194 | { |
| 195 | if (arg & ~IMM_MASK) | 195 | WARN(arg & ~IMM_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
| 196 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
| 197 | 196 | ||
| 198 | return arg & IMM_MASK; | 197 | return arg & IMM_MASK; |
| 199 | } | 198 | } |
| 200 | 199 | ||
| 201 | static inline __uasminit u32 build_bimm(s32 arg) | 200 | static inline __uasminit u32 build_bimm(s32 arg) |
| 202 | { | 201 | { |
| 203 | if (arg > 0x1ffff || arg < -0x20000) | 202 | WARN(arg > 0x1ffff || arg < -0x20000, |
| 204 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | 203 | KERN_WARNING "Micro-assembler field overflow\n"); |
| 205 | 204 | ||
| 206 | if (arg & 0x3) | 205 | WARN(arg & 0x3, KERN_WARNING "Invalid micro-assembler branch target\n"); |
| 207 | printk(KERN_WARNING "Invalid micro-assembler branch target\n"); | ||
| 208 | 206 | ||
| 209 | return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff); | 207 | return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff); |
| 210 | } | 208 | } |
| 211 | 209 | ||
| 212 | static inline __uasminit u32 build_jimm(u32 arg) | 210 | static inline __uasminit u32 build_jimm(u32 arg) |
| 213 | { | 211 | { |
| 214 | if (arg & ~((JIMM_MASK) << 2)) | 212 | WARN(arg & ~(JIMM_MASK << 2), |
| 215 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | 213 | KERN_WARNING "Micro-assembler field overflow\n"); |
| 216 | 214 | ||
| 217 | return (arg >> 2) & JIMM_MASK; | 215 | return (arg >> 2) & JIMM_MASK; |
| 218 | } | 216 | } |
| 219 | 217 | ||
| 220 | static inline __uasminit u32 build_scimm(u32 arg) | 218 | static inline __uasminit u32 build_scimm(u32 arg) |
| 221 | { | 219 | { |
| 222 | if (arg & ~SCIMM_MASK) | 220 | WARN(arg & ~SCIMM_MASK, |
| 223 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | 221 | KERN_WARNING "Micro-assembler field overflow\n"); |
| 224 | 222 | ||
| 225 | return (arg & SCIMM_MASK) << SCIMM_SH; | 223 | return (arg & SCIMM_MASK) << SCIMM_SH; |
| 226 | } | 224 | } |
| 227 | 225 | ||
| 228 | static inline __uasminit u32 build_func(u32 arg) | 226 | static inline __uasminit u32 build_func(u32 arg) |
| 229 | { | 227 | { |
| 230 | if (arg & ~FUNC_MASK) | 228 | WARN(arg & ~FUNC_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
| 231 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
| 232 | 229 | ||
| 233 | return arg & FUNC_MASK; | 230 | return arg & FUNC_MASK; |
| 234 | } | 231 | } |
| 235 | 232 | ||
| 236 | static inline __uasminit u32 build_set(u32 arg) | 233 | static inline __uasminit u32 build_set(u32 arg) |
| 237 | { | 234 | { |
| 238 | if (arg & ~SET_MASK) | 235 | WARN(arg & ~SET_MASK, KERN_WARNING "Micro-assembler field overflow\n"); |
| 239 | printk(KERN_WARNING "Micro-assembler field overflow\n"); | ||
| 240 | 236 | ||
| 241 | return arg & SET_MASK; | 237 | return arg & SET_MASK; |
| 242 | } | 238 | } |
| @@ -340,6 +336,13 @@ Ip_u2u1msbu3(op) \ | |||
| 340 | } \ | 336 | } \ |
| 341 | UASM_EXPORT_SYMBOL(uasm_i##op); | 337 | UASM_EXPORT_SYMBOL(uasm_i##op); |
| 342 | 338 | ||
| 339 | #define I_u2u1msb32u3(op) \ | ||
| 340 | Ip_u2u1msbu3(op) \ | ||
| 341 | { \ | ||
| 342 | build_insn(buf, insn##op, b, a, c+d-33, c); \ | ||
| 343 | } \ | ||
| 344 | UASM_EXPORT_SYMBOL(uasm_i##op); | ||
| 345 | |||
| 343 | #define I_u1u2(op) \ | 346 | #define I_u1u2(op) \ |
| 344 | Ip_u1u2(op) \ | 347 | Ip_u1u2(op) \ |
| 345 | { \ | 348 | { \ |
| @@ -422,9 +425,12 @@ I_0(_tlbwr) | |||
| 422 | I_u3u1u2(_xor) | 425 | I_u3u1u2(_xor) |
| 423 | I_u2u1u3(_xori) | 426 | I_u2u1u3(_xori) |
| 424 | I_u2u1msbu3(_dins); | 427 | I_u2u1msbu3(_dins); |
| 428 | I_u2u1msb32u3(_dinsm); | ||
| 425 | I_u1(_syscall); | 429 | I_u1(_syscall); |
| 426 | I_u1u2s3(_bbit0); | 430 | I_u1u2s3(_bbit0); |
| 427 | I_u1u2s3(_bbit1); | 431 | I_u1u2s3(_bbit1); |
| 432 | I_u3u1u2(_lwx) | ||
| 433 | I_u3u1u2(_ldx) | ||
| 428 | 434 | ||
| 429 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | 435 | #ifdef CONFIG_CPU_CAVIUM_OCTEON |
| 430 | #include <asm/octeon/octeon.h> | 436 | #include <asm/octeon/octeon.h> |
diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c index 87ccdb4b5ac9..48853ab5bcf0 100644 --- a/arch/mips/sibyte/common/sb_tbprof.c +++ b/arch/mips/sibyte/common/sb_tbprof.c | |||
| @@ -410,14 +410,13 @@ static int sbprof_tb_open(struct inode *inode, struct file *filp) | |||
| 410 | return -EBUSY; | 410 | return -EBUSY; |
| 411 | 411 | ||
| 412 | memset(&sbp, 0, sizeof(struct sbprof_tb)); | 412 | memset(&sbp, 0, sizeof(struct sbprof_tb)); |
| 413 | sbp.sbprof_tbbuf = vmalloc(MAX_TBSAMPLE_BYTES); | 413 | sbp.sbprof_tbbuf = vzalloc(MAX_TBSAMPLE_BYTES); |
| 414 | if (!sbp.sbprof_tbbuf) { | 414 | if (!sbp.sbprof_tbbuf) { |
| 415 | sbp.open = SB_CLOSED; | 415 | sbp.open = SB_CLOSED; |
| 416 | wmb(); | 416 | wmb(); |
| 417 | return -ENOMEM; | 417 | return -ENOMEM; |
| 418 | } | 418 | } |
| 419 | 419 | ||
| 420 | memset(sbp.sbprof_tbbuf, 0, MAX_TBSAMPLE_BYTES); | ||
| 421 | init_waitqueue_head(&sbp.tb_sync); | 420 | init_waitqueue_head(&sbp.tb_sync); |
| 422 | init_waitqueue_head(&sbp.tb_read); | 421 | init_waitqueue_head(&sbp.tb_read); |
| 423 | mutex_init(&sbp.lock); | 422 | mutex_init(&sbp.lock); |
diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c index 96e69a00ffc8..85a87de17eb4 100644 --- a/arch/mips/txx9/generic/pci.c +++ b/arch/mips/txx9/generic/pci.c | |||
| @@ -213,11 +213,8 @@ txx9_alloc_pci_controller(struct pci_controller *pcic, | |||
| 213 | 213 | ||
| 214 | pcic->mem_offset = 0; /* busaddr == physaddr */ | 214 | pcic->mem_offset = 0; /* busaddr == physaddr */ |
| 215 | 215 | ||
| 216 | printk(KERN_INFO "PCI: IO 0x%08llx-0x%08llx MEM 0x%08llx-0x%08llx\n", | 216 | printk(KERN_INFO "PCI: IO %pR MEM %pR\n", |
| 217 | (unsigned long long)pcic->mem_resource[1].start, | 217 | &pcic->mem_resource[1], &pcic->mem_resource[0]); |
| 218 | (unsigned long long)pcic->mem_resource[1].end, | ||
| 219 | (unsigned long long)pcic->mem_resource[0].start, | ||
| 220 | (unsigned long long)pcic->mem_resource[0].end); | ||
| 221 | 218 | ||
| 222 | /* register_pci_controller() will request MEM resource */ | 219 | /* register_pci_controller() will request MEM resource */ |
| 223 | release_resource(&pcic->mem_resource[0]); | 220 | release_resource(&pcic->mem_resource[0]); |
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index df971fa0c32f..4896ed090585 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c | |||
| @@ -1126,15 +1126,13 @@ int pdc_iodc_print(const unsigned char *str, unsigned count) | |||
| 1126 | unsigned int i; | 1126 | unsigned int i; |
| 1127 | unsigned long flags; | 1127 | unsigned long flags; |
| 1128 | 1128 | ||
| 1129 | for (i = 0; i < count && i < 79;) { | 1129 | for (i = 0; i < count;) { |
| 1130 | switch(str[i]) { | 1130 | switch(str[i]) { |
| 1131 | case '\n': | 1131 | case '\n': |
| 1132 | iodc_dbuf[i+0] = '\r'; | 1132 | iodc_dbuf[i+0] = '\r'; |
| 1133 | iodc_dbuf[i+1] = '\n'; | 1133 | iodc_dbuf[i+1] = '\n'; |
| 1134 | i += 2; | 1134 | i += 2; |
| 1135 | goto print; | 1135 | goto print; |
| 1136 | case '\b': /* BS */ | ||
| 1137 | i--; /* overwrite last */ | ||
| 1138 | default: | 1136 | default: |
| 1139 | iodc_dbuf[i] = str[i]; | 1137 | iodc_dbuf[i] = str[i]; |
| 1140 | i++; | 1138 | i++; |
| @@ -1142,15 +1140,6 @@ int pdc_iodc_print(const unsigned char *str, unsigned count) | |||
| 1142 | } | 1140 | } |
| 1143 | } | 1141 | } |
| 1144 | 1142 | ||
| 1145 | /* if we're at the end of line, and not already inserting a newline, | ||
| 1146 | * insert one anyway. iodc console doesn't claim to support >79 char | ||
| 1147 | * lines. don't account for this in the return value. | ||
| 1148 | */ | ||
| 1149 | if (i == 79 && iodc_dbuf[i-1] != '\n') { | ||
| 1150 | iodc_dbuf[i+0] = '\r'; | ||
| 1151 | iodc_dbuf[i+1] = '\n'; | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | print: | 1143 | print: |
| 1155 | spin_lock_irqsave(&pdc_lock, flags); | 1144 | spin_lock_irqsave(&pdc_lock, flags); |
| 1156 | real32_call(PAGE0->mem_cons.iodc_io, | 1145 | real32_call(PAGE0->mem_cons.iodc_io, |
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index 48ff6dcffa02..9974d21048fd 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c | |||
| @@ -129,8 +129,7 @@ void __cpuinit irq_ctx_init(int cpu) | |||
| 129 | irqctx = page_address(alloc_pages_node(cpu_to_node(cpu), | 129 | irqctx = page_address(alloc_pages_node(cpu_to_node(cpu), |
| 130 | THREAD_FLAGS, | 130 | THREAD_FLAGS, |
| 131 | THREAD_ORDER)); | 131 | THREAD_ORDER)); |
| 132 | irqctx->tinfo.task = NULL; | 132 | memset(&irqctx->tinfo, 0, sizeof(struct thread_info)); |
| 133 | irqctx->tinfo.exec_domain = NULL; | ||
| 134 | irqctx->tinfo.cpu = cpu; | 133 | irqctx->tinfo.cpu = cpu; |
| 135 | irqctx->tinfo.preempt_count = HARDIRQ_OFFSET; | 134 | irqctx->tinfo.preempt_count = HARDIRQ_OFFSET; |
| 136 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); | 135 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); |
| @@ -140,10 +139,8 @@ void __cpuinit irq_ctx_init(int cpu) | |||
| 140 | irqctx = page_address(alloc_pages_node(cpu_to_node(cpu), | 139 | irqctx = page_address(alloc_pages_node(cpu_to_node(cpu), |
| 141 | THREAD_FLAGS, | 140 | THREAD_FLAGS, |
| 142 | THREAD_ORDER)); | 141 | THREAD_ORDER)); |
| 143 | irqctx->tinfo.task = NULL; | 142 | memset(&irqctx->tinfo, 0, sizeof(struct thread_info)); |
| 144 | irqctx->tinfo.exec_domain = NULL; | ||
| 145 | irqctx->tinfo.cpu = cpu; | 143 | irqctx->tinfo.cpu = cpu; |
| 146 | irqctx->tinfo.preempt_count = 0; | ||
| 147 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); | 144 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); |
| 148 | 145 | ||
| 149 | per_cpu(softirq_ctx, cpu) = irqctx; | 146 | per_cpu(softirq_ctx, cpu) = irqctx; |
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index bf4700755184..b34ab80fddd5 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S | |||
| @@ -34,11 +34,9 @@ OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT) | |||
| 34 | #ifdef CONFIG_X86_32 | 34 | #ifdef CONFIG_X86_32 |
| 35 | OUTPUT_ARCH(i386) | 35 | OUTPUT_ARCH(i386) |
| 36 | ENTRY(phys_startup_32) | 36 | ENTRY(phys_startup_32) |
| 37 | jiffies = jiffies_64; | ||
| 38 | #else | 37 | #else |
| 39 | OUTPUT_ARCH(i386:x86-64) | 38 | OUTPUT_ARCH(i386:x86-64) |
| 40 | ENTRY(phys_startup_64) | 39 | ENTRY(phys_startup_64) |
| 41 | jiffies_64 = jiffies; | ||
| 42 | #endif | 40 | #endif |
| 43 | 41 | ||
| 44 | #if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) | 42 | #if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) |
| @@ -142,6 +140,15 @@ SECTIONS | |||
| 142 | CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES) | 140 | CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES) |
| 143 | 141 | ||
| 144 | DATA_DATA | 142 | DATA_DATA |
| 143 | /* | ||
| 144 | * Workaround a binutils (2.20.51.0.12 to 2.21.51.0.3) bug. | ||
| 145 | * This makes jiffies relocatable in such binutils | ||
| 146 | */ | ||
| 147 | #ifdef CONFIG_X86_32 | ||
| 148 | jiffies = jiffies_64; | ||
| 149 | #else | ||
| 150 | jiffies_64 = jiffies; | ||
| 151 | #endif | ||
| 145 | CONSTRUCTORS | 152 | CONSTRUCTORS |
| 146 | 153 | ||
| 147 | /* rarely changed data like cpu maps */ | 154 | /* rarely changed data like cpu maps */ |
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 13bfa9d48082..bb233a9cbad2 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
| @@ -53,6 +53,14 @@ if SPI_MASTER | |||
| 53 | 53 | ||
| 54 | comment "SPI Master Controller Drivers" | 54 | comment "SPI Master Controller Drivers" |
| 55 | 55 | ||
| 56 | config SPI_ATH79 | ||
| 57 | tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver" | ||
| 58 | depends on ATH79 && GENERIC_GPIO | ||
| 59 | select SPI_BITBANG | ||
| 60 | help | ||
| 61 | This enables support for the SPI controller present on the | ||
| 62 | Atheros AR71XX/AR724X/AR913X SoCs. | ||
| 63 | |||
| 56 | config SPI_ATMEL | 64 | config SPI_ATMEL |
| 57 | tristate "Atmel SPI Controller" | 65 | tristate "Atmel SPI Controller" |
| 58 | depends on (ARCH_AT91 || AVR32) | 66 | depends on (ARCH_AT91 || AVR32) |
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 3a42463c92a4..86d1b5f9bbd9 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile | |||
| @@ -10,6 +10,7 @@ obj-$(CONFIG_SPI_MASTER) += spi.o | |||
| 10 | 10 | ||
| 11 | # SPI master controller drivers (bus) | 11 | # SPI master controller drivers (bus) |
| 12 | obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o | 12 | obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o |
| 13 | obj-$(CONFIG_SPI_ATH79) += ath79_spi.o | ||
| 13 | obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o | 14 | obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o |
| 14 | obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o | 15 | obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o |
| 15 | obj-$(CONFIG_SPI_AU1550) += au1550_spi.o | 16 | obj-$(CONFIG_SPI_AU1550) += au1550_spi.o |
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c new file mode 100644 index 000000000000..fcff810ea3b0 --- /dev/null +++ b/drivers/spi/ath79_spi.c | |||
| @@ -0,0 +1,292 @@ | |||
| 1 | /* | ||
| 2 | * SPI controller driver for the Atheros AR71XX/AR724X/AR913X SoCs | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * | ||
| 6 | * This driver has been based on the spi-gpio.c: | ||
| 7 | * Copyright (C) 2006,2008 David Brownell | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/delay.h> | ||
| 18 | #include <linux/spinlock.h> | ||
| 19 | #include <linux/workqueue.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/io.h> | ||
| 22 | #include <linux/spi/spi.h> | ||
| 23 | #include <linux/spi/spi_bitbang.h> | ||
| 24 | #include <linux/bitops.h> | ||
| 25 | #include <linux/gpio.h> | ||
| 26 | |||
| 27 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
| 28 | #include <asm/mach-ath79/ath79_spi_platform.h> | ||
| 29 | |||
| 30 | #define DRV_NAME "ath79-spi" | ||
| 31 | |||
| 32 | struct ath79_spi { | ||
| 33 | struct spi_bitbang bitbang; | ||
| 34 | u32 ioc_base; | ||
| 35 | u32 reg_ctrl; | ||
| 36 | void __iomem *base; | ||
| 37 | }; | ||
| 38 | |||
| 39 | static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg) | ||
| 40 | { | ||
| 41 | return ioread32(sp->base + reg); | ||
| 42 | } | ||
| 43 | |||
| 44 | static inline void ath79_spi_wr(struct ath79_spi *sp, unsigned reg, u32 val) | ||
| 45 | { | ||
| 46 | iowrite32(val, sp->base + reg); | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi) | ||
| 50 | { | ||
| 51 | return spi_master_get_devdata(spi->master); | ||
| 52 | } | ||
| 53 | |||
| 54 | static void ath79_spi_chipselect(struct spi_device *spi, int is_active) | ||
| 55 | { | ||
| 56 | struct ath79_spi *sp = ath79_spidev_to_sp(spi); | ||
| 57 | int cs_high = (spi->mode & SPI_CS_HIGH) ? is_active : !is_active; | ||
| 58 | |||
| 59 | if (is_active) { | ||
| 60 | /* set initial clock polarity */ | ||
| 61 | if (spi->mode & SPI_CPOL) | ||
| 62 | sp->ioc_base |= AR71XX_SPI_IOC_CLK; | ||
| 63 | else | ||
| 64 | sp->ioc_base &= ~AR71XX_SPI_IOC_CLK; | ||
| 65 | |||
| 66 | ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); | ||
| 67 | } | ||
| 68 | |||
| 69 | if (spi->chip_select) { | ||
| 70 | struct ath79_spi_controller_data *cdata = spi->controller_data; | ||
| 71 | |||
| 72 | /* SPI is normally active-low */ | ||
| 73 | gpio_set_value(cdata->gpio, cs_high); | ||
| 74 | } else { | ||
| 75 | if (cs_high) | ||
| 76 | sp->ioc_base |= AR71XX_SPI_IOC_CS0; | ||
| 77 | else | ||
| 78 | sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; | ||
| 79 | |||
| 80 | ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); | ||
| 81 | } | ||
| 82 | |||
| 83 | } | ||
| 84 | |||
| 85 | static int ath79_spi_setup_cs(struct spi_device *spi) | ||
| 86 | { | ||
| 87 | struct ath79_spi *sp = ath79_spidev_to_sp(spi); | ||
| 88 | struct ath79_spi_controller_data *cdata; | ||
| 89 | |||
| 90 | cdata = spi->controller_data; | ||
| 91 | if (spi->chip_select && !cdata) | ||
| 92 | return -EINVAL; | ||
| 93 | |||
| 94 | /* enable GPIO mode */ | ||
| 95 | ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO); | ||
| 96 | |||
| 97 | /* save CTRL register */ | ||
| 98 | sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL); | ||
| 99 | sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC); | ||
| 100 | |||
| 101 | /* TODO: setup speed? */ | ||
| 102 | ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43); | ||
| 103 | |||
| 104 | if (spi->chip_select) { | ||
| 105 | int status = 0; | ||
| 106 | |||
| 107 | status = gpio_request(cdata->gpio, dev_name(&spi->dev)); | ||
| 108 | if (status) | ||
| 109 | return status; | ||
| 110 | |||
| 111 | status = gpio_direction_output(cdata->gpio, | ||
| 112 | spi->mode & SPI_CS_HIGH); | ||
| 113 | if (status) { | ||
| 114 | gpio_free(cdata->gpio); | ||
| 115 | return status; | ||
| 116 | } | ||
| 117 | } else { | ||
| 118 | if (spi->mode & SPI_CS_HIGH) | ||
| 119 | sp->ioc_base |= AR71XX_SPI_IOC_CS0; | ||
| 120 | else | ||
| 121 | sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; | ||
| 122 | ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); | ||
| 123 | } | ||
| 124 | |||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | static void ath79_spi_cleanup_cs(struct spi_device *spi) | ||
| 129 | { | ||
| 130 | struct ath79_spi *sp = ath79_spidev_to_sp(spi); | ||
| 131 | |||
| 132 | if (spi->chip_select) { | ||
| 133 | struct ath79_spi_controller_data *cdata = spi->controller_data; | ||
| 134 | gpio_free(cdata->gpio); | ||
| 135 | } | ||
| 136 | |||
| 137 | /* restore CTRL register */ | ||
| 138 | ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, sp->reg_ctrl); | ||
| 139 | /* disable GPIO mode */ | ||
| 140 | ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0); | ||
| 141 | } | ||
| 142 | |||
| 143 | static int ath79_spi_setup(struct spi_device *spi) | ||
| 144 | { | ||
| 145 | int status = 0; | ||
| 146 | |||
| 147 | if (spi->bits_per_word > 32) | ||
| 148 | return -EINVAL; | ||
| 149 | |||
| 150 | if (!spi->controller_state) { | ||
| 151 | status = ath79_spi_setup_cs(spi); | ||
| 152 | if (status) | ||
| 153 | return status; | ||
| 154 | } | ||
| 155 | |||
| 156 | status = spi_bitbang_setup(spi); | ||
| 157 | if (status && !spi->controller_state) | ||
| 158 | ath79_spi_cleanup_cs(spi); | ||
| 159 | |||
| 160 | return status; | ||
| 161 | } | ||
| 162 | |||
| 163 | static void ath79_spi_cleanup(struct spi_device *spi) | ||
| 164 | { | ||
| 165 | ath79_spi_cleanup_cs(spi); | ||
| 166 | spi_bitbang_cleanup(spi); | ||
| 167 | } | ||
| 168 | |||
| 169 | static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs, | ||
| 170 | u32 word, u8 bits) | ||
| 171 | { | ||
| 172 | struct ath79_spi *sp = ath79_spidev_to_sp(spi); | ||
| 173 | u32 ioc = sp->ioc_base; | ||
| 174 | |||
| 175 | /* clock starts at inactive polarity */ | ||
| 176 | for (word <<= (32 - bits); likely(bits); bits--) { | ||
| 177 | u32 out; | ||
| 178 | |||
| 179 | if (word & (1 << 31)) | ||
| 180 | out = ioc | AR71XX_SPI_IOC_DO; | ||
| 181 | else | ||
| 182 | out = ioc & ~AR71XX_SPI_IOC_DO; | ||
| 183 | |||
| 184 | /* setup MSB (to slave) on trailing edge */ | ||
| 185 | ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out); | ||
| 186 | ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK); | ||
| 187 | |||
| 188 | word <<= 1; | ||
| 189 | } | ||
| 190 | |||
| 191 | return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS); | ||
| 192 | } | ||
| 193 | |||
| 194 | static __devinit int ath79_spi_probe(struct platform_device *pdev) | ||
| 195 | { | ||
| 196 | struct spi_master *master; | ||
| 197 | struct ath79_spi *sp; | ||
| 198 | struct ath79_spi_platform_data *pdata; | ||
| 199 | struct resource *r; | ||
| 200 | int ret; | ||
| 201 | |||
| 202 | master = spi_alloc_master(&pdev->dev, sizeof(*sp)); | ||
| 203 | if (master == NULL) { | ||
| 204 | dev_err(&pdev->dev, "failed to allocate spi master\n"); | ||
| 205 | return -ENOMEM; | ||
| 206 | } | ||
| 207 | |||
| 208 | sp = spi_master_get_devdata(master); | ||
| 209 | platform_set_drvdata(pdev, sp); | ||
| 210 | |||
| 211 | pdata = pdev->dev.platform_data; | ||
| 212 | |||
| 213 | master->setup = ath79_spi_setup; | ||
| 214 | master->cleanup = ath79_spi_cleanup; | ||
| 215 | if (pdata) { | ||
| 216 | master->bus_num = pdata->bus_num; | ||
| 217 | master->num_chipselect = pdata->num_chipselect; | ||
| 218 | } else { | ||
| 219 | master->bus_num = -1; | ||
| 220 | master->num_chipselect = 1; | ||
| 221 | } | ||
| 222 | |||
| 223 | sp->bitbang.master = spi_master_get(master); | ||
| 224 | sp->bitbang.chipselect = ath79_spi_chipselect; | ||
| 225 | sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0; | ||
| 226 | sp->bitbang.setup_transfer = spi_bitbang_setup_transfer; | ||
| 227 | sp->bitbang.flags = SPI_CS_HIGH; | ||
| 228 | |||
| 229 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 230 | if (r == NULL) { | ||
| 231 | ret = -ENOENT; | ||
| 232 | goto err_put_master; | ||
| 233 | } | ||
| 234 | |||
| 235 | sp->base = ioremap(r->start, r->end - r->start + 1); | ||
| 236 | if (!sp->base) { | ||
| 237 | ret = -ENXIO; | ||
| 238 | goto err_put_master; | ||
| 239 | } | ||
| 240 | |||
| 241 | ret = spi_bitbang_start(&sp->bitbang); | ||
| 242 | if (ret) | ||
| 243 | goto err_unmap; | ||
| 244 | |||
| 245 | return 0; | ||
| 246 | |||
| 247 | err_unmap: | ||
| 248 | iounmap(sp->base); | ||
| 249 | err_put_master: | ||
| 250 | platform_set_drvdata(pdev, NULL); | ||
| 251 | spi_master_put(sp->bitbang.master); | ||
| 252 | |||
| 253 | return ret; | ||
| 254 | } | ||
| 255 | |||
| 256 | static __devexit int ath79_spi_remove(struct platform_device *pdev) | ||
| 257 | { | ||
| 258 | struct ath79_spi *sp = platform_get_drvdata(pdev); | ||
| 259 | |||
| 260 | spi_bitbang_stop(&sp->bitbang); | ||
| 261 | iounmap(sp->base); | ||
| 262 | platform_set_drvdata(pdev, NULL); | ||
| 263 | spi_master_put(sp->bitbang.master); | ||
| 264 | |||
| 265 | return 0; | ||
| 266 | } | ||
| 267 | |||
| 268 | static struct platform_driver ath79_spi_driver = { | ||
| 269 | .probe = ath79_spi_probe, | ||
| 270 | .remove = __devexit_p(ath79_spi_remove), | ||
| 271 | .driver = { | ||
| 272 | .name = DRV_NAME, | ||
| 273 | .owner = THIS_MODULE, | ||
| 274 | }, | ||
| 275 | }; | ||
| 276 | |||
| 277 | static __init int ath79_spi_init(void) | ||
| 278 | { | ||
| 279 | return platform_driver_register(&ath79_spi_driver); | ||
| 280 | } | ||
| 281 | module_init(ath79_spi_init); | ||
| 282 | |||
| 283 | static __exit void ath79_spi_exit(void) | ||
| 284 | { | ||
| 285 | platform_driver_unregister(&ath79_spi_driver); | ||
| 286 | } | ||
| 287 | module_exit(ath79_spi_exit); | ||
| 288 | |||
| 289 | MODULE_DESCRIPTION("SPI controller driver for Atheros AR71XX/AR724X/AR913X"); | ||
| 290 | MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); | ||
| 291 | MODULE_LICENSE("GPL v2"); | ||
| 292 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 05ebe841270b..84522c796987 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
| @@ -2228,14 +2228,11 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) | |||
| 2228 | unsigned long flags; | 2228 | unsigned long flags; |
| 2229 | int ctxn, err; | 2229 | int ctxn, err; |
| 2230 | 2230 | ||
| 2231 | if (!task && cpu != -1) { | 2231 | if (!task) { |
| 2232 | /* Must be root to operate on a CPU event: */ | 2232 | /* Must be root to operate on a CPU event: */ |
| 2233 | if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) | 2233 | if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) |
| 2234 | return ERR_PTR(-EACCES); | 2234 | return ERR_PTR(-EACCES); |
| 2235 | 2235 | ||
| 2236 | if (cpu < 0 || cpu >= nr_cpumask_bits) | ||
| 2237 | return ERR_PTR(-EINVAL); | ||
| 2238 | |||
| 2239 | /* | 2236 | /* |
| 2240 | * We could be clever and allow to attach a event to an | 2237 | * We could be clever and allow to attach a event to an |
| 2241 | * offline CPU and activate it when the CPU comes up, but | 2238 | * offline CPU and activate it when the CPU comes up, but |
| @@ -5541,6 +5538,11 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, | |||
| 5541 | struct hw_perf_event *hwc; | 5538 | struct hw_perf_event *hwc; |
| 5542 | long err; | 5539 | long err; |
| 5543 | 5540 | ||
| 5541 | if ((unsigned)cpu >= nr_cpu_ids) { | ||
| 5542 | if (!task || cpu != -1) | ||
| 5543 | return ERR_PTR(-EINVAL); | ||
| 5544 | } | ||
| 5545 | |||
| 5544 | event = kzalloc(sizeof(*event), GFP_KERNEL); | 5546 | event = kzalloc(sizeof(*event), GFP_KERNEL); |
| 5545 | if (!event) | 5547 | if (!event) |
| 5546 | return ERR_PTR(-ENOMEM); | 5548 | return ERR_PTR(-ENOMEM); |
| @@ -5589,7 +5591,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, | |||
| 5589 | 5591 | ||
| 5590 | if (!overflow_handler && parent_event) | 5592 | if (!overflow_handler && parent_event) |
| 5591 | overflow_handler = parent_event->overflow_handler; | 5593 | overflow_handler = parent_event->overflow_handler; |
| 5592 | 5594 | ||
| 5593 | event->overflow_handler = overflow_handler; | 5595 | event->overflow_handler = overflow_handler; |
| 5594 | 5596 | ||
| 5595 | if (attr->disabled) | 5597 | if (attr->disabled) |
| @@ -6494,7 +6496,6 @@ int perf_event_init_context(struct task_struct *child, int ctxn) | |||
| 6494 | 6496 | ||
| 6495 | raw_spin_lock_irqsave(&parent_ctx->lock, flags); | 6497 | raw_spin_lock_irqsave(&parent_ctx->lock, flags); |
| 6496 | parent_ctx->rotate_disable = 0; | 6498 | parent_ctx->rotate_disable = 0; |
| 6497 | raw_spin_unlock_irqrestore(&parent_ctx->lock, flags); | ||
| 6498 | 6499 | ||
| 6499 | child_ctx = child->perf_event_ctxp[ctxn]; | 6500 | child_ctx = child->perf_event_ctxp[ctxn]; |
| 6500 | 6501 | ||
| @@ -6502,12 +6503,11 @@ int perf_event_init_context(struct task_struct *child, int ctxn) | |||
| 6502 | /* | 6503 | /* |
| 6503 | * Mark the child context as a clone of the parent | 6504 | * Mark the child context as a clone of the parent |
| 6504 | * context, or of whatever the parent is a clone of. | 6505 | * context, or of whatever the parent is a clone of. |
| 6505 | * Note that if the parent is a clone, it could get | 6506 | * |
| 6506 | * uncloned at any point, but that doesn't matter | 6507 | * Note that if the parent is a clone, the holding of |
| 6507 | * because the list of events and the generation | 6508 | * parent_ctx->lock avoids it from being uncloned. |
| 6508 | * count can't have changed since we took the mutex. | ||
| 6509 | */ | 6509 | */ |
| 6510 | cloned_ctx = rcu_dereference(parent_ctx->parent_ctx); | 6510 | cloned_ctx = parent_ctx->parent_ctx; |
| 6511 | if (cloned_ctx) { | 6511 | if (cloned_ctx) { |
| 6512 | child_ctx->parent_ctx = cloned_ctx; | 6512 | child_ctx->parent_ctx = cloned_ctx; |
| 6513 | child_ctx->parent_gen = parent_ctx->parent_gen; | 6513 | child_ctx->parent_gen = parent_ctx->parent_gen; |
| @@ -6518,6 +6518,7 @@ int perf_event_init_context(struct task_struct *child, int ctxn) | |||
| 6518 | get_ctx(child_ctx->parent_ctx); | 6518 | get_ctx(child_ctx->parent_ctx); |
| 6519 | } | 6519 | } |
| 6520 | 6520 | ||
| 6521 | raw_spin_unlock_irqrestore(&parent_ctx->lock, flags); | ||
| 6521 | mutex_unlock(&parent_ctx->mutex); | 6522 | mutex_unlock(&parent_ctx->mutex); |
| 6522 | 6523 | ||
| 6523 | perf_unpin_context(parent_ctx); | 6524 | perf_unpin_context(parent_ctx); |
