diff options
24 files changed, 696 insertions, 167 deletions
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 02d6d29a63c1..3a617af60d46 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig | |||
| @@ -14,6 +14,7 @@ config XTENSA | |||
| 14 | select GENERIC_PCI_IOMAP | 14 | select GENERIC_PCI_IOMAP |
| 15 | select ARCH_WANT_IPC_PARSE_VERSION | 15 | select ARCH_WANT_IPC_PARSE_VERSION |
| 16 | select ARCH_WANT_OPTIONAL_GPIOLIB | 16 | select ARCH_WANT_OPTIONAL_GPIOLIB |
| 17 | select BUILDTIME_EXTABLE_SORT | ||
| 17 | select CLONE_BACKWARDS | 18 | select CLONE_BACKWARDS |
| 18 | select IRQ_DOMAIN | 19 | select IRQ_DOMAIN |
| 19 | select HAVE_OPROFILE | 20 | select HAVE_OPROFILE |
| @@ -189,6 +190,24 @@ config INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX | |||
| 189 | 190 | ||
| 190 | If in doubt, say Y. | 191 | If in doubt, say Y. |
| 191 | 192 | ||
| 193 | config HIGHMEM | ||
| 194 | bool "High Memory Support" | ||
| 195 | help | ||
| 196 | Linux can use the full amount of RAM in the system by | ||
| 197 | default. However, the default MMUv2 setup only maps the | ||
| 198 | lowermost 128 MB of memory linearly to the areas starting | ||
| 199 | at 0xd0000000 (cached) and 0xd8000000 (uncached). | ||
| 200 | When there are more than 128 MB memory in the system not | ||
| 201 | all of it can be "permanently mapped" by the kernel. | ||
| 202 | The physical memory that's not permanently mapped is called | ||
| 203 | "high memory". | ||
| 204 | |||
| 205 | If you are compiling a kernel which will never run on a | ||
| 206 | machine with more than 128 MB total physical RAM, answer | ||
| 207 | N here. | ||
| 208 | |||
| 209 | If unsure, say Y. | ||
| 210 | |||
| 192 | endmenu | 211 | endmenu |
| 193 | 212 | ||
| 194 | config XTENSA_CALIBRATE_CCOUNT | 213 | config XTENSA_CALIBRATE_CCOUNT |
| @@ -224,7 +243,6 @@ choice | |||
| 224 | 243 | ||
| 225 | config XTENSA_PLATFORM_ISS | 244 | config XTENSA_PLATFORM_ISS |
| 226 | bool "ISS" | 245 | bool "ISS" |
| 227 | depends on TTY | ||
| 228 | select XTENSA_CALIBRATE_CCOUNT | 246 | select XTENSA_CALIBRATE_CCOUNT |
| 229 | select SERIAL_CONSOLE | 247 | select SERIAL_CONSOLE |
| 230 | help | 248 | help |
diff --git a/arch/xtensa/boot/dts/kc705.dts b/arch/xtensa/boot/dts/kc705.dts new file mode 100644 index 000000000000..742a347be67a --- /dev/null +++ b/arch/xtensa/boot/dts/kc705.dts | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | /dts-v1/; | ||
| 2 | /include/ "xtfpga.dtsi" | ||
| 3 | /include/ "xtfpga-flash-128m.dtsi" | ||
| 4 | |||
| 5 | / { | ||
| 6 | compatible = "cdns,xtensa-kc705"; | ||
| 7 | memory@0 { | ||
| 8 | device_type = "memory"; | ||
| 9 | reg = <0x00000000 0x08000000>; | ||
| 10 | }; | ||
| 11 | }; | ||
diff --git a/arch/xtensa/boot/dts/xtfpga-flash-128m.dtsi b/arch/xtensa/boot/dts/xtfpga-flash-128m.dtsi new file mode 100644 index 000000000000..d3a88e029873 --- /dev/null +++ b/arch/xtensa/boot/dts/xtfpga-flash-128m.dtsi | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | / { | ||
| 2 | soc { | ||
| 3 | flash: flash@00000000 { | ||
| 4 | #address-cells = <1>; | ||
| 5 | #size-cells = <1>; | ||
| 6 | compatible = "cfi-flash"; | ||
| 7 | reg = <0x00000000 0x08000000>; | ||
| 8 | bank-width = <2>; | ||
| 9 | device-width = <2>; | ||
| 10 | partition@0x0 { | ||
| 11 | label = "data"; | ||
| 12 | reg = <0x00000000 0x06000000>; | ||
| 13 | }; | ||
| 14 | partition@0x6000000 { | ||
| 15 | label = "boot loader area"; | ||
| 16 | reg = <0x06000000 0x00800000>; | ||
| 17 | }; | ||
| 18 | partition@0x6800000 { | ||
| 19 | label = "kernel image"; | ||
| 20 | reg = <0x06800000 0x017e0000>; | ||
| 21 | }; | ||
| 22 | partition@0x7fe0000 { | ||
| 23 | label = "boot environment"; | ||
| 24 | reg = <0x07fe0000 0x00020000>; | ||
| 25 | }; | ||
| 26 | }; | ||
| 27 | }; | ||
| 28 | }; | ||
diff --git a/arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi b/arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi index e5703c7beeb6..1d97203c18e7 100644 --- a/arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi +++ b/arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi | |||
| @@ -1,26 +1,28 @@ | |||
| 1 | / { | 1 | / { |
| 2 | flash: flash@f8000000 { | 2 | soc { |
| 3 | #address-cells = <1>; | 3 | flash: flash@08000000 { |
| 4 | #size-cells = <1>; | 4 | #address-cells = <1>; |
| 5 | compatible = "cfi-flash"; | 5 | #size-cells = <1>; |
| 6 | reg = <0xf8000000 0x01000000>; | 6 | compatible = "cfi-flash"; |
| 7 | bank-width = <2>; | 7 | reg = <0x08000000 0x01000000>; |
| 8 | device-width = <2>; | 8 | bank-width = <2>; |
| 9 | partition@0x0 { | 9 | device-width = <2>; |
| 10 | label = "boot loader area"; | 10 | partition@0x0 { |
| 11 | reg = <0x00000000 0x00400000>; | 11 | label = "boot loader area"; |
| 12 | reg = <0x00000000 0x00400000>; | ||
| 13 | }; | ||
| 14 | partition@0x400000 { | ||
| 15 | label = "kernel image"; | ||
| 16 | reg = <0x00400000 0x00600000>; | ||
| 17 | }; | ||
| 18 | partition@0xa00000 { | ||
| 19 | label = "data"; | ||
| 20 | reg = <0x00a00000 0x005e0000>; | ||
| 21 | }; | ||
| 22 | partition@0xfe0000 { | ||
| 23 | label = "boot environment"; | ||
| 24 | reg = <0x00fe0000 0x00020000>; | ||
| 25 | }; | ||
| 12 | }; | 26 | }; |
| 13 | partition@0x400000 { | 27 | }; |
| 14 | label = "kernel image"; | ||
| 15 | reg = <0x00400000 0x00600000>; | ||
| 16 | }; | ||
| 17 | partition@0xa00000 { | ||
| 18 | label = "data"; | ||
| 19 | reg = <0x00a00000 0x005e0000>; | ||
| 20 | }; | ||
| 21 | partition@0xfe0000 { | ||
| 22 | label = "boot environment"; | ||
| 23 | reg = <0x00fe0000 0x00020000>; | ||
| 24 | }; | ||
| 25 | }; | ||
| 26 | }; | 28 | }; |
diff --git a/arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi b/arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi index 6f9c10d6b689..d1c621ca8be1 100644 --- a/arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi +++ b/arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi | |||
| @@ -1,18 +1,20 @@ | |||
| 1 | / { | 1 | / { |
| 2 | flash: flash@f8000000 { | 2 | soc { |
| 3 | #address-cells = <1>; | 3 | flash: flash@08000000 { |
| 4 | #size-cells = <1>; | 4 | #address-cells = <1>; |
| 5 | compatible = "cfi-flash"; | 5 | #size-cells = <1>; |
| 6 | reg = <0xf8000000 0x00400000>; | 6 | compatible = "cfi-flash"; |
| 7 | bank-width = <2>; | 7 | reg = <0x08000000 0x00400000>; |
| 8 | device-width = <2>; | 8 | bank-width = <2>; |
| 9 | partition@0x0 { | 9 | device-width = <2>; |
| 10 | label = "boot loader area"; | 10 | partition@0x0 { |
| 11 | reg = <0x00000000 0x003f0000>; | 11 | label = "boot loader area"; |
| 12 | reg = <0x00000000 0x003f0000>; | ||
| 13 | }; | ||
| 14 | partition@0x3f0000 { | ||
| 15 | label = "boot environment"; | ||
| 16 | reg = <0x003f0000 0x00010000>; | ||
| 17 | }; | ||
| 12 | }; | 18 | }; |
| 13 | partition@0x3f0000 { | 19 | }; |
| 14 | label = "boot environment"; | ||
| 15 | reg = <0x003f0000 0x00010000>; | ||
| 16 | }; | ||
| 17 | }; | ||
| 18 | }; | 20 | }; |
diff --git a/arch/xtensa/boot/dts/xtfpga.dtsi b/arch/xtensa/boot/dts/xtfpga.dtsi index e7370b11348e..dec9178840f6 100644 --- a/arch/xtensa/boot/dts/xtfpga.dtsi +++ b/arch/xtensa/boot/dts/xtfpga.dtsi | |||
| @@ -42,21 +42,28 @@ | |||
| 42 | }; | 42 | }; |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | serial0: serial@fd050020 { | 45 | soc { |
| 46 | device_type = "serial"; | 46 | #address-cells = <1>; |
| 47 | compatible = "ns16550a"; | 47 | #size-cells = <1>; |
| 48 | no-loopback-test; | 48 | compatible = "simple-bus"; |
| 49 | reg = <0xfd050020 0x20>; | 49 | ranges = <0x00000000 0xf0000000 0x10000000>; |
| 50 | reg-shift = <2>; | ||
| 51 | interrupts = <0 1>; /* external irq 0 */ | ||
| 52 | clocks = <&osc>; | ||
| 53 | }; | ||
| 54 | 50 | ||
| 55 | enet0: ethoc@fd030000 { | 51 | serial0: serial@0d050020 { |
| 56 | compatible = "opencores,ethoc"; | 52 | device_type = "serial"; |
| 57 | reg = <0xfd030000 0x4000 0xfd800000 0x4000>; | 53 | compatible = "ns16550a"; |
| 58 | interrupts = <1 1>; /* external irq 1 */ | 54 | no-loopback-test; |
| 59 | local-mac-address = [00 50 c2 13 6f 00]; | 55 | reg = <0x0d050020 0x20>; |
| 60 | clocks = <&osc>; | 56 | reg-shift = <2>; |
| 57 | interrupts = <0 1>; /* external irq 0 */ | ||
| 58 | clocks = <&osc>; | ||
| 59 | }; | ||
| 60 | |||
| 61 | enet0: ethoc@0d030000 { | ||
| 62 | compatible = "opencores,ethoc"; | ||
| 63 | reg = <0x0d030000 0x4000 0x0d800000 0x4000>; | ||
| 64 | interrupts = <1 1>; /* external irq 1 */ | ||
| 65 | local-mac-address = [00 50 c2 13 6f 00]; | ||
| 66 | clocks = <&osc>; | ||
| 67 | }; | ||
| 61 | }; | 68 | }; |
| 62 | }; | 69 | }; |
diff --git a/arch/xtensa/include/asm/bootparam.h b/arch/xtensa/include/asm/bootparam.h index 23392c5630ce..892aab399ac8 100644 --- a/arch/xtensa/include/asm/bootparam.h +++ b/arch/xtensa/include/asm/bootparam.h | |||
| @@ -37,23 +37,14 @@ typedef struct bp_tag { | |||
| 37 | unsigned long data[0]; /* data */ | 37 | unsigned long data[0]; /* data */ |
| 38 | } bp_tag_t; | 38 | } bp_tag_t; |
| 39 | 39 | ||
| 40 | typedef struct meminfo { | 40 | struct bp_meminfo { |
| 41 | unsigned long type; | 41 | unsigned long type; |
| 42 | unsigned long start; | 42 | unsigned long start; |
| 43 | unsigned long end; | 43 | unsigned long end; |
| 44 | } meminfo_t; | 44 | }; |
| 45 | |||
| 46 | #define SYSMEM_BANKS_MAX 5 | ||
| 47 | 45 | ||
| 48 | #define MEMORY_TYPE_CONVENTIONAL 0x1000 | 46 | #define MEMORY_TYPE_CONVENTIONAL 0x1000 |
| 49 | #define MEMORY_TYPE_NONE 0x2000 | 47 | #define MEMORY_TYPE_NONE 0x2000 |
| 50 | 48 | ||
| 51 | typedef struct sysmem_info { | ||
| 52 | int nr_banks; | ||
| 53 | meminfo_t bank[SYSMEM_BANKS_MAX]; | ||
| 54 | } sysmem_info_t; | ||
| 55 | |||
| 56 | extern sysmem_info_t sysmem; | ||
| 57 | |||
| 58 | #endif | 49 | #endif |
| 59 | #endif | 50 | #endif |
diff --git a/arch/xtensa/include/asm/fixmap.h b/arch/xtensa/include/asm/fixmap.h new file mode 100644 index 000000000000..9f6c33d0428a --- /dev/null +++ b/arch/xtensa/include/asm/fixmap.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* | ||
| 2 | * fixmap.h: compile-time virtual memory allocation | ||
| 3 | * | ||
| 4 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 5 | * License. See the file "COPYING" in the main directory of this archive | ||
| 6 | * for more details. | ||
| 7 | * | ||
| 8 | * Copyright (C) 1998 Ingo Molnar | ||
| 9 | * | ||
| 10 | * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 | ||
| 11 | */ | ||
| 12 | |||
| 13 | #ifndef _ASM_FIXMAP_H | ||
| 14 | #define _ASM_FIXMAP_H | ||
| 15 | |||
| 16 | #include <asm/pgtable.h> | ||
| 17 | #ifdef CONFIG_HIGHMEM | ||
| 18 | #include <linux/threads.h> | ||
| 19 | #include <asm/kmap_types.h> | ||
| 20 | #endif | ||
| 21 | |||
| 22 | /* | ||
| 23 | * Here we define all the compile-time 'special' virtual | ||
| 24 | * addresses. The point is to have a constant address at | ||
| 25 | * compile time, but to set the physical address only | ||
| 26 | * in the boot process. We allocate these special addresses | ||
| 27 | * from the end of the consistent memory region backwards. | ||
| 28 | * Also this lets us do fail-safe vmalloc(), we | ||
| 29 | * can guarantee that these special addresses and | ||
| 30 | * vmalloc()-ed addresses never overlap. | ||
| 31 | * | ||
| 32 | * these 'compile-time allocated' memory buffers are | ||
| 33 | * fixed-size 4k pages. (or larger if used with an increment | ||
| 34 | * higher than 1) use fixmap_set(idx,phys) to associate | ||
| 35 | * physical memory with fixmap indices. | ||
| 36 | */ | ||
| 37 | enum fixed_addresses { | ||
| 38 | #ifdef CONFIG_HIGHMEM | ||
| 39 | /* reserved pte's for temporary kernel mappings */ | ||
| 40 | FIX_KMAP_BEGIN, | ||
| 41 | FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS) - 1, | ||
| 42 | #endif | ||
| 43 | __end_of_fixed_addresses | ||
| 44 | }; | ||
| 45 | |||
| 46 | #define FIXADDR_TOP (VMALLOC_START - PAGE_SIZE) | ||
| 47 | #define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) | ||
| 48 | #define FIXADDR_START ((FIXADDR_TOP - FIXADDR_SIZE) & PMD_MASK) | ||
| 49 | |||
| 50 | #include <asm-generic/fixmap.h> | ||
| 51 | |||
| 52 | #define kmap_get_fixmap_pte(vaddr) \ | ||
| 53 | pte_offset_kernel( \ | ||
| 54 | pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), \ | ||
| 55 | (vaddr) \ | ||
| 56 | ) | ||
| 57 | |||
| 58 | #endif | ||
diff --git a/arch/xtensa/include/asm/highmem.h b/arch/xtensa/include/asm/highmem.h index 80be15124697..2653ef5d55f1 100644 --- a/arch/xtensa/include/asm/highmem.h +++ b/arch/xtensa/include/asm/highmem.h | |||
| @@ -6,11 +6,54 @@ | |||
| 6 | * this archive for more details. | 6 | * this archive for more details. |
| 7 | * | 7 | * |
| 8 | * Copyright (C) 2003 - 2005 Tensilica Inc. | 8 | * Copyright (C) 2003 - 2005 Tensilica Inc. |
| 9 | * Copyright (C) 2014 Cadence Design Systems Inc. | ||
| 9 | */ | 10 | */ |
| 10 | 11 | ||
| 11 | #ifndef _XTENSA_HIGHMEM_H | 12 | #ifndef _XTENSA_HIGHMEM_H |
| 12 | #define _XTENSA_HIGHMEM_H | 13 | #define _XTENSA_HIGHMEM_H |
| 13 | 14 | ||
| 14 | extern void flush_cache_kmaps(void); | 15 | #include <asm/cacheflush.h> |
| 16 | #include <asm/fixmap.h> | ||
| 17 | #include <asm/kmap_types.h> | ||
| 18 | #include <asm/pgtable.h> | ||
| 19 | |||
| 20 | #define PKMAP_BASE (FIXADDR_START - PMD_SIZE) | ||
| 21 | #define LAST_PKMAP PTRS_PER_PTE | ||
| 22 | #define LAST_PKMAP_MASK (LAST_PKMAP - 1) | ||
| 23 | #define PKMAP_NR(virt) (((virt) - PKMAP_BASE) >> PAGE_SHIFT) | ||
| 24 | #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) | ||
| 25 | |||
| 26 | #define kmap_prot PAGE_KERNEL | ||
| 27 | |||
| 28 | extern pte_t *pkmap_page_table; | ||
| 29 | |||
| 30 | void *kmap_high(struct page *page); | ||
| 31 | void kunmap_high(struct page *page); | ||
| 32 | |||
| 33 | static inline void *kmap(struct page *page) | ||
| 34 | { | ||
| 35 | BUG_ON(in_interrupt()); | ||
| 36 | if (!PageHighMem(page)) | ||
| 37 | return page_address(page); | ||
| 38 | return kmap_high(page); | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline void kunmap(struct page *page) | ||
| 42 | { | ||
| 43 | BUG_ON(in_interrupt()); | ||
| 44 | if (!PageHighMem(page)) | ||
| 45 | return; | ||
| 46 | kunmap_high(page); | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline void flush_cache_kmaps(void) | ||
| 50 | { | ||
| 51 | flush_cache_all(); | ||
| 52 | } | ||
| 53 | |||
| 54 | void *kmap_atomic(struct page *page); | ||
| 55 | void __kunmap_atomic(void *kvaddr); | ||
| 56 | |||
| 57 | void kmap_init(void); | ||
| 15 | 58 | ||
| 16 | #endif | 59 | #endif |
diff --git a/arch/xtensa/include/asm/pgtable.h b/arch/xtensa/include/asm/pgtable.h index 216446295ada..4b0ca35a93b1 100644 --- a/arch/xtensa/include/asm/pgtable.h +++ b/arch/xtensa/include/asm/pgtable.h | |||
| @@ -310,6 +310,10 @@ set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval) | |||
| 310 | update_pte(ptep, pteval); | 310 | update_pte(ptep, pteval); |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | static inline void set_pte(pte_t *ptep, pte_t pteval) | ||
| 314 | { | ||
| 315 | update_pte(ptep, pteval); | ||
| 316 | } | ||
| 313 | 317 | ||
| 314 | static inline void | 318 | static inline void |
| 315 | set_pmd(pmd_t *pmdp, pmd_t pmdval) | 319 | set_pmd(pmd_t *pmdp, pmd_t pmdval) |
diff --git a/arch/xtensa/include/asm/sysmem.h b/arch/xtensa/include/asm/sysmem.h new file mode 100644 index 000000000000..c015c5c8e3f7 --- /dev/null +++ b/arch/xtensa/include/asm/sysmem.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | /* | ||
| 2 | * sysmem-related prototypes. | ||
| 3 | * | ||
| 4 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 5 | * License. See the file "COPYING" in the main directory of this archive | ||
| 6 | * for more details. | ||
| 7 | * | ||
| 8 | * Copyright (C) 2014 Cadence Design Systems Inc. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef _XTENSA_SYSMEM_H | ||
| 12 | #define _XTENSA_SYSMEM_H | ||
| 13 | |||
| 14 | #define SYSMEM_BANKS_MAX 31 | ||
| 15 | |||
| 16 | struct meminfo { | ||
| 17 | unsigned long start; | ||
| 18 | unsigned long end; | ||
| 19 | }; | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Bank array is sorted by .start. | ||
| 23 | * Banks don't overlap and there's at least one page gap | ||
| 24 | * between adjacent bank entries. | ||
| 25 | */ | ||
| 26 | struct sysmem_info { | ||
| 27 | int nr_banks; | ||
| 28 | struct meminfo bank[SYSMEM_BANKS_MAX]; | ||
| 29 | }; | ||
| 30 | |||
| 31 | extern struct sysmem_info sysmem; | ||
| 32 | |||
| 33 | int add_sysmem_bank(unsigned long start, unsigned long end); | ||
| 34 | int mem_reserve(unsigned long, unsigned long, int); | ||
| 35 | void bootmem_init(void); | ||
| 36 | void zones_init(void); | ||
| 37 | |||
| 38 | #endif /* _XTENSA_SYSMEM_H */ | ||
diff --git a/arch/xtensa/include/asm/tlbflush.h b/arch/xtensa/include/asm/tlbflush.h index fc34274ce41b..06875feb27c2 100644 --- a/arch/xtensa/include/asm/tlbflush.h +++ b/arch/xtensa/include/asm/tlbflush.h | |||
| @@ -36,6 +36,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, | |||
| 36 | unsigned long page); | 36 | unsigned long page); |
| 37 | void local_flush_tlb_range(struct vm_area_struct *vma, | 37 | void local_flush_tlb_range(struct vm_area_struct *vma, |
| 38 | unsigned long start, unsigned long end); | 38 | unsigned long start, unsigned long end); |
| 39 | void local_flush_tlb_kernel_range(unsigned long start, unsigned long end); | ||
| 39 | 40 | ||
| 40 | #ifdef CONFIG_SMP | 41 | #ifdef CONFIG_SMP |
| 41 | 42 | ||
| @@ -44,12 +45,7 @@ void flush_tlb_mm(struct mm_struct *); | |||
| 44 | void flush_tlb_page(struct vm_area_struct *, unsigned long); | 45 | void flush_tlb_page(struct vm_area_struct *, unsigned long); |
| 45 | void flush_tlb_range(struct vm_area_struct *, unsigned long, | 46 | void flush_tlb_range(struct vm_area_struct *, unsigned long, |
| 46 | unsigned long); | 47 | unsigned long); |
| 47 | 48 | void flush_tlb_kernel_range(unsigned long start, unsigned long end); | |
| 48 | static inline void flush_tlb_kernel_range(unsigned long start, | ||
| 49 | unsigned long end) | ||
| 50 | { | ||
| 51 | flush_tlb_all(); | ||
| 52 | } | ||
| 53 | 49 | ||
| 54 | #else /* !CONFIG_SMP */ | 50 | #else /* !CONFIG_SMP */ |
| 55 | 51 | ||
| @@ -58,7 +54,8 @@ static inline void flush_tlb_kernel_range(unsigned long start, | |||
| 58 | #define flush_tlb_page(vma, page) local_flush_tlb_page(vma, page) | 54 | #define flush_tlb_page(vma, page) local_flush_tlb_page(vma, page) |
| 59 | #define flush_tlb_range(vma, vmaddr, end) local_flush_tlb_range(vma, vmaddr, \ | 55 | #define flush_tlb_range(vma, vmaddr, end) local_flush_tlb_range(vma, vmaddr, \ |
| 60 | end) | 56 | end) |
| 61 | #define flush_tlb_kernel_range(start, end) local_flush_tlb_all() | 57 | #define flush_tlb_kernel_range(start, end) local_flush_tlb_kernel_range(start, \ |
| 58 | end) | ||
| 62 | 59 | ||
| 63 | #endif /* CONFIG_SMP */ | 60 | #endif /* CONFIG_SMP */ |
| 64 | 61 | ||
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index 84fe931bb60e..9757bb74e532 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #include <asm/param.h> | 50 | #include <asm/param.h> |
| 51 | #include <asm/traps.h> | 51 | #include <asm/traps.h> |
| 52 | #include <asm/smp.h> | 52 | #include <asm/smp.h> |
| 53 | #include <asm/sysmem.h> | ||
| 53 | 54 | ||
| 54 | #include <platform/hardware.h> | 55 | #include <platform/hardware.h> |
| 55 | 56 | ||
| @@ -88,12 +89,6 @@ static char __initdata command_line[COMMAND_LINE_SIZE]; | |||
| 88 | static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; | 89 | static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; |
| 89 | #endif | 90 | #endif |
| 90 | 91 | ||
| 91 | sysmem_info_t __initdata sysmem; | ||
| 92 | |||
| 93 | extern int mem_reserve(unsigned long, unsigned long, int); | ||
| 94 | extern void bootmem_init(void); | ||
| 95 | extern void zones_init(void); | ||
| 96 | |||
| 97 | /* | 92 | /* |
| 98 | * Boot parameter parsing. | 93 | * Boot parameter parsing. |
| 99 | * | 94 | * |
| @@ -113,31 +108,14 @@ typedef struct tagtable { | |||
| 113 | 108 | ||
| 114 | /* parse current tag */ | 109 | /* parse current tag */ |
| 115 | 110 | ||
| 116 | static int __init add_sysmem_bank(unsigned long type, unsigned long start, | ||
| 117 | unsigned long end) | ||
| 118 | { | ||
| 119 | if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) { | ||
| 120 | printk(KERN_WARNING | ||
| 121 | "Ignoring memory bank 0x%08lx size %ldKB\n", | ||
| 122 | start, end - start); | ||
| 123 | return -EINVAL; | ||
| 124 | } | ||
| 125 | sysmem.bank[sysmem.nr_banks].type = type; | ||
| 126 | sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(start); | ||
| 127 | sysmem.bank[sysmem.nr_banks].end = end & PAGE_MASK; | ||
| 128 | sysmem.nr_banks++; | ||
| 129 | |||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | static int __init parse_tag_mem(const bp_tag_t *tag) | 111 | static int __init parse_tag_mem(const bp_tag_t *tag) |
| 134 | { | 112 | { |
| 135 | meminfo_t *mi = (meminfo_t *)(tag->data); | 113 | struct bp_meminfo *mi = (struct bp_meminfo *)(tag->data); |
| 136 | 114 | ||
| 137 | if (mi->type != MEMORY_TYPE_CONVENTIONAL) | 115 | if (mi->type != MEMORY_TYPE_CONVENTIONAL) |
| 138 | return -1; | 116 | return -1; |
| 139 | 117 | ||
| 140 | return add_sysmem_bank(mi->type, mi->start, mi->end); | 118 | return add_sysmem_bank(mi->start, mi->end); |
| 141 | } | 119 | } |
| 142 | 120 | ||
| 143 | __tagtable(BP_TAG_MEMORY, parse_tag_mem); | 121 | __tagtable(BP_TAG_MEMORY, parse_tag_mem); |
| @@ -146,8 +124,8 @@ __tagtable(BP_TAG_MEMORY, parse_tag_mem); | |||
| 146 | 124 | ||
| 147 | static int __init parse_tag_initrd(const bp_tag_t* tag) | 125 | static int __init parse_tag_initrd(const bp_tag_t* tag) |
| 148 | { | 126 | { |
| 149 | meminfo_t* mi; | 127 | struct bp_meminfo *mi = (struct bp_meminfo *)(tag->data); |
| 150 | mi = (meminfo_t*)(tag->data); | 128 | |
| 151 | initrd_start = (unsigned long)__va(mi->start); | 129 | initrd_start = (unsigned long)__va(mi->start); |
| 152 | initrd_end = (unsigned long)__va(mi->end); | 130 | initrd_end = (unsigned long)__va(mi->end); |
| 153 | 131 | ||
| @@ -255,7 +233,7 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) | |||
| 255 | return; | 233 | return; |
| 256 | 234 | ||
| 257 | size &= PAGE_MASK; | 235 | size &= PAGE_MASK; |
| 258 | add_sysmem_bank(MEMORY_TYPE_CONVENTIONAL, base, base + size); | 236 | add_sysmem_bank(base, base + size); |
| 259 | } | 237 | } |
| 260 | 238 | ||
| 261 | void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) | 239 | void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) |
| @@ -292,8 +270,6 @@ device_initcall(xtensa_device_probe); | |||
| 292 | 270 | ||
| 293 | void __init init_arch(bp_tag_t *bp_start) | 271 | void __init init_arch(bp_tag_t *bp_start) |
| 294 | { | 272 | { |
| 295 | sysmem.nr_banks = 0; | ||
| 296 | |||
| 297 | /* Parse boot parameters */ | 273 | /* Parse boot parameters */ |
| 298 | 274 | ||
| 299 | if (bp_start) | 275 | if (bp_start) |
| @@ -304,10 +280,9 @@ void __init init_arch(bp_tag_t *bp_start) | |||
| 304 | #endif | 280 | #endif |
| 305 | 281 | ||
| 306 | if (sysmem.nr_banks == 0) { | 282 | if (sysmem.nr_banks == 0) { |
| 307 | sysmem.nr_banks = 1; | 283 | add_sysmem_bank(PLATFORM_DEFAULT_MEM_START, |
| 308 | sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START; | 284 | PLATFORM_DEFAULT_MEM_START + |
| 309 | sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START | 285 | PLATFORM_DEFAULT_MEM_SIZE); |
| 310 | + PLATFORM_DEFAULT_MEM_SIZE; | ||
| 311 | } | 286 | } |
| 312 | 287 | ||
| 313 | #ifdef CONFIG_CMDLINE_BOOL | 288 | #ifdef CONFIG_CMDLINE_BOOL |
| @@ -487,7 +462,7 @@ void __init setup_arch(char **cmdline_p) | |||
| 487 | #ifdef CONFIG_BLK_DEV_INITRD | 462 | #ifdef CONFIG_BLK_DEV_INITRD |
| 488 | if (initrd_start < initrd_end) { | 463 | if (initrd_start < initrd_end) { |
| 489 | initrd_is_mapped = mem_reserve(__pa(initrd_start), | 464 | initrd_is_mapped = mem_reserve(__pa(initrd_start), |
| 490 | __pa(initrd_end), 0); | 465 | __pa(initrd_end), 0) == 0; |
| 491 | initrd_below_start_ok = 1; | 466 | initrd_below_start_ok = 1; |
| 492 | } else { | 467 | } else { |
| 493 | initrd_start = 0; | 468 | initrd_start = 0; |
| @@ -532,6 +507,7 @@ void __init setup_arch(char **cmdline_p) | |||
| 532 | __pa(&_Level6InterruptVector_text_end), 0); | 507 | __pa(&_Level6InterruptVector_text_end), 0); |
| 533 | #endif | 508 | #endif |
| 534 | 509 | ||
| 510 | parse_early_param(); | ||
| 535 | bootmem_init(); | 511 | bootmem_init(); |
| 536 | 512 | ||
| 537 | unflatten_and_copy_device_tree(); | 513 | unflatten_and_copy_device_tree(); |
diff --git a/arch/xtensa/kernel/smp.c b/arch/xtensa/kernel/smp.c index aa8bd8717927..40b5a3771fb0 100644 --- a/arch/xtensa/kernel/smp.c +++ b/arch/xtensa/kernel/smp.c | |||
| @@ -496,6 +496,21 @@ void flush_tlb_range(struct vm_area_struct *vma, | |||
| 496 | on_each_cpu(ipi_flush_tlb_range, &fd, 1); | 496 | on_each_cpu(ipi_flush_tlb_range, &fd, 1); |
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | static void ipi_flush_tlb_kernel_range(void *arg) | ||
| 500 | { | ||
| 501 | struct flush_data *fd = arg; | ||
| 502 | local_flush_tlb_kernel_range(fd->addr1, fd->addr2); | ||
| 503 | } | ||
| 504 | |||
| 505 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) | ||
| 506 | { | ||
| 507 | struct flush_data fd = { | ||
| 508 | .addr1 = start, | ||
| 509 | .addr2 = end, | ||
| 510 | }; | ||
| 511 | on_each_cpu(ipi_flush_tlb_kernel_range, &fd, 1); | ||
| 512 | } | ||
| 513 | |||
| 499 | /* Cache flush functions */ | 514 | /* Cache flush functions */ |
| 500 | 515 | ||
| 501 | static void ipi_flush_cache_all(void *arg) | 516 | static void ipi_flush_cache_all(void *arg) |
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index 80b33ed51f31..4d2872fd9bb5 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/in6.h> | 20 | #include <linux/in6.h> |
| 21 | 21 | ||
| 22 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
| 23 | #include <asm/cacheflush.h> | ||
| 23 | #include <asm/checksum.h> | 24 | #include <asm/checksum.h> |
| 24 | #include <asm/dma.h> | 25 | #include <asm/dma.h> |
| 25 | #include <asm/io.h> | 26 | #include <asm/io.h> |
| @@ -105,6 +106,7 @@ EXPORT_SYMBOL(csum_partial_copy_generic); | |||
| 105 | * Architecture-specific symbols | 106 | * Architecture-specific symbols |
| 106 | */ | 107 | */ |
| 107 | EXPORT_SYMBOL(__xtensa_copy_user); | 108 | EXPORT_SYMBOL(__xtensa_copy_user); |
| 109 | EXPORT_SYMBOL(__invalidate_icache_range); | ||
| 108 | 110 | ||
| 109 | /* | 111 | /* |
| 110 | * Kernel hacking ... | 112 | * Kernel hacking ... |
| @@ -127,3 +129,8 @@ EXPORT_SYMBOL(common_exception_return); | |||
| 127 | #ifdef CONFIG_FUNCTION_TRACER | 129 | #ifdef CONFIG_FUNCTION_TRACER |
| 128 | EXPORT_SYMBOL(_mcount); | 130 | EXPORT_SYMBOL(_mcount); |
| 129 | #endif | 131 | #endif |
| 132 | |||
| 133 | EXPORT_SYMBOL(__invalidate_dcache_range); | ||
| 134 | #if XCHAL_DCACHE_IS_WRITEBACK | ||
| 135 | EXPORT_SYMBOL(__flush_dcache_range); | ||
| 136 | #endif | ||
diff --git a/arch/xtensa/mm/Makefile b/arch/xtensa/mm/Makefile index f0b646d2f843..f54f78e24d7b 100644 --- a/arch/xtensa/mm/Makefile +++ b/arch/xtensa/mm/Makefile | |||
| @@ -4,3 +4,4 @@ | |||
| 4 | 4 | ||
| 5 | obj-y := init.o cache.o misc.o | 5 | obj-y := init.o cache.o misc.o |
| 6 | obj-$(CONFIG_MMU) += fault.o mmu.o tlb.o | 6 | obj-$(CONFIG_MMU) += fault.o mmu.o tlb.o |
| 7 | obj-$(CONFIG_HIGHMEM) += highmem.o | ||
diff --git a/arch/xtensa/mm/cache.c b/arch/xtensa/mm/cache.c index ba4c47f291b1..63cbb867dadd 100644 --- a/arch/xtensa/mm/cache.c +++ b/arch/xtensa/mm/cache.c | |||
| @@ -59,6 +59,10 @@ | |||
| 59 | * | 59 | * |
| 60 | */ | 60 | */ |
| 61 | 61 | ||
| 62 | #if (DCACHE_WAY_SIZE > PAGE_SIZE) && defined(CONFIG_HIGHMEM) | ||
| 63 | #error "HIGHMEM is not supported on cores with aliasing cache." | ||
| 64 | #endif | ||
| 65 | |||
| 62 | #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK | 66 | #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK |
| 63 | 67 | ||
| 64 | /* | 68 | /* |
| @@ -179,10 +183,11 @@ update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep) | |||
| 179 | #else | 183 | #else |
| 180 | if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags) | 184 | if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags) |
| 181 | && (vma->vm_flags & VM_EXEC) != 0) { | 185 | && (vma->vm_flags & VM_EXEC) != 0) { |
| 182 | unsigned long paddr = (unsigned long) page_address(page); | 186 | unsigned long paddr = (unsigned long)kmap_atomic(page); |
| 183 | __flush_dcache_page(paddr); | 187 | __flush_dcache_page(paddr); |
| 184 | __invalidate_icache_page(paddr); | 188 | __invalidate_icache_page(paddr); |
| 185 | set_bit(PG_arch_1, &page->flags); | 189 | set_bit(PG_arch_1, &page->flags); |
| 190 | kunmap_atomic((void *)paddr); | ||
| 186 | } | 191 | } |
| 187 | #endif | 192 | #endif |
| 188 | } | 193 | } |
diff --git a/arch/xtensa/mm/highmem.c b/arch/xtensa/mm/highmem.c new file mode 100644 index 000000000000..17a8c0d6fd17 --- /dev/null +++ b/arch/xtensa/mm/highmem.c | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | /* | ||
| 2 | * High memory support for Xtensa architecture | ||
| 3 | * | ||
| 4 | * This file is subject to the terms and conditions of the GNU General | ||
| 5 | * Public License. See the file "COPYING" in the main directory of | ||
| 6 | * this archive for more details. | ||
| 7 | * | ||
| 8 | * Copyright (C) 2014 Cadence Design Systems Inc. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/export.h> | ||
| 12 | #include <linux/highmem.h> | ||
| 13 | #include <asm/tlbflush.h> | ||
| 14 | |||
| 15 | static pte_t *kmap_pte; | ||
| 16 | |||
| 17 | void *kmap_atomic(struct page *page) | ||
| 18 | { | ||
| 19 | enum fixed_addresses idx; | ||
| 20 | unsigned long vaddr; | ||
| 21 | int type; | ||
| 22 | |||
| 23 | pagefault_disable(); | ||
| 24 | if (!PageHighMem(page)) | ||
| 25 | return page_address(page); | ||
| 26 | |||
| 27 | type = kmap_atomic_idx_push(); | ||
| 28 | idx = type + KM_TYPE_NR * smp_processor_id(); | ||
| 29 | vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); | ||
| 30 | #ifdef CONFIG_DEBUG_HIGHMEM | ||
| 31 | BUG_ON(!pte_none(*(kmap_pte - idx))); | ||
| 32 | #endif | ||
| 33 | set_pte(kmap_pte - idx, mk_pte(page, PAGE_KERNEL_EXEC)); | ||
| 34 | |||
| 35 | return (void *)vaddr; | ||
| 36 | } | ||
| 37 | EXPORT_SYMBOL(kmap_atomic); | ||
| 38 | |||
| 39 | void __kunmap_atomic(void *kvaddr) | ||
| 40 | { | ||
| 41 | int idx, type; | ||
| 42 | |||
| 43 | if (kvaddr >= (void *)FIXADDR_START && | ||
| 44 | kvaddr < (void *)FIXADDR_TOP) { | ||
| 45 | type = kmap_atomic_idx(); | ||
| 46 | idx = type + KM_TYPE_NR * smp_processor_id(); | ||
| 47 | |||
| 48 | /* | ||
| 49 | * Force other mappings to Oops if they'll try to access this | ||
| 50 | * pte without first remap it. Keeping stale mappings around | ||
| 51 | * is a bad idea also, in case the page changes cacheability | ||
| 52 | * attributes or becomes a protected page in a hypervisor. | ||
| 53 | */ | ||
| 54 | pte_clear(&init_mm, kvaddr, kmap_pte - idx); | ||
| 55 | local_flush_tlb_kernel_range((unsigned long)kvaddr, | ||
| 56 | (unsigned long)kvaddr + PAGE_SIZE); | ||
| 57 | |||
| 58 | kmap_atomic_idx_pop(); | ||
| 59 | } | ||
| 60 | |||
| 61 | pagefault_enable(); | ||
| 62 | } | ||
| 63 | EXPORT_SYMBOL(__kunmap_atomic); | ||
| 64 | |||
| 65 | void __init kmap_init(void) | ||
| 66 | { | ||
| 67 | unsigned long kmap_vstart; | ||
| 68 | |||
| 69 | /* cache the first kmap pte */ | ||
| 70 | kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); | ||
| 71 | kmap_pte = kmap_get_fixmap_pte(kmap_vstart); | ||
| 72 | } | ||
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c index aff108df92d3..4224256bb215 100644 --- a/arch/xtensa/mm/init.c +++ b/arch/xtensa/mm/init.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | * for more details. | 8 | * for more details. |
| 9 | * | 9 | * |
| 10 | * Copyright (C) 2001 - 2005 Tensilica Inc. | 10 | * Copyright (C) 2001 - 2005 Tensilica Inc. |
| 11 | * Copyright (C) 2014 Cadence Design Systems Inc. | ||
| 11 | * | 12 | * |
| 12 | * Chris Zankel <chris@zankel.net> | 13 | * Chris Zankel <chris@zankel.net> |
| 13 | * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> | 14 | * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> |
| @@ -19,6 +20,7 @@ | |||
| 19 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
| 20 | #include <linux/bootmem.h> | 21 | #include <linux/bootmem.h> |
| 21 | #include <linux/gfp.h> | 22 | #include <linux/gfp.h> |
| 23 | #include <linux/highmem.h> | ||
| 22 | #include <linux/swap.h> | 24 | #include <linux/swap.h> |
| 23 | #include <linux/mman.h> | 25 | #include <linux/mman.h> |
| 24 | #include <linux/nodemask.h> | 26 | #include <linux/nodemask.h> |
| @@ -27,11 +29,133 @@ | |||
| 27 | #include <asm/bootparam.h> | 29 | #include <asm/bootparam.h> |
| 28 | #include <asm/page.h> | 30 | #include <asm/page.h> |
| 29 | #include <asm/sections.h> | 31 | #include <asm/sections.h> |
| 32 | #include <asm/sysmem.h> | ||
| 33 | |||
| 34 | struct sysmem_info sysmem __initdata; | ||
| 35 | |||
| 36 | static void __init sysmem_dump(void) | ||
| 37 | { | ||
| 38 | unsigned i; | ||
| 39 | |||
| 40 | pr_debug("Sysmem:\n"); | ||
| 41 | for (i = 0; i < sysmem.nr_banks; ++i) | ||
| 42 | pr_debug(" 0x%08lx - 0x%08lx (%ldK)\n", | ||
| 43 | sysmem.bank[i].start, sysmem.bank[i].end, | ||
| 44 | (sysmem.bank[i].end - sysmem.bank[i].start) >> 10); | ||
| 45 | } | ||
| 46 | |||
| 47 | /* | ||
| 48 | * Find bank with maximal .start such that bank.start <= start | ||
| 49 | */ | ||
| 50 | static inline struct meminfo * __init find_bank(unsigned long start) | ||
| 51 | { | ||
| 52 | unsigned i; | ||
| 53 | struct meminfo *it = NULL; | ||
| 54 | |||
| 55 | for (i = 0; i < sysmem.nr_banks; ++i) | ||
| 56 | if (sysmem.bank[i].start <= start) | ||
| 57 | it = sysmem.bank + i; | ||
| 58 | else | ||
| 59 | break; | ||
| 60 | return it; | ||
| 61 | } | ||
| 62 | |||
| 63 | /* | ||
| 64 | * Move all memory banks starting at 'from' to a new place at 'to', | ||
| 65 | * adjust nr_banks accordingly. | ||
| 66 | * Both 'from' and 'to' must be inside the sysmem.bank. | ||
| 67 | * | ||
| 68 | * Returns: 0 (success), -ENOMEM (not enough space in the sysmem.bank). | ||
| 69 | */ | ||
| 70 | static int __init move_banks(struct meminfo *to, struct meminfo *from) | ||
| 71 | { | ||
| 72 | unsigned n = sysmem.nr_banks - (from - sysmem.bank); | ||
| 73 | |||
| 74 | if (to > from && to - from + sysmem.nr_banks > SYSMEM_BANKS_MAX) | ||
| 75 | return -ENOMEM; | ||
| 76 | if (to != from) | ||
| 77 | memmove(to, from, n * sizeof(struct meminfo)); | ||
| 78 | sysmem.nr_banks += to - from; | ||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | /* | ||
| 83 | * Add new bank to sysmem. Resulting sysmem is the union of bytes of the | ||
| 84 | * original sysmem and the new bank. | ||
| 85 | * | ||
| 86 | * Returns: 0 (success), < 0 (error) | ||
| 87 | */ | ||
| 88 | int __init add_sysmem_bank(unsigned long start, unsigned long end) | ||
| 89 | { | ||
| 90 | unsigned i; | ||
| 91 | struct meminfo *it = NULL; | ||
| 92 | unsigned long sz; | ||
| 93 | unsigned long bank_sz = 0; | ||
| 94 | |||
| 95 | if (start == end || | ||
| 96 | (start < end) != (PAGE_ALIGN(start) < (end & PAGE_MASK))) { | ||
| 97 | pr_warn("Ignoring small memory bank 0x%08lx size: %ld bytes\n", | ||
| 98 | start, end - start); | ||
| 99 | return -EINVAL; | ||
| 100 | } | ||
| 101 | |||
| 102 | start = PAGE_ALIGN(start); | ||
| 103 | end &= PAGE_MASK; | ||
| 104 | sz = end - start; | ||
| 105 | |||
| 106 | it = find_bank(start); | ||
| 107 | |||
| 108 | if (it) | ||
| 109 | bank_sz = it->end - it->start; | ||
| 110 | |||
| 111 | if (it && bank_sz >= start - it->start) { | ||
| 112 | if (end - it->start > bank_sz) | ||
| 113 | it->end = end; | ||
| 114 | else | ||
| 115 | return 0; | ||
| 116 | } else { | ||
| 117 | if (!it) | ||
| 118 | it = sysmem.bank; | ||
| 119 | else | ||
| 120 | ++it; | ||
| 121 | |||
| 122 | if (it - sysmem.bank < sysmem.nr_banks && | ||
| 123 | it->start - start <= sz) { | ||
| 124 | it->start = start; | ||
| 125 | if (it->end - it->start < sz) | ||
| 126 | it->end = end; | ||
| 127 | else | ||
| 128 | return 0; | ||
| 129 | } else { | ||
| 130 | if (move_banks(it + 1, it) < 0) { | ||
| 131 | pr_warn("Ignoring memory bank 0x%08lx size %ld bytes\n", | ||
| 132 | start, end - start); | ||
| 133 | return -EINVAL; | ||
| 134 | } | ||
| 135 | it->start = start; | ||
| 136 | it->end = end; | ||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | sz = it->end - it->start; | ||
| 141 | for (i = it + 1 - sysmem.bank; i < sysmem.nr_banks; ++i) | ||
| 142 | if (sysmem.bank[i].start - it->start <= sz) { | ||
| 143 | if (sz < sysmem.bank[i].end - it->start) | ||
| 144 | it->end = sysmem.bank[i].end; | ||
| 145 | } else { | ||
| 146 | break; | ||
| 147 | } | ||
| 148 | |||
| 149 | move_banks(it + 1, sysmem.bank + i); | ||
| 150 | return 0; | ||
| 151 | } | ||
| 30 | 152 | ||
| 31 | /* | 153 | /* |
| 32 | * mem_reserve(start, end, must_exist) | 154 | * mem_reserve(start, end, must_exist) |
| 33 | * | 155 | * |
| 34 | * Reserve some memory from the memory pool. | 156 | * Reserve some memory from the memory pool. |
| 157 | * If must_exist is set and a part of the region being reserved does not exist | ||
| 158 | * memory map is not altered. | ||
| 35 | * | 159 | * |
| 36 | * Parameters: | 160 | * Parameters: |
| 37 | * start Start of region, | 161 | * start Start of region, |
| @@ -39,53 +163,69 @@ | |||
| 39 | * must_exist Must exist in memory pool. | 163 | * must_exist Must exist in memory pool. |
| 40 | * | 164 | * |
| 41 | * Returns: | 165 | * Returns: |
| 42 | * 0 (memory area couldn't be mapped) | 166 | * 0 (success) |
| 43 | * -1 (success) | 167 | * < 0 (error) |
| 44 | */ | 168 | */ |
| 45 | 169 | ||
| 46 | int __init mem_reserve(unsigned long start, unsigned long end, int must_exist) | 170 | int __init mem_reserve(unsigned long start, unsigned long end, int must_exist) |
| 47 | { | 171 | { |
| 48 | int i; | 172 | struct meminfo *it; |
| 49 | 173 | struct meminfo *rm = NULL; | |
| 50 | if (start == end) | 174 | unsigned long sz; |
| 51 | return 0; | 175 | unsigned long bank_sz = 0; |
| 52 | 176 | ||
| 53 | start = start & PAGE_MASK; | 177 | start = start & PAGE_MASK; |
| 54 | end = PAGE_ALIGN(end); | 178 | end = PAGE_ALIGN(end); |
| 179 | sz = end - start; | ||
| 180 | if (!sz) | ||
| 181 | return -EINVAL; | ||
| 55 | 182 | ||
| 56 | for (i = 0; i < sysmem.nr_banks; i++) | 183 | it = find_bank(start); |
| 57 | if (start < sysmem.bank[i].end | 184 | |
| 58 | && end >= sysmem.bank[i].start) | 185 | if (it) |
| 59 | break; | 186 | bank_sz = it->end - it->start; |
| 60 | 187 | ||
| 61 | if (i == sysmem.nr_banks) { | 188 | if ((!it || end - it->start > bank_sz) && must_exist) { |
| 62 | if (must_exist) | 189 | pr_warn("mem_reserve: [0x%0lx, 0x%0lx) not in any region!\n", |
| 63 | printk (KERN_WARNING "mem_reserve: [0x%0lx, 0x%0lx) " | 190 | start, end); |
| 64 | "not in any region!\n", start, end); | 191 | return -EINVAL; |
| 65 | return 0; | ||
| 66 | } | 192 | } |
| 67 | 193 | ||
| 68 | if (start > sysmem.bank[i].start) { | 194 | if (it && start - it->start < bank_sz) { |
| 69 | if (end < sysmem.bank[i].end) { | 195 | if (start == it->start) { |
| 70 | /* split entry */ | 196 | if (end - it->start < bank_sz) { |
| 71 | if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) | 197 | it->start = end; |
| 72 | panic("meminfo overflow\n"); | 198 | return 0; |
| 73 | sysmem.bank[sysmem.nr_banks].start = end; | 199 | } else { |
| 74 | sysmem.bank[sysmem.nr_banks].end = sysmem.bank[i].end; | 200 | rm = it; |
| 75 | sysmem.nr_banks++; | 201 | } |
| 202 | } else { | ||
| 203 | it->end = start; | ||
| 204 | if (end - it->start < bank_sz) | ||
| 205 | return add_sysmem_bank(end, | ||
| 206 | it->start + bank_sz); | ||
| 207 | ++it; | ||
| 76 | } | 208 | } |
| 77 | sysmem.bank[i].end = start; | 209 | } |
| 78 | 210 | ||
| 79 | } else if (end < sysmem.bank[i].end) { | 211 | if (!it) |
| 80 | sysmem.bank[i].start = end; | 212 | it = sysmem.bank; |
| 81 | 213 | ||
| 82 | } else { | 214 | for (; it < sysmem.bank + sysmem.nr_banks; ++it) { |
| 83 | /* remove entry */ | 215 | if (it->end - start <= sz) { |
| 84 | sysmem.nr_banks--; | 216 | if (!rm) |
| 85 | sysmem.bank[i].start = sysmem.bank[sysmem.nr_banks].start; | 217 | rm = it; |
| 86 | sysmem.bank[i].end = sysmem.bank[sysmem.nr_banks].end; | 218 | } else { |
| 219 | if (it->start - start < sz) | ||
| 220 | it->start = end; | ||
| 221 | break; | ||
| 222 | } | ||
| 87 | } | 223 | } |
| 88 | return -1; | 224 | |
| 225 | if (rm) | ||
| 226 | move_banks(rm, it); | ||
| 227 | |||
| 228 | return 0; | ||
| 89 | } | 229 | } |
| 90 | 230 | ||
| 91 | 231 | ||
| @@ -99,6 +239,7 @@ void __init bootmem_init(void) | |||
| 99 | unsigned long bootmap_start, bootmap_size; | 239 | unsigned long bootmap_start, bootmap_size; |
| 100 | int i; | 240 | int i; |
| 101 | 241 | ||
| 242 | sysmem_dump(); | ||
| 102 | max_low_pfn = max_pfn = 0; | 243 | max_low_pfn = max_pfn = 0; |
| 103 | min_low_pfn = ~0; | 244 | min_low_pfn = ~0; |
| 104 | 245 | ||
| @@ -156,19 +297,13 @@ void __init bootmem_init(void) | |||
| 156 | 297 | ||
| 157 | void __init zones_init(void) | 298 | void __init zones_init(void) |
| 158 | { | 299 | { |
| 159 | unsigned long zones_size[MAX_NR_ZONES]; | ||
| 160 | int i; | ||
| 161 | |||
| 162 | /* All pages are DMA-able, so we put them all in the DMA zone. */ | 300 | /* All pages are DMA-able, so we put them all in the DMA zone. */ |
| 163 | 301 | unsigned long zones_size[MAX_NR_ZONES] = { | |
| 164 | zones_size[ZONE_DMA] = max_low_pfn - ARCH_PFN_OFFSET; | 302 | [ZONE_DMA] = max_low_pfn - ARCH_PFN_OFFSET, |
| 165 | for (i = 1; i < MAX_NR_ZONES; i++) | ||
| 166 | zones_size[i] = 0; | ||
| 167 | |||
| 168 | #ifdef CONFIG_HIGHMEM | 303 | #ifdef CONFIG_HIGHMEM |
| 169 | zones_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn; | 304 | [ZONE_HIGHMEM] = max_pfn - max_low_pfn, |
| 170 | #endif | 305 | #endif |
| 171 | 306 | }; | |
| 172 | free_area_init_node(0, zones_size, ARCH_PFN_OFFSET, NULL); | 307 | free_area_init_node(0, zones_size, ARCH_PFN_OFFSET, NULL); |
| 173 | } | 308 | } |
| 174 | 309 | ||
| @@ -178,16 +313,38 @@ void __init zones_init(void) | |||
| 178 | 313 | ||
| 179 | void __init mem_init(void) | 314 | void __init mem_init(void) |
| 180 | { | 315 | { |
| 181 | max_mapnr = max_low_pfn - ARCH_PFN_OFFSET; | ||
| 182 | high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT); | ||
| 183 | |||
| 184 | #ifdef CONFIG_HIGHMEM | 316 | #ifdef CONFIG_HIGHMEM |
| 185 | #error HIGHGMEM not implemented in init.c | 317 | unsigned long tmp; |
| 318 | |||
| 319 | reset_all_zones_managed_pages(); | ||
| 320 | for (tmp = max_low_pfn; tmp < max_pfn; tmp++) | ||
| 321 | free_highmem_page(pfn_to_page(tmp)); | ||
| 186 | #endif | 322 | #endif |
| 187 | 323 | ||
| 324 | max_mapnr = max_pfn - ARCH_PFN_OFFSET; | ||
| 325 | high_memory = (void *)__va(max_low_pfn << PAGE_SHIFT); | ||
| 326 | |||
| 188 | free_all_bootmem(); | 327 | free_all_bootmem(); |
| 189 | 328 | ||
| 190 | mem_init_print_info(NULL); | 329 | mem_init_print_info(NULL); |
| 330 | pr_info("virtual kernel memory layout:\n" | ||
| 331 | #ifdef CONFIG_HIGHMEM | ||
| 332 | " pkmap : 0x%08lx - 0x%08lx (%5lu kB)\n" | ||
| 333 | " fixmap : 0x%08lx - 0x%08lx (%5lu kB)\n" | ||
| 334 | #endif | ||
| 335 | " vmalloc : 0x%08x - 0x%08x (%5u MB)\n" | ||
| 336 | " lowmem : 0x%08x - 0x%08lx (%5lu MB)\n", | ||
| 337 | #ifdef CONFIG_HIGHMEM | ||
| 338 | PKMAP_BASE, PKMAP_BASE + LAST_PKMAP * PAGE_SIZE, | ||
| 339 | (LAST_PKMAP*PAGE_SIZE) >> 10, | ||
| 340 | FIXADDR_START, FIXADDR_TOP, | ||
| 341 | (FIXADDR_TOP - FIXADDR_START) >> 10, | ||
| 342 | #endif | ||
| 343 | VMALLOC_START, VMALLOC_END, | ||
| 344 | (VMALLOC_END - VMALLOC_START) >> 20, | ||
| 345 | PAGE_OFFSET, PAGE_OFFSET + | ||
| 346 | (max_low_pfn - min_low_pfn) * PAGE_SIZE, | ||
| 347 | ((max_low_pfn - min_low_pfn) * PAGE_SIZE) >> 20); | ||
| 191 | } | 348 | } |
| 192 | 349 | ||
| 193 | #ifdef CONFIG_BLK_DEV_INITRD | 350 | #ifdef CONFIG_BLK_DEV_INITRD |
| @@ -204,3 +361,53 @@ void free_initmem(void) | |||
| 204 | { | 361 | { |
| 205 | free_initmem_default(-1); | 362 | free_initmem_default(-1); |
| 206 | } | 363 | } |
| 364 | |||
| 365 | static void __init parse_memmap_one(char *p) | ||
| 366 | { | ||
| 367 | char *oldp; | ||
| 368 | unsigned long start_at, mem_size; | ||
| 369 | |||
| 370 | if (!p) | ||
| 371 | return; | ||
| 372 | |||
| 373 | oldp = p; | ||
| 374 | mem_size = memparse(p, &p); | ||
| 375 | if (p == oldp) | ||
| 376 | return; | ||
| 377 | |||
| 378 | switch (*p) { | ||
| 379 | case '@': | ||
| 380 | start_at = memparse(p + 1, &p); | ||
| 381 | add_sysmem_bank(start_at, start_at + mem_size); | ||
| 382 | break; | ||
| 383 | |||
| 384 | case '$': | ||
| 385 | start_at = memparse(p + 1, &p); | ||
| 386 | mem_reserve(start_at, start_at + mem_size, 0); | ||
| 387 | break; | ||
| 388 | |||
| 389 | case 0: | ||
| 390 | mem_reserve(mem_size, 0, 0); | ||
| 391 | break; | ||
| 392 | |||
| 393 | default: | ||
| 394 | pr_warn("Unrecognized memmap syntax: %s\n", p); | ||
| 395 | break; | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | static int __init parse_memmap_opt(char *str) | ||
| 400 | { | ||
| 401 | while (str) { | ||
| 402 | char *k = strchr(str, ','); | ||
| 403 | |||
| 404 | if (k) | ||
| 405 | *k++ = 0; | ||
| 406 | |||
| 407 | parse_memmap_one(str); | ||
| 408 | str = k; | ||
| 409 | } | ||
| 410 | |||
| 411 | return 0; | ||
| 412 | } | ||
| 413 | early_param("memmap", parse_memmap_opt); | ||
diff --git a/arch/xtensa/mm/mmu.c b/arch/xtensa/mm/mmu.c index 861203e958da..3429b483d9f8 100644 --- a/arch/xtensa/mm/mmu.c +++ b/arch/xtensa/mm/mmu.c | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | * | 3 | * |
| 4 | * Extracted from init.c | 4 | * Extracted from init.c |
| 5 | */ | 5 | */ |
| 6 | #include <linux/bootmem.h> | ||
| 6 | #include <linux/percpu.h> | 7 | #include <linux/percpu.h> |
| 7 | #include <linux/init.h> | 8 | #include <linux/init.h> |
| 8 | #include <linux/string.h> | 9 | #include <linux/string.h> |
| @@ -16,9 +17,44 @@ | |||
| 16 | #include <asm/initialize_mmu.h> | 17 | #include <asm/initialize_mmu.h> |
| 17 | #include <asm/io.h> | 18 | #include <asm/io.h> |
| 18 | 19 | ||
| 20 | #if defined(CONFIG_HIGHMEM) | ||
| 21 | static void * __init init_pmd(unsigned long vaddr) | ||
| 22 | { | ||
| 23 | pgd_t *pgd = pgd_offset_k(vaddr); | ||
| 24 | pmd_t *pmd = pmd_offset(pgd, vaddr); | ||
| 25 | |||
| 26 | if (pmd_none(*pmd)) { | ||
| 27 | unsigned i; | ||
| 28 | pte_t *pte = alloc_bootmem_low_pages(PAGE_SIZE); | ||
| 29 | |||
| 30 | for (i = 0; i < 1024; i++) | ||
| 31 | pte_clear(NULL, 0, pte + i); | ||
| 32 | |||
| 33 | set_pmd(pmd, __pmd(((unsigned long)pte) & PAGE_MASK)); | ||
| 34 | BUG_ON(pte != pte_offset_kernel(pmd, 0)); | ||
| 35 | pr_debug("%s: vaddr: 0x%08lx, pmd: 0x%p, pte: 0x%p\n", | ||
| 36 | __func__, vaddr, pmd, pte); | ||
| 37 | return pte; | ||
| 38 | } else { | ||
| 39 | return pte_offset_kernel(pmd, 0); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | static void __init fixedrange_init(void) | ||
| 44 | { | ||
| 45 | BUILD_BUG_ON(FIXADDR_SIZE > PMD_SIZE); | ||
| 46 | init_pmd(__fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK); | ||
| 47 | } | ||
| 48 | #endif | ||
| 49 | |||
| 19 | void __init paging_init(void) | 50 | void __init paging_init(void) |
| 20 | { | 51 | { |
| 21 | memset(swapper_pg_dir, 0, PAGE_SIZE); | 52 | memset(swapper_pg_dir, 0, PAGE_SIZE); |
| 53 | #ifdef CONFIG_HIGHMEM | ||
| 54 | fixedrange_init(); | ||
| 55 | pkmap_page_table = init_pmd(PKMAP_BASE); | ||
| 56 | kmap_init(); | ||
| 57 | #endif | ||
| 22 | } | 58 | } |
| 23 | 59 | ||
| 24 | /* | 60 | /* |
diff --git a/arch/xtensa/mm/tlb.c b/arch/xtensa/mm/tlb.c index ade623826788..5ece856c5725 100644 --- a/arch/xtensa/mm/tlb.c +++ b/arch/xtensa/mm/tlb.c | |||
| @@ -149,6 +149,21 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | |||
| 149 | local_irq_restore(flags); | 149 | local_irq_restore(flags); |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) | ||
| 153 | { | ||
| 154 | if (end > start && start >= TASK_SIZE && end <= PAGE_OFFSET && | ||
| 155 | end - start < _TLB_ENTRIES << PAGE_SHIFT) { | ||
| 156 | start &= PAGE_MASK; | ||
| 157 | while (start < end) { | ||
| 158 | invalidate_itlb_mapping(start); | ||
| 159 | invalidate_dtlb_mapping(start); | ||
| 160 | start += PAGE_SIZE; | ||
| 161 | } | ||
| 162 | } else { | ||
| 163 | local_flush_tlb_all(); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 152 | #ifdef CONFIG_DEBUG_TLB_SANITY | 167 | #ifdef CONFIG_DEBUG_TLB_SANITY |
| 153 | 168 | ||
| 154 | static unsigned get_pte_for_vaddr(unsigned vaddr) | 169 | static unsigned get_pte_for_vaddr(unsigned vaddr) |
diff --git a/arch/xtensa/platforms/iss/Makefile b/arch/xtensa/platforms/iss/Makefile index d2369b799c50..b3e89291cfba 100644 --- a/arch/xtensa/platforms/iss/Makefile +++ b/arch/xtensa/platforms/iss/Makefile | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | # "prom monitor" library routines under Linux. | 4 | # "prom monitor" library routines under Linux. |
| 5 | # | 5 | # |
| 6 | 6 | ||
| 7 | obj-y = console.o setup.o | 7 | obj-y = setup.o |
| 8 | obj-$(CONFIG_TTY) += console.o | ||
| 8 | obj-$(CONFIG_NET) += network.o | 9 | obj-$(CONFIG_NET) += network.o |
| 9 | obj-$(CONFIG_BLK_DEV_SIMDISK) += simdisk.o | 10 | obj-$(CONFIG_BLK_DEV_SIMDISK) += simdisk.o |
diff --git a/arch/xtensa/platforms/xt2000/setup.c b/arch/xtensa/platforms/xt2000/setup.c index f9bc87966290..b90555cb8089 100644 --- a/arch/xtensa/platforms/xt2000/setup.c +++ b/arch/xtensa/platforms/xt2000/setup.c | |||
| @@ -92,18 +92,8 @@ void __init platform_setup(char** cmdline) | |||
| 92 | 92 | ||
| 93 | /* early initialization */ | 93 | /* early initialization */ |
| 94 | 94 | ||
| 95 | extern sysmem_info_t __initdata sysmem; | 95 | void __init platform_init(bp_tag_t *first) |
| 96 | |||
| 97 | void platform_init(bp_tag_t* first) | ||
| 98 | { | 96 | { |
| 99 | /* Set default memory block if not provided by the bootloader. */ | ||
| 100 | |||
| 101 | if (sysmem.nr_banks == 0) { | ||
| 102 | sysmem.nr_banks = 1; | ||
| 103 | sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START; | ||
| 104 | sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START | ||
| 105 | + PLATFORM_DEFAULT_MEM_SIZE; | ||
| 106 | } | ||
| 107 | } | 97 | } |
| 108 | 98 | ||
| 109 | /* Heartbeat. Let the LED blink. */ | 99 | /* Heartbeat. Let the LED blink. */ |
diff --git a/scripts/sortextable.c b/scripts/sortextable.c index cc49062acdee..1052d4834a44 100644 --- a/scripts/sortextable.c +++ b/scripts/sortextable.c | |||
| @@ -35,6 +35,10 @@ | |||
| 35 | #define EM_ARCOMPACT 93 | 35 | #define EM_ARCOMPACT 93 |
| 36 | #endif | 36 | #endif |
| 37 | 37 | ||
| 38 | #ifndef EM_XTENSA | ||
| 39 | #define EM_XTENSA 94 | ||
| 40 | #endif | ||
| 41 | |||
| 38 | #ifndef EM_AARCH64 | 42 | #ifndef EM_AARCH64 |
| 39 | #define EM_AARCH64 183 | 43 | #define EM_AARCH64 183 |
| 40 | #endif | 44 | #endif |
| @@ -281,6 +285,7 @@ do_file(char const *const fname) | |||
| 281 | case EM_AARCH64: | 285 | case EM_AARCH64: |
| 282 | case EM_MICROBLAZE: | 286 | case EM_MICROBLAZE: |
| 283 | case EM_MIPS: | 287 | case EM_MIPS: |
| 288 | case EM_XTENSA: | ||
| 284 | break; | 289 | break; |
| 285 | } /* end switch */ | 290 | } /* end switch */ |
| 286 | 291 | ||
