diff options
Diffstat (limited to 'arch/arm/mm')
-rw-r--r-- | arch/arm/mm/alignment.c | 139 | ||||
-rw-r--r-- | arch/arm/mm/fault.c | 2 | ||||
-rw-r--r-- | arch/arm/mm/init.c | 118 | ||||
-rw-r--r-- | arch/arm/mm/mmu.c | 16 | ||||
-rw-r--r-- | arch/arm/mm/proc-syms.c | 1 |
5 files changed, 209 insertions, 67 deletions
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 3a398befed41..03cd27d917b9 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c | |||
@@ -62,6 +62,12 @@ | |||
62 | #define SHIFT_ASR 0x40 | 62 | #define SHIFT_ASR 0x40 |
63 | #define SHIFT_RORRRX 0x60 | 63 | #define SHIFT_RORRRX 0x60 |
64 | 64 | ||
65 | #define BAD_INSTR 0xdeadc0de | ||
66 | |||
67 | /* Thumb-2 32 bit format per ARMv7 DDI0406A A6.3, either f800h,e800h,f800h */ | ||
68 | #define IS_T32(hi16) \ | ||
69 | (((hi16) & 0xe000) == 0xe000 && ((hi16) & 0x1800)) | ||
70 | |||
65 | static unsigned long ai_user; | 71 | static unsigned long ai_user; |
66 | static unsigned long ai_sys; | 72 | static unsigned long ai_sys; |
67 | static unsigned long ai_skipped; | 73 | static unsigned long ai_skipped; |
@@ -332,38 +338,48 @@ do_alignment_ldrdstrd(unsigned long addr, unsigned long instr, | |||
332 | struct pt_regs *regs) | 338 | struct pt_regs *regs) |
333 | { | 339 | { |
334 | unsigned int rd = RD_BITS(instr); | 340 | unsigned int rd = RD_BITS(instr); |
335 | 341 | unsigned int rd2; | |
336 | if (((rd & 1) == 1) || (rd == 14)) | 342 | int load; |
343 | |||
344 | if ((instr & 0xfe000000) == 0xe8000000) { | ||
345 | /* ARMv7 Thumb-2 32-bit LDRD/STRD */ | ||
346 | rd2 = (instr >> 8) & 0xf; | ||
347 | load = !!(LDST_L_BIT(instr)); | ||
348 | } else if (((rd & 1) == 1) || (rd == 14)) | ||
337 | goto bad; | 349 | goto bad; |
350 | else { | ||
351 | load = ((instr & 0xf0) == 0xd0); | ||
352 | rd2 = rd + 1; | ||
353 | } | ||
338 | 354 | ||
339 | ai_dword += 1; | 355 | ai_dword += 1; |
340 | 356 | ||
341 | if (user_mode(regs)) | 357 | if (user_mode(regs)) |
342 | goto user; | 358 | goto user; |
343 | 359 | ||
344 | if ((instr & 0xf0) == 0xd0) { | 360 | if (load) { |
345 | unsigned long val; | 361 | unsigned long val; |
346 | get32_unaligned_check(val, addr); | 362 | get32_unaligned_check(val, addr); |
347 | regs->uregs[rd] = val; | 363 | regs->uregs[rd] = val; |
348 | get32_unaligned_check(val, addr + 4); | 364 | get32_unaligned_check(val, addr + 4); |
349 | regs->uregs[rd + 1] = val; | 365 | regs->uregs[rd2] = val; |
350 | } else { | 366 | } else { |
351 | put32_unaligned_check(regs->uregs[rd], addr); | 367 | put32_unaligned_check(regs->uregs[rd], addr); |
352 | put32_unaligned_check(regs->uregs[rd + 1], addr + 4); | 368 | put32_unaligned_check(regs->uregs[rd2], addr + 4); |
353 | } | 369 | } |
354 | 370 | ||
355 | return TYPE_LDST; | 371 | return TYPE_LDST; |
356 | 372 | ||
357 | user: | 373 | user: |
358 | if ((instr & 0xf0) == 0xd0) { | 374 | if (load) { |
359 | unsigned long val; | 375 | unsigned long val; |
360 | get32t_unaligned_check(val, addr); | 376 | get32t_unaligned_check(val, addr); |
361 | regs->uregs[rd] = val; | 377 | regs->uregs[rd] = val; |
362 | get32t_unaligned_check(val, addr + 4); | 378 | get32t_unaligned_check(val, addr + 4); |
363 | regs->uregs[rd + 1] = val; | 379 | regs->uregs[rd2] = val; |
364 | } else { | 380 | } else { |
365 | put32t_unaligned_check(regs->uregs[rd], addr); | 381 | put32t_unaligned_check(regs->uregs[rd], addr); |
366 | put32t_unaligned_check(regs->uregs[rd + 1], addr + 4); | 382 | put32t_unaligned_check(regs->uregs[rd2], addr + 4); |
367 | } | 383 | } |
368 | 384 | ||
369 | return TYPE_LDST; | 385 | return TYPE_LDST; |
@@ -616,8 +632,72 @@ thumb2arm(u16 tinstr) | |||
616 | /* Else fall through for illegal instruction case */ | 632 | /* Else fall through for illegal instruction case */ |
617 | 633 | ||
618 | default: | 634 | default: |
619 | return 0xdeadc0de; | 635 | return BAD_INSTR; |
636 | } | ||
637 | } | ||
638 | |||
639 | /* | ||
640 | * Convert Thumb-2 32 bit LDM, STM, LDRD, STRD to equivalent instruction | ||
641 | * handlable by ARM alignment handler, also find the corresponding handler, | ||
642 | * so that we can reuse ARM userland alignment fault fixups for Thumb. | ||
643 | * | ||
644 | * @pinstr: original Thumb-2 instruction; returns new handlable instruction | ||
645 | * @regs: register context. | ||
646 | * @poffset: return offset from faulted addr for later writeback | ||
647 | * | ||
648 | * NOTES: | ||
649 | * 1. Comments below refer to ARMv7 DDI0406A Thumb Instruction sections. | ||
650 | * 2. Register name Rt from ARMv7 is same as Rd from ARMv6 (Rd is Rt) | ||
651 | */ | ||
652 | static void * | ||
653 | do_alignment_t32_to_handler(unsigned long *pinstr, struct pt_regs *regs, | ||
654 | union offset_union *poffset) | ||
655 | { | ||
656 | unsigned long instr = *pinstr; | ||
657 | u16 tinst1 = (instr >> 16) & 0xffff; | ||
658 | u16 tinst2 = instr & 0xffff; | ||
659 | poffset->un = 0; | ||
660 | |||
661 | switch (tinst1 & 0xffe0) { | ||
662 | /* A6.3.5 Load/Store multiple */ | ||
663 | case 0xe880: /* STM/STMIA/STMEA,LDM/LDMIA, PUSH/POP T2 */ | ||
664 | case 0xe8a0: /* ...above writeback version */ | ||
665 | case 0xe900: /* STMDB/STMFD, LDMDB/LDMEA */ | ||
666 | case 0xe920: /* ...above writeback version */ | ||
667 | /* no need offset decision since handler calculates it */ | ||
668 | return do_alignment_ldmstm; | ||
669 | |||
670 | case 0xf840: /* POP/PUSH T3 (single register) */ | ||
671 | if (RN_BITS(instr) == 13 && (tinst2 & 0x09ff) == 0x0904) { | ||
672 | u32 L = !!(LDST_L_BIT(instr)); | ||
673 | const u32 subset[2] = { | ||
674 | 0xe92d0000, /* STMDB sp!,{registers} */ | ||
675 | 0xe8bd0000, /* LDMIA sp!,{registers} */ | ||
676 | }; | ||
677 | *pinstr = subset[L] | (1<<RD_BITS(instr)); | ||
678 | return do_alignment_ldmstm; | ||
679 | } | ||
680 | /* Else fall through for illegal instruction case */ | ||
681 | break; | ||
682 | |||
683 | /* A6.3.6 Load/store double, STRD/LDRD(immed, lit, reg) */ | ||
684 | case 0xe860: | ||
685 | case 0xe960: | ||
686 | case 0xe8e0: | ||
687 | case 0xe9e0: | ||
688 | poffset->un = (tinst2 & 0xff) << 2; | ||
689 | case 0xe940: | ||
690 | case 0xe9c0: | ||
691 | return do_alignment_ldrdstrd; | ||
692 | |||
693 | /* | ||
694 | * No need to handle load/store instructions up to word size | ||
695 | * since ARMv6 and later CPUs can perform unaligned accesses. | ||
696 | */ | ||
697 | default: | ||
698 | break; | ||
620 | } | 699 | } |
700 | return NULL; | ||
621 | } | 701 | } |
622 | 702 | ||
623 | static int | 703 | static int |
@@ -630,6 +710,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
630 | mm_segment_t fs; | 710 | mm_segment_t fs; |
631 | unsigned int fault; | 711 | unsigned int fault; |
632 | u16 tinstr = 0; | 712 | u16 tinstr = 0; |
713 | int isize = 4; | ||
714 | int thumb2_32b = 0; | ||
633 | 715 | ||
634 | instrptr = instruction_pointer(regs); | 716 | instrptr = instruction_pointer(regs); |
635 | 717 | ||
@@ -637,8 +719,19 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
637 | set_fs(KERNEL_DS); | 719 | set_fs(KERNEL_DS); |
638 | if (thumb_mode(regs)) { | 720 | if (thumb_mode(regs)) { |
639 | fault = __get_user(tinstr, (u16 *)(instrptr & ~1)); | 721 | fault = __get_user(tinstr, (u16 *)(instrptr & ~1)); |
640 | if (!(fault)) | 722 | if (!fault) { |
641 | instr = thumb2arm(tinstr); | 723 | if (cpu_architecture() >= CPU_ARCH_ARMv7 && |
724 | IS_T32(tinstr)) { | ||
725 | /* Thumb-2 32-bit */ | ||
726 | u16 tinst2 = 0; | ||
727 | fault = __get_user(tinst2, (u16 *)(instrptr+2)); | ||
728 | instr = (tinstr << 16) | tinst2; | ||
729 | thumb2_32b = 1; | ||
730 | } else { | ||
731 | isize = 2; | ||
732 | instr = thumb2arm(tinstr); | ||
733 | } | ||
734 | } | ||
642 | } else | 735 | } else |
643 | fault = __get_user(instr, (u32 *)instrptr); | 736 | fault = __get_user(instr, (u32 *)instrptr); |
644 | set_fs(fs); | 737 | set_fs(fs); |
@@ -655,7 +748,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
655 | 748 | ||
656 | fixup: | 749 | fixup: |
657 | 750 | ||
658 | regs->ARM_pc += thumb_mode(regs) ? 2 : 4; | 751 | regs->ARM_pc += isize; |
659 | 752 | ||
660 | switch (CODING_BITS(instr)) { | 753 | switch (CODING_BITS(instr)) { |
661 | case 0x00000000: /* 3.13.4 load/store instruction extensions */ | 754 | case 0x00000000: /* 3.13.4 load/store instruction extensions */ |
@@ -714,18 +807,25 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
714 | handler = do_alignment_ldrstr; | 807 | handler = do_alignment_ldrstr; |
715 | break; | 808 | break; |
716 | 809 | ||
717 | case 0x08000000: /* ldm or stm */ | 810 | case 0x08000000: /* ldm or stm, or thumb-2 32bit instruction */ |
718 | handler = do_alignment_ldmstm; | 811 | if (thumb2_32b) |
812 | handler = do_alignment_t32_to_handler(&instr, regs, &offset); | ||
813 | else | ||
814 | handler = do_alignment_ldmstm; | ||
719 | break; | 815 | break; |
720 | 816 | ||
721 | default: | 817 | default: |
722 | goto bad; | 818 | goto bad; |
723 | } | 819 | } |
724 | 820 | ||
821 | if (!handler) | ||
822 | goto bad; | ||
725 | type = handler(addr, instr, regs); | 823 | type = handler(addr, instr, regs); |
726 | 824 | ||
727 | if (type == TYPE_ERROR || type == TYPE_FAULT) | 825 | if (type == TYPE_ERROR || type == TYPE_FAULT) { |
826 | regs->ARM_pc -= isize; | ||
728 | goto bad_or_fault; | 827 | goto bad_or_fault; |
828 | } | ||
729 | 829 | ||
730 | if (type == TYPE_LDST) | 830 | if (type == TYPE_LDST) |
731 | do_alignment_finish_ldst(addr, instr, regs, offset); | 831 | do_alignment_finish_ldst(addr, instr, regs, offset); |
@@ -735,7 +835,6 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
735 | bad_or_fault: | 835 | bad_or_fault: |
736 | if (type == TYPE_ERROR) | 836 | if (type == TYPE_ERROR) |
737 | goto bad; | 837 | goto bad; |
738 | regs->ARM_pc -= thumb_mode(regs) ? 2 : 4; | ||
739 | /* | 838 | /* |
740 | * We got a fault - fix it up, or die. | 839 | * We got a fault - fix it up, or die. |
741 | */ | 840 | */ |
@@ -751,8 +850,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
751 | */ | 850 | */ |
752 | printk(KERN_ERR "Alignment trap: not handling instruction " | 851 | printk(KERN_ERR "Alignment trap: not handling instruction " |
753 | "%0*lx at [<%08lx>]\n", | 852 | "%0*lx at [<%08lx>]\n", |
754 | thumb_mode(regs) ? 4 : 8, | 853 | isize << 1, |
755 | thumb_mode(regs) ? tinstr : instr, instrptr); | 854 | isize == 2 ? tinstr : instr, instrptr); |
756 | ai_skipped += 1; | 855 | ai_skipped += 1; |
757 | return 1; | 856 | return 1; |
758 | 857 | ||
@@ -763,8 +862,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
763 | printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%0*lx " | 862 | printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%0*lx " |
764 | "Address=0x%08lx FSR 0x%03x\n", current->comm, | 863 | "Address=0x%08lx FSR 0x%03x\n", current->comm, |
765 | task_pid_nr(current), instrptr, | 864 | task_pid_nr(current), instrptr, |
766 | thumb_mode(regs) ? 4 : 8, | 865 | isize << 1, |
767 | thumb_mode(regs) ? tinstr : instr, | 866 | isize == 2 ? tinstr : instr, |
768 | addr, fsr); | 867 | addr, fsr); |
769 | 868 | ||
770 | if (ai_usermode & UM_FIXUP) | 869 | if (ai_usermode & UM_FIXUP) |
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 0455557a2899..6fdcbb709827 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c | |||
@@ -208,7 +208,7 @@ good_area: | |||
208 | * than endlessly redo the fault. | 208 | * than endlessly redo the fault. |
209 | */ | 209 | */ |
210 | survive: | 210 | survive: |
211 | fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, fsr & (1 << 11)); | 211 | fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, (fsr & (1 << 11)) ? FAULT_FLAG_WRITE : 0); |
212 | if (unlikely(fault & VM_FAULT_ERROR)) { | 212 | if (unlikely(fault & VM_FAULT_ERROR)) { |
213 | if (fault & VM_FAULT_OOM) | 213 | if (fault & VM_FAULT_OOM) |
214 | goto out_of_memory; | 214 | goto out_of_memory; |
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 8277802ec859..3a7279c1ce5e 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c | |||
@@ -120,6 +120,32 @@ void show_mem(void) | |||
120 | printk("%d pages swap cached\n", cached); | 120 | printk("%d pages swap cached\n", cached); |
121 | } | 121 | } |
122 | 122 | ||
123 | static void __init find_node_limits(int node, struct meminfo *mi, | ||
124 | unsigned long *min, unsigned long *max_low, unsigned long *max_high) | ||
125 | { | ||
126 | int i; | ||
127 | |||
128 | *min = -1UL; | ||
129 | *max_low = *max_high = 0; | ||
130 | |||
131 | for_each_nodebank(i, mi, node) { | ||
132 | struct membank *bank = &mi->bank[i]; | ||
133 | unsigned long start, end; | ||
134 | |||
135 | start = bank_pfn_start(bank); | ||
136 | end = bank_pfn_end(bank); | ||
137 | |||
138 | if (*min > start) | ||
139 | *min = start; | ||
140 | if (*max_high < end) | ||
141 | *max_high = end; | ||
142 | if (bank->highmem) | ||
143 | continue; | ||
144 | if (*max_low < end) | ||
145 | *max_low = end; | ||
146 | } | ||
147 | } | ||
148 | |||
123 | /* | 149 | /* |
124 | * FIXME: We really want to avoid allocating the bootmap bitmap | 150 | * FIXME: We really want to avoid allocating the bootmap bitmap |
125 | * over the top of the initrd. Hopefully, this is located towards | 151 | * over the top of the initrd. Hopefully, this is located towards |
@@ -210,41 +236,25 @@ static inline void map_memory_bank(struct membank *bank) | |||
210 | #endif | 236 | #endif |
211 | } | 237 | } |
212 | 238 | ||
213 | static unsigned long __init bootmem_init_node(int node, struct meminfo *mi) | 239 | static void __init bootmem_init_node(int node, struct meminfo *mi, |
240 | unsigned long start_pfn, unsigned long end_pfn) | ||
214 | { | 241 | { |
215 | unsigned long start_pfn, end_pfn, boot_pfn; | 242 | unsigned long boot_pfn; |
216 | unsigned int boot_pages; | 243 | unsigned int boot_pages; |
217 | pg_data_t *pgdat; | 244 | pg_data_t *pgdat; |
218 | int i; | 245 | int i; |
219 | 246 | ||
220 | start_pfn = -1UL; | ||
221 | end_pfn = 0; | ||
222 | |||
223 | /* | 247 | /* |
224 | * Calculate the pfn range, and map the memory banks for this node. | 248 | * Map the memory banks for this node. |
225 | */ | 249 | */ |
226 | for_each_nodebank(i, mi, node) { | 250 | for_each_nodebank(i, mi, node) { |
227 | struct membank *bank = &mi->bank[i]; | 251 | struct membank *bank = &mi->bank[i]; |
228 | unsigned long start, end; | ||
229 | 252 | ||
230 | start = bank_pfn_start(bank); | 253 | if (!bank->highmem) |
231 | end = bank_pfn_end(bank); | 254 | map_memory_bank(bank); |
232 | |||
233 | if (start_pfn > start) | ||
234 | start_pfn = start; | ||
235 | if (end_pfn < end) | ||
236 | end_pfn = end; | ||
237 | |||
238 | map_memory_bank(bank); | ||
239 | } | 255 | } |
240 | 256 | ||
241 | /* | 257 | /* |
242 | * If there is no memory in this node, ignore it. | ||
243 | */ | ||
244 | if (end_pfn == 0) | ||
245 | return end_pfn; | ||
246 | |||
247 | /* | ||
248 | * Allocate the bootmem bitmap page. | 258 | * Allocate the bootmem bitmap page. |
249 | */ | 259 | */ |
250 | boot_pages = bootmem_bootmap_pages(end_pfn - start_pfn); | 260 | boot_pages = bootmem_bootmap_pages(end_pfn - start_pfn); |
@@ -260,7 +270,8 @@ static unsigned long __init bootmem_init_node(int node, struct meminfo *mi) | |||
260 | 270 | ||
261 | for_each_nodebank(i, mi, node) { | 271 | for_each_nodebank(i, mi, node) { |
262 | struct membank *bank = &mi->bank[i]; | 272 | struct membank *bank = &mi->bank[i]; |
263 | free_bootmem_node(pgdat, bank_phys_start(bank), bank_phys_size(bank)); | 273 | if (!bank->highmem) |
274 | free_bootmem_node(pgdat, bank_phys_start(bank), bank_phys_size(bank)); | ||
264 | memory_present(node, bank_pfn_start(bank), bank_pfn_end(bank)); | 275 | memory_present(node, bank_pfn_start(bank), bank_pfn_end(bank)); |
265 | } | 276 | } |
266 | 277 | ||
@@ -269,8 +280,6 @@ static unsigned long __init bootmem_init_node(int node, struct meminfo *mi) | |||
269 | */ | 280 | */ |
270 | reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT, | 281 | reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT, |
271 | boot_pages << PAGE_SHIFT, BOOTMEM_DEFAULT); | 282 | boot_pages << PAGE_SHIFT, BOOTMEM_DEFAULT); |
272 | |||
273 | return end_pfn; | ||
274 | } | 283 | } |
275 | 284 | ||
276 | static void __init bootmem_reserve_initrd(int node) | 285 | static void __init bootmem_reserve_initrd(int node) |
@@ -297,33 +306,39 @@ static void __init bootmem_reserve_initrd(int node) | |||
297 | static void __init bootmem_free_node(int node, struct meminfo *mi) | 306 | static void __init bootmem_free_node(int node, struct meminfo *mi) |
298 | { | 307 | { |
299 | unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; | 308 | unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; |
300 | unsigned long start_pfn, end_pfn; | 309 | unsigned long min, max_low, max_high; |
301 | pg_data_t *pgdat = NODE_DATA(node); | ||
302 | int i; | 310 | int i; |
303 | 311 | ||
304 | start_pfn = pgdat->bdata->node_min_pfn; | 312 | find_node_limits(node, mi, &min, &max_low, &max_high); |
305 | end_pfn = pgdat->bdata->node_low_pfn; | ||
306 | 313 | ||
307 | /* | 314 | /* |
308 | * initialise the zones within this node. | 315 | * initialise the zones within this node. |
309 | */ | 316 | */ |
310 | memset(zone_size, 0, sizeof(zone_size)); | 317 | memset(zone_size, 0, sizeof(zone_size)); |
311 | memset(zhole_size, 0, sizeof(zhole_size)); | ||
312 | 318 | ||
313 | /* | 319 | /* |
314 | * The size of this node has already been determined. If we need | 320 | * The size of this node has already been determined. If we need |
315 | * to do anything fancy with the allocation of this memory to the | 321 | * to do anything fancy with the allocation of this memory to the |
316 | * zones, now is the time to do it. | 322 | * zones, now is the time to do it. |
317 | */ | 323 | */ |
318 | zone_size[0] = end_pfn - start_pfn; | 324 | zone_size[0] = max_low - min; |
325 | #ifdef CONFIG_HIGHMEM | ||
326 | zone_size[ZONE_HIGHMEM] = max_high - max_low; | ||
327 | #endif | ||
319 | 328 | ||
320 | /* | 329 | /* |
321 | * For each bank in this node, calculate the size of the holes. | 330 | * For each bank in this node, calculate the size of the holes. |
322 | * holes = node_size - sum(bank_sizes_in_node) | 331 | * holes = node_size - sum(bank_sizes_in_node) |
323 | */ | 332 | */ |
324 | zhole_size[0] = zone_size[0]; | 333 | memcpy(zhole_size, zone_size, sizeof(zhole_size)); |
325 | for_each_nodebank(i, mi, node) | 334 | for_each_nodebank(i, mi, node) { |
326 | zhole_size[0] -= bank_pfn_size(&mi->bank[i]); | 335 | int idx = 0; |
336 | #ifdef CONFIG_HIGHMEM | ||
337 | if (mi->bank[i].highmem) | ||
338 | idx = ZONE_HIGHMEM; | ||
339 | #endif | ||
340 | zhole_size[idx] -= bank_pfn_size(&mi->bank[i]); | ||
341 | } | ||
327 | 342 | ||
328 | /* | 343 | /* |
329 | * Adjust the sizes according to any special requirements for | 344 | * Adjust the sizes according to any special requirements for |
@@ -331,13 +346,13 @@ static void __init bootmem_free_node(int node, struct meminfo *mi) | |||
331 | */ | 346 | */ |
332 | arch_adjust_zones(node, zone_size, zhole_size); | 347 | arch_adjust_zones(node, zone_size, zhole_size); |
333 | 348 | ||
334 | free_area_init_node(node, zone_size, start_pfn, zhole_size); | 349 | free_area_init_node(node, zone_size, min, zhole_size); |
335 | } | 350 | } |
336 | 351 | ||
337 | void __init bootmem_init(void) | 352 | void __init bootmem_init(void) |
338 | { | 353 | { |
339 | struct meminfo *mi = &meminfo; | 354 | struct meminfo *mi = &meminfo; |
340 | unsigned long memend_pfn = 0; | 355 | unsigned long min, max_low, max_high; |
341 | int node, initrd_node; | 356 | int node, initrd_node; |
342 | 357 | ||
343 | /* | 358 | /* |
@@ -345,11 +360,29 @@ void __init bootmem_init(void) | |||
345 | */ | 360 | */ |
346 | initrd_node = check_initrd(mi); | 361 | initrd_node = check_initrd(mi); |
347 | 362 | ||
363 | max_low = max_high = 0; | ||
364 | |||
348 | /* | 365 | /* |
349 | * Run through each node initialising the bootmem allocator. | 366 | * Run through each node initialising the bootmem allocator. |
350 | */ | 367 | */ |
351 | for_each_node(node) { | 368 | for_each_node(node) { |
352 | unsigned long end_pfn = bootmem_init_node(node, mi); | 369 | unsigned long node_low, node_high; |
370 | |||
371 | find_node_limits(node, mi, &min, &node_low, &node_high); | ||
372 | |||
373 | if (node_low > max_low) | ||
374 | max_low = node_low; | ||
375 | if (node_high > max_high) | ||
376 | max_high = node_high; | ||
377 | |||
378 | /* | ||
379 | * If there is no memory in this node, ignore it. | ||
380 | * (We can't have nodes which have no lowmem) | ||
381 | */ | ||
382 | if (node_low == 0) | ||
383 | continue; | ||
384 | |||
385 | bootmem_init_node(node, mi, min, node_low); | ||
353 | 386 | ||
354 | /* | 387 | /* |
355 | * Reserve any special node zero regions. | 388 | * Reserve any special node zero regions. |
@@ -362,12 +395,6 @@ void __init bootmem_init(void) | |||
362 | */ | 395 | */ |
363 | if (node == initrd_node) | 396 | if (node == initrd_node) |
364 | bootmem_reserve_initrd(node); | 397 | bootmem_reserve_initrd(node); |
365 | |||
366 | /* | ||
367 | * Remember the highest memory PFN. | ||
368 | */ | ||
369 | if (end_pfn > memend_pfn) | ||
370 | memend_pfn = end_pfn; | ||
371 | } | 398 | } |
372 | 399 | ||
373 | /* | 400 | /* |
@@ -383,7 +410,7 @@ void __init bootmem_init(void) | |||
383 | for_each_node(node) | 410 | for_each_node(node) |
384 | bootmem_free_node(node, mi); | 411 | bootmem_free_node(node, mi); |
385 | 412 | ||
386 | high_memory = __va((memend_pfn << PAGE_SHIFT) - 1) + 1; | 413 | high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1; |
387 | 414 | ||
388 | /* | 415 | /* |
389 | * This doesn't seem to be used by the Linux memory manager any | 416 | * This doesn't seem to be used by the Linux memory manager any |
@@ -393,7 +420,8 @@ void __init bootmem_init(void) | |||
393 | * Note: max_low_pfn and max_pfn reflect the number of _pages_ in | 420 | * Note: max_low_pfn and max_pfn reflect the number of _pages_ in |
394 | * the system, not the maximum PFN. | 421 | * the system, not the maximum PFN. |
395 | */ | 422 | */ |
396 | max_pfn = max_low_pfn = memend_pfn - PHYS_PFN_OFFSET; | 423 | max_low_pfn = max_low - PHYS_PFN_OFFSET; |
424 | max_pfn = max_high - PHYS_PFN_OFFSET; | ||
397 | } | 425 | } |
398 | 426 | ||
399 | static inline int free_area(unsigned long pfn, unsigned long end, char *s) | 427 | static inline int free_area(unsigned long pfn, unsigned long end, char *s) |
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index fdaa9bb87c16..4426ee67ceca 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c | |||
@@ -687,13 +687,19 @@ __early_param("vmalloc=", early_vmalloc); | |||
687 | 687 | ||
688 | static void __init sanity_check_meminfo(void) | 688 | static void __init sanity_check_meminfo(void) |
689 | { | 689 | { |
690 | int i, j; | 690 | int i, j, highmem = 0; |
691 | 691 | ||
692 | for (i = 0, j = 0; i < meminfo.nr_banks; i++) { | 692 | for (i = 0, j = 0; i < meminfo.nr_banks; i++) { |
693 | struct membank *bank = &meminfo.bank[j]; | 693 | struct membank *bank = &meminfo.bank[j]; |
694 | *bank = meminfo.bank[i]; | 694 | *bank = meminfo.bank[i]; |
695 | 695 | ||
696 | #ifdef CONFIG_HIGHMEM | 696 | #ifdef CONFIG_HIGHMEM |
697 | if (__va(bank->start) > VMALLOC_MIN || | ||
698 | __va(bank->start) < (void *)PAGE_OFFSET) | ||
699 | highmem = 1; | ||
700 | |||
701 | bank->highmem = highmem; | ||
702 | |||
697 | /* | 703 | /* |
698 | * Split those memory banks which are partially overlapping | 704 | * Split those memory banks which are partially overlapping |
699 | * the vmalloc area greatly simplifying things later. | 705 | * the vmalloc area greatly simplifying things later. |
@@ -714,6 +720,7 @@ static void __init sanity_check_meminfo(void) | |||
714 | i++; | 720 | i++; |
715 | bank[1].size -= VMALLOC_MIN - __va(bank->start); | 721 | bank[1].size -= VMALLOC_MIN - __va(bank->start); |
716 | bank[1].start = __pa(VMALLOC_MIN - 1) + 1; | 722 | bank[1].start = __pa(VMALLOC_MIN - 1) + 1; |
723 | bank[1].highmem = highmem = 1; | ||
717 | j++; | 724 | j++; |
718 | } | 725 | } |
719 | bank->size = VMALLOC_MIN - __va(bank->start); | 726 | bank->size = VMALLOC_MIN - __va(bank->start); |
@@ -836,6 +843,13 @@ void __init reserve_node_zero(pg_data_t *pgdat) | |||
836 | BOOTMEM_EXCLUSIVE); | 843 | BOOTMEM_EXCLUSIVE); |
837 | } | 844 | } |
838 | 845 | ||
846 | if (machine_is_treo680()) { | ||
847 | reserve_bootmem_node(pgdat, 0xa0000000, 0x1000, | ||
848 | BOOTMEM_EXCLUSIVE); | ||
849 | reserve_bootmem_node(pgdat, 0xa2000000, 0x1000, | ||
850 | BOOTMEM_EXCLUSIVE); | ||
851 | } | ||
852 | |||
839 | if (machine_is_palmt5()) | 853 | if (machine_is_palmt5()) |
840 | reserve_bootmem_node(pgdat, 0xa0200000, 0x1000, | 854 | reserve_bootmem_node(pgdat, 0xa0200000, 0x1000, |
841 | BOOTMEM_EXCLUSIVE); | 855 | BOOTMEM_EXCLUSIVE); |
diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c index 195e48edd8c2..ac5c80062b70 100644 --- a/arch/arm/mm/proc-syms.c +++ b/arch/arm/mm/proc-syms.c | |||
@@ -27,6 +27,7 @@ EXPORT_SYMBOL(__cpuc_flush_kern_all); | |||
27 | EXPORT_SYMBOL(__cpuc_flush_user_all); | 27 | EXPORT_SYMBOL(__cpuc_flush_user_all); |
28 | EXPORT_SYMBOL(__cpuc_flush_user_range); | 28 | EXPORT_SYMBOL(__cpuc_flush_user_range); |
29 | EXPORT_SYMBOL(__cpuc_coherent_kern_range); | 29 | EXPORT_SYMBOL(__cpuc_coherent_kern_range); |
30 | EXPORT_SYMBOL(__cpuc_flush_dcache_page); | ||
30 | EXPORT_SYMBOL(dmac_inv_range); /* because of flush_ioremap_region() */ | 31 | EXPORT_SYMBOL(dmac_inv_range); /* because of flush_ioremap_region() */ |
31 | #else | 32 | #else |
32 | EXPORT_SYMBOL(cpu_cache); | 33 | EXPORT_SYMBOL(cpu_cache); |