Commit 03787ff6f9156e43019f3f4b69cb6212b3a47f65

Authored by Linus Torvalds

Merge tag 'xtensa-next-20140503' of git://github.com/czankel/xtensa-linux

Pull Xtensa fixes from Chris Zankel:
 - Fixes allmodconfig, allnoconfig builds
 - Adds highmem support
 - Enables build-time exception table sorting.

* tag 'xtensa-next-20140503' of git://github.com/czankel/xtensa-linux:
  xtensa: ISS: don't depend on CONFIG_TTY
  xtensa: xt2000: drop redundant sysmem initialization
  xtensa: add support for KC705
  xtensa: xtfpga: introduce SoC I/O bus
  xtensa: add HIGHMEM support
  xtensa: optimize local_flush_tlb_kernel_range
  xtensa: dump sysmem from the bootmem_init
  xtensa: handle memmap kernel option
  xtensa: keep sysmem banks ordered in mem_reserve
  xtensa: keep sysmem banks ordered in add_sysmem_bank
  xtensa: split bootparam and kernel meminfo
  xtensa: enable sorting extable at build time
  xtensa: export __{invalidate,flush}_dcache_range
  xtensa: Export __invalidate_icache_range

Showing 24 changed files Side-by-side Diff

... ... @@ -14,6 +14,7 @@
14 14 select GENERIC_PCI_IOMAP
15 15 select ARCH_WANT_IPC_PARSE_VERSION
16 16 select ARCH_WANT_OPTIONAL_GPIOLIB
  17 + select BUILDTIME_EXTABLE_SORT
17 18 select CLONE_BACKWARDS
18 19 select IRQ_DOMAIN
19 20 select HAVE_OPROFILE
... ... @@ -189,6 +190,24 @@
189 190  
190 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 211 endmenu
193 212  
194 213 config XTENSA_CALIBRATE_CCOUNT
... ... @@ -224,7 +243,6 @@
224 243  
225 244 config XTENSA_PLATFORM_ISS
226 245 bool "ISS"
227   - depends on TTY
228 246 select XTENSA_CALIBRATE_CCOUNT
229 247 select SERIAL_CONSOLE
230 248 help
arch/xtensa/boot/dts/kc705.dts
  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 +};
arch/xtensa/boot/dts/xtfpga-flash-128m.dtsi
  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 +};
arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi
1 1 / {
2   - flash: flash@f8000000 {
3   - #address-cells = <1>;
4   - #size-cells = <1>;
5   - compatible = "cfi-flash";
6   - reg = <0xf8000000 0x01000000>;
7   - bank-width = <2>;
8   - device-width = <2>;
9   - partition@0x0 {
10   - label = "boot loader area";
11   - reg = <0x00000000 0x00400000>;
  2 + soc {
  3 + flash: flash@08000000 {
  4 + #address-cells = <1>;
  5 + #size-cells = <1>;
  6 + compatible = "cfi-flash";
  7 + reg = <0x08000000 0x01000000>;
  8 + bank-width = <2>;
  9 + device-width = <2>;
  10 + partition@0x0 {
  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 {
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   - };
  27 + };
26 28 };
arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi
1 1 / {
2   - flash: flash@f8000000 {
3   - #address-cells = <1>;
4   - #size-cells = <1>;
5   - compatible = "cfi-flash";
6   - reg = <0xf8000000 0x00400000>;
7   - bank-width = <2>;
8   - device-width = <2>;
9   - partition@0x0 {
10   - label = "boot loader area";
11   - reg = <0x00000000 0x003f0000>;
  2 + soc {
  3 + flash: flash@08000000 {
  4 + #address-cells = <1>;
  5 + #size-cells = <1>;
  6 + compatible = "cfi-flash";
  7 + reg = <0x08000000 0x00400000>;
  8 + bank-width = <2>;
  9 + device-width = <2>;
  10 + partition@0x0 {
  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 {
14   - label = "boot environment";
15   - reg = <0x003f0000 0x00010000>;
16   - };
17   - };
  19 + };
18 20 };
arch/xtensa/boot/dts/xtfpga.dtsi
... ... @@ -42,22 +42,29 @@
42 42 };
43 43 };
44 44  
45   - serial0: serial@fd050020 {
46   - device_type = "serial";
47   - compatible = "ns16550a";
48   - no-loopback-test;
49   - reg = <0xfd050020 0x20>;
50   - reg-shift = <2>;
51   - interrupts = <0 1>; /* external irq 0 */
52   - clocks = <&osc>;
53   - };
  45 + soc {
  46 + #address-cells = <1>;
  47 + #size-cells = <1>;
  48 + compatible = "simple-bus";
  49 + ranges = <0x00000000 0xf0000000 0x10000000>;
54 50  
55   - enet0: ethoc@fd030000 {
56   - compatible = "opencores,ethoc";
57   - reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
58   - interrupts = <1 1>; /* external irq 1 */
59   - local-mac-address = [00 50 c2 13 6f 00];
60   - clocks = <&osc>;
  51 + serial0: serial@0d050020 {
  52 + device_type = "serial";
  53 + compatible = "ns16550a";
  54 + no-loopback-test;
  55 + reg = <0x0d050020 0x20>;
  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 };
arch/xtensa/include/asm/bootparam.h
... ... @@ -37,23 +37,14 @@
37 37 unsigned long data[0]; /* data */
38 38 } bp_tag_t;
39 39  
40   -typedef struct meminfo {
  40 +struct bp_meminfo {
41 41 unsigned long type;
42 42 unsigned long start;
43 43 unsigned long end;
44   -} meminfo_t;
  44 +};
45 45  
46   -#define SYSMEM_BANKS_MAX 5
47   -
48 46 #define MEMORY_TYPE_CONVENTIONAL 0x1000
49 47 #define MEMORY_TYPE_NONE 0x2000
50   -
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 48  
58 49 #endif
59 50 #endif
arch/xtensa/include/asm/fixmap.h
  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
arch/xtensa/include/asm/highmem.h
... ... @@ -6,12 +6,55 @@
6 6 * this archive for more details.
7 7 *
8 8 * Copyright (C) 2003 - 2005 Tensilica Inc.
  9 + * Copyright (C) 2014 Cadence Design Systems Inc.
9 10 */
10 11  
11 12 #ifndef _XTENSA_HIGHMEM_H
12 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 59 #endif
arch/xtensa/include/asm/pgtable.h
... ... @@ -310,6 +310,10 @@
310 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 318 static inline void
315 319 set_pmd(pmd_t *pmdp, pmd_t pmdval)
arch/xtensa/include/asm/sysmem.h
  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 */
arch/xtensa/include/asm/tlbflush.h
... ... @@ -36,6 +36,7 @@
36 36 unsigned long page);
37 37 void local_flush_tlb_range(struct vm_area_struct *vma,
38 38 unsigned long start, unsigned long end);
  39 +void local_flush_tlb_kernel_range(unsigned long start, unsigned long end);
39 40  
40 41 #ifdef CONFIG_SMP
41 42  
42 43  
... ... @@ -44,13 +45,8 @@
44 45 void flush_tlb_page(struct vm_area_struct *, unsigned long);
45 46 void flush_tlb_range(struct vm_area_struct *, unsigned long,
46 47 unsigned long);
  48 +void flush_tlb_kernel_range(unsigned long start, unsigned long end);
47 49  
48   -static inline void flush_tlb_kernel_range(unsigned long start,
49   - unsigned long end)
50   -{
51   - flush_tlb_all();
52   -}
53   -
54 50 #else /* !CONFIG_SMP */
55 51  
56 52 #define flush_tlb_all() local_flush_tlb_all()
... ... @@ -58,7 +54,8 @@
58 54 #define flush_tlb_page(vma, page) local_flush_tlb_page(vma, page)
59 55 #define flush_tlb_range(vma, vmaddr, end) local_flush_tlb_range(vma, vmaddr, \
60 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 60 #endif /* CONFIG_SMP */
64 61  
arch/xtensa/kernel/setup.c
... ... @@ -50,6 +50,7 @@
50 50 #include <asm/param.h>
51 51 #include <asm/traps.h>
52 52 #include <asm/smp.h>
  53 +#include <asm/sysmem.h>
53 54  
54 55 #include <platform/hardware.h>
55 56  
... ... @@ -88,12 +89,6 @@
88 89 static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
89 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 93 * Boot parameter parsing.
99 94 *
100 95  
101 96  
... ... @@ -113,31 +108,14 @@
113 108  
114 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 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 115 if (mi->type != MEMORY_TYPE_CONVENTIONAL)
138 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 121 __tagtable(BP_TAG_MEMORY, parse_tag_mem);
... ... @@ -146,8 +124,8 @@
146 124  
147 125 static int __init parse_tag_initrd(const bp_tag_t* tag)
148 126 {
149   - meminfo_t* mi;
150   - mi = (meminfo_t*)(tag->data);
  127 + struct bp_meminfo *mi = (struct bp_meminfo *)(tag->data);
  128 +
151 129 initrd_start = (unsigned long)__va(mi->start);
152 130 initrd_end = (unsigned long)__va(mi->end);
153 131  
... ... @@ -255,7 +233,7 @@
255 233 return;
256 234  
257 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 239 void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
... ... @@ -292,8 +270,6 @@
292 270  
293 271 void __init init_arch(bp_tag_t *bp_start)
294 272 {
295   - sysmem.nr_banks = 0;
296   -
297 273 /* Parse boot parameters */
298 274  
299 275 if (bp_start)
... ... @@ -304,10 +280,9 @@
304 280 #endif
305 281  
306 282 if (sysmem.nr_banks == 0) {
307   - sysmem.nr_banks = 1;
308   - sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START;
309   - sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START
310   - + PLATFORM_DEFAULT_MEM_SIZE;
  283 + add_sysmem_bank(PLATFORM_DEFAULT_MEM_START,
  284 + PLATFORM_DEFAULT_MEM_START +
  285 + PLATFORM_DEFAULT_MEM_SIZE);
311 286 }
312 287  
313 288 #ifdef CONFIG_CMDLINE_BOOL
... ... @@ -487,7 +462,7 @@
487 462 #ifdef CONFIG_BLK_DEV_INITRD
488 463 if (initrd_start < initrd_end) {
489 464 initrd_is_mapped = mem_reserve(__pa(initrd_start),
490   - __pa(initrd_end), 0);
  465 + __pa(initrd_end), 0) == 0;
491 466 initrd_below_start_ok = 1;
492 467 } else {
493 468 initrd_start = 0;
... ... @@ -532,6 +507,7 @@
532 507 __pa(&_Level6InterruptVector_text_end), 0);
533 508 #endif
534 509  
  510 + parse_early_param();
535 511 bootmem_init();
536 512  
537 513 unflatten_and_copy_device_tree();
arch/xtensa/kernel/smp.c
... ... @@ -496,6 +496,21 @@
496 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 514 /* Cache flush functions */
500 515  
501 516 static void ipi_flush_cache_all(void *arg)
arch/xtensa/kernel/xtensa_ksyms.c
... ... @@ -20,6 +20,7 @@
20 20 #include <linux/in6.h>
21 21  
22 22 #include <asm/uaccess.h>
  23 +#include <asm/cacheflush.h>
23 24 #include <asm/checksum.h>
24 25 #include <asm/dma.h>
25 26 #include <asm/io.h>
... ... @@ -105,6 +106,7 @@
105 106 * Architecture-specific symbols
106 107 */
107 108 EXPORT_SYMBOL(__xtensa_copy_user);
  109 +EXPORT_SYMBOL(__invalidate_icache_range);
108 110  
109 111 /*
110 112 * Kernel hacking ...
... ... @@ -126,5 +128,10 @@
126 128  
127 129 #ifdef CONFIG_FUNCTION_TRACER
128 130 EXPORT_SYMBOL(_mcount);
  131 +#endif
  132 +
  133 +EXPORT_SYMBOL(__invalidate_dcache_range);
  134 +#if XCHAL_DCACHE_IS_WRITEBACK
  135 +EXPORT_SYMBOL(__flush_dcache_range);
129 136 #endif
arch/xtensa/mm/Makefile
... ... @@ -4,4 +4,5 @@
4 4  
5 5 obj-y := init.o cache.o misc.o
6 6 obj-$(CONFIG_MMU) += fault.o mmu.o tlb.o
  7 +obj-$(CONFIG_HIGHMEM) += highmem.o
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 66 #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
63 67  
64 68 /*
65 69  
... ... @@ -179,10 +183,11 @@
179 183 #else
180 184 if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)
181 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 187 __flush_dcache_page(paddr);
184 188 __invalidate_icache_page(paddr);
185 189 set_bit(PG_arch_1, &page->flags);
  190 + kunmap_atomic((void *)paddr);
186 191 }
187 192 #endif
188 193 }
arch/xtensa/mm/highmem.c
  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 +}
arch/xtensa/mm/init.c
... ... @@ -8,6 +8,7 @@
8 8 * for more details.
9 9 *
10 10 * Copyright (C) 2001 - 2005 Tensilica Inc.
  11 + * Copyright (C) 2014 Cadence Design Systems Inc.
11 12 *
12 13 * Chris Zankel <chris@zankel.net>
13 14 * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
... ... @@ -19,6 +20,7 @@
19 20 #include <linux/errno.h>
20 21 #include <linux/bootmem.h>
21 22 #include <linux/gfp.h>
  23 +#include <linux/highmem.h>
22 24 #include <linux/swap.h>
23 25 #include <linux/mman.h>
24 26 #include <linux/nodemask.h>
25 27  
26 28  
27 29  
... ... @@ -27,11 +29,133 @@
27 29 #include <asm/bootparam.h>
28 30 #include <asm/page.h>
29 31 #include <asm/sections.h>
  32 +#include <asm/sysmem.h>
30 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 +
31 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 +}
  152 +
  153 +/*
32 154 * mem_reserve(start, end, must_exist)
33 155 *
34 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 160 * Parameters:
37 161 * start Start of region,
38 162  
39 163  
40 164  
41 165  
42 166  
43 167  
44 168  
45 169  
46 170  
47 171  
... ... @@ -39,53 +163,69 @@
39 163 * must_exist Must exist in memory pool.
40 164 *
41 165 * Returns:
42   - * 0 (memory area couldn't be mapped)
43   - * -1 (success)
  166 + * 0 (success)
  167 + * < 0 (error)
44 168 */
45 169  
46 170 int __init mem_reserve(unsigned long start, unsigned long end, int must_exist)
47 171 {
48   - int i;
  172 + struct meminfo *it;
  173 + struct meminfo *rm = NULL;
  174 + unsigned long sz;
  175 + unsigned long bank_sz = 0;
49 176  
50   - if (start == end)
51   - return 0;
52   -
53 177 start = start & PAGE_MASK;
54 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++)
57   - if (start < sysmem.bank[i].end
58   - && end >= sysmem.bank[i].start)
59   - break;
  183 + it = find_bank(start);
60 184  
61   - if (i == sysmem.nr_banks) {
62   - if (must_exist)
63   - printk (KERN_WARNING "mem_reserve: [0x%0lx, 0x%0lx) "
64   - "not in any region!\n", start, end);
65   - return 0;
  185 + if (it)
  186 + bank_sz = it->end - it->start;
  187 +
  188 + if ((!it || end - it->start > bank_sz) && must_exist) {
  189 + pr_warn("mem_reserve: [0x%0lx, 0x%0lx) not in any region!\n",
  190 + start, end);
  191 + return -EINVAL;
66 192 }
67 193  
68   - if (start > sysmem.bank[i].start) {
69   - if (end < sysmem.bank[i].end) {
70   - /* split entry */
71   - if (sysmem.nr_banks >= SYSMEM_BANKS_MAX)
72   - panic("meminfo overflow\n");
73   - sysmem.bank[sysmem.nr_banks].start = end;
74   - sysmem.bank[sysmem.nr_banks].end = sysmem.bank[i].end;
75   - sysmem.nr_banks++;
  194 + if (it && start - it->start < bank_sz) {
  195 + if (start == it->start) {
  196 + if (end - it->start < bank_sz) {
  197 + it->start = end;
  198 + return 0;
  199 + } else {
  200 + rm = it;
  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) {
80   - sysmem.bank[i].start = end;
  211 + if (!it)
  212 + it = sysmem.bank;
81 213  
82   - } else {
83   - /* remove entry */
84   - sysmem.nr_banks--;
85   - sysmem.bank[i].start = sysmem.bank[sysmem.nr_banks].start;
86   - sysmem.bank[i].end = sysmem.bank[sysmem.nr_banks].end;
  214 + for (; it < sysmem.bank + sysmem.nr_banks; ++it) {
  215 + if (it->end - start <= sz) {
  216 + if (!rm)
  217 + rm = it;
  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 @@
99 239 unsigned long bootmap_start, bootmap_size;
100 240 int i;
101 241  
  242 + sysmem_dump();
102 243 max_low_pfn = max_pfn = 0;
103 244 min_low_pfn = ~0;
104 245  
105 246  
106 247  
107 248  
... ... @@ -156,19 +297,13 @@
156 297  
157 298 void __init zones_init(void)
158 299 {
159   - unsigned long zones_size[MAX_NR_ZONES];
160   - int i;
161   -
162 300 /* All pages are DMA-able, so we put them all in the DMA zone. */
163   -
164   - zones_size[ZONE_DMA] = max_low_pfn - ARCH_PFN_OFFSET;
165   - for (i = 1; i < MAX_NR_ZONES; i++)
166   - zones_size[i] = 0;
167   -
  301 + unsigned long zones_size[MAX_NR_ZONES] = {
  302 + [ZONE_DMA] = max_low_pfn - ARCH_PFN_OFFSET,
168 303 #ifdef CONFIG_HIGHMEM
169   - zones_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn;
  304 + [ZONE_HIGHMEM] = max_pfn - max_low_pfn,
170 305 #endif
171   -
  306 + };
172 307 free_area_init_node(0, zones_size, ARCH_PFN_OFFSET, NULL);
173 308 }
174 309  
175 310  
176 311  
177 312  
... ... @@ -178,16 +313,38 @@
178 313  
179 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 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 322 #endif
187 323  
  324 + max_mapnr = max_pfn - ARCH_PFN_OFFSET;
  325 + high_memory = (void *)__va(max_low_pfn << PAGE_SHIFT);
  326 +
188 327 free_all_bootmem();
189 328  
190 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 350 #ifdef CONFIG_BLK_DEV_INITRD
... ... @@ -204,4 +361,54 @@
204 361 {
205 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);
arch/xtensa/mm/mmu.c
... ... @@ -3,6 +3,7 @@
3 3 *
4 4 * Extracted from init.c
5 5 */
  6 +#include <linux/bootmem.h>
6 7 #include <linux/percpu.h>
7 8 #include <linux/init.h>
8 9 #include <linux/string.h>
9 10  
... ... @@ -16,9 +17,44 @@
16 17 #include <asm/initialize_mmu.h>
17 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 50 void __init paging_init(void)
20 51 {
21 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 /*
arch/xtensa/mm/tlb.c
... ... @@ -149,6 +149,21 @@
149 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 167 #ifdef CONFIG_DEBUG_TLB_SANITY
153 168  
154 169 static unsigned get_pte_for_vaddr(unsigned vaddr)
arch/xtensa/platforms/iss/Makefile
... ... @@ -4,7 +4,8 @@
4 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 9 obj-$(CONFIG_NET) += network.o
9 10 obj-$(CONFIG_BLK_DEV_SIMDISK) += simdisk.o
arch/xtensa/platforms/xt2000/setup.c
... ... @@ -92,18 +92,8 @@
92 92  
93 93 /* early initialization */
94 94  
95   -extern sysmem_info_t __initdata sysmem;
96   -
97   -void platform_init(bp_tag_t* first)
  95 +void __init 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 99 /* Heartbeat. Let the LED blink. */
scripts/sortextable.c
... ... @@ -35,6 +35,10 @@
35 35 #define EM_ARCOMPACT 93
36 36 #endif
37 37  
  38 +#ifndef EM_XTENSA
  39 +#define EM_XTENSA 94
  40 +#endif
  41 +
38 42 #ifndef EM_AARCH64
39 43 #define EM_AARCH64 183
40 44 #endif
... ... @@ -281,6 +285,7 @@
281 285 case EM_AARCH64:
282 286 case EM_MICROBLAZE:
283 287 case EM_MIPS:
  288 + case EM_XTENSA:
284 289 break;
285 290 } /* end switch */
286 291