diff options
Diffstat (limited to 'arch/arm/mm')
| -rw-r--r-- | arch/arm/mm/Kconfig | 8 | ||||
| -rw-r--r-- | arch/arm/mm/abort-ev6.S | 5 | ||||
| -rw-r--r-- | arch/arm/mm/alignment.c | 55 | ||||
| -rw-r--r-- | arch/arm/mm/cache-v6.S | 9 | ||||
| -rw-r--r-- | arch/arm/mm/flush.c | 36 | ||||
| -rw-r--r-- | arch/arm/mm/proc-v6.S | 9 |
6 files changed, 75 insertions, 47 deletions
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index db5e47dfc303..c54e04c995ee 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig | |||
| @@ -370,21 +370,21 @@ config CPU_BIG_ENDIAN | |||
| 370 | 370 | ||
| 371 | config CPU_ICACHE_DISABLE | 371 | config CPU_ICACHE_DISABLE |
| 372 | bool "Disable I-Cache" | 372 | bool "Disable I-Cache" |
| 373 | depends on CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 | 373 | depends on CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_V6 |
| 374 | help | 374 | help |
| 375 | Say Y here to disable the processor instruction cache. Unless | 375 | Say Y here to disable the processor instruction cache. Unless |
| 376 | you have a reason not to or are unsure, say N. | 376 | you have a reason not to or are unsure, say N. |
| 377 | 377 | ||
| 378 | config CPU_DCACHE_DISABLE | 378 | config CPU_DCACHE_DISABLE |
| 379 | bool "Disable D-Cache" | 379 | bool "Disable D-Cache" |
| 380 | depends on CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 | 380 | depends on CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_V6 |
| 381 | help | 381 | help |
| 382 | Say Y here to disable the processor data cache. Unless | 382 | Say Y here to disable the processor data cache. Unless |
| 383 | you have a reason not to or are unsure, say N. | 383 | you have a reason not to or are unsure, say N. |
| 384 | 384 | ||
| 385 | config CPU_DCACHE_WRITETHROUGH | 385 | config CPU_DCACHE_WRITETHROUGH |
| 386 | bool "Force write through D-cache" | 386 | bool "Force write through D-cache" |
| 387 | depends on (CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020) && !CPU_DCACHE_DISABLE | 387 | depends on (CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_V6) && !CPU_DCACHE_DISABLE |
| 388 | default y if CPU_ARM925T | 388 | default y if CPU_ARM925T |
| 389 | help | 389 | help |
| 390 | Say Y here to use the data cache in writethrough mode. Unless you | 390 | Say Y here to use the data cache in writethrough mode. Unless you |
| @@ -399,7 +399,7 @@ config CPU_CACHE_ROUND_ROBIN | |||
| 399 | 399 | ||
| 400 | config CPU_BPREDICT_DISABLE | 400 | config CPU_BPREDICT_DISABLE |
| 401 | bool "Disable branch prediction" | 401 | bool "Disable branch prediction" |
| 402 | depends on CPU_ARM1020 | 402 | depends on CPU_ARM1020 || CPU_V6 |
| 403 | help | 403 | help |
| 404 | Say Y here to disable branch prediction. If unsure, say N. | 404 | Say Y here to disable branch prediction. If unsure, say N. |
| 405 | 405 | ||
diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S index 8f76f3df7b4c..dbd346033122 100644 --- a/arch/arm/mm/abort-ev6.S +++ b/arch/arm/mm/abort-ev6.S | |||
| @@ -20,6 +20,11 @@ | |||
| 20 | */ | 20 | */ |
| 21 | .align 5 | 21 | .align 5 |
| 22 | ENTRY(v6_early_abort) | 22 | ENTRY(v6_early_abort) |
| 23 | #ifdef CONFIG_CPU_MPCORE | ||
| 24 | clrex | ||
| 25 | #else | ||
| 26 | strex r0, r1, [sp] @ Clear the exclusive monitor | ||
| 27 | #endif | ||
| 23 | mrc p15, 0, r1, c5, c0, 0 @ get FSR | 28 | mrc p15, 0, r1, c5, c0, 0 @ get FSR |
| 24 | mrc p15, 0, r0, c6, c0, 0 @ get FAR | 29 | mrc p15, 0, r0, c6, c0, 0 @ get FAR |
| 25 | /* | 30 | /* |
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 4b39d867ac14..705c98921c37 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c | |||
| @@ -111,7 +111,7 @@ proc_alignment_read(char *page, char **start, off_t off, int count, int *eof, | |||
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | static int proc_alignment_write(struct file *file, const char __user *buffer, | 113 | static int proc_alignment_write(struct file *file, const char __user *buffer, |
| 114 | unsigned long count, void *data) | 114 | unsigned long count, void *data) |
| 115 | { | 115 | { |
| 116 | char mode; | 116 | char mode; |
| 117 | 117 | ||
| @@ -119,7 +119,7 @@ static int proc_alignment_write(struct file *file, const char __user *buffer, | |||
| 119 | if (get_user(mode, buffer)) | 119 | if (get_user(mode, buffer)) |
| 120 | return -EFAULT; | 120 | return -EFAULT; |
| 121 | if (mode >= '0' && mode <= '5') | 121 | if (mode >= '0' && mode <= '5') |
| 122 | ai_usermode = mode - '0'; | 122 | ai_usermode = mode - '0'; |
| 123 | } | 123 | } |
| 124 | return count; | 124 | return count; |
| 125 | } | 125 | } |
| @@ -262,7 +262,7 @@ union offset_union { | |||
| 262 | goto fault; \ | 262 | goto fault; \ |
| 263 | } while (0) | 263 | } while (0) |
| 264 | 264 | ||
| 265 | #define put32_unaligned_check(val,addr) \ | 265 | #define put32_unaligned_check(val,addr) \ |
| 266 | __put32_unaligned_check("strb", val, addr) | 266 | __put32_unaligned_check("strb", val, addr) |
| 267 | 267 | ||
| 268 | #define put32t_unaligned_check(val,addr) \ | 268 | #define put32t_unaligned_check(val,addr) \ |
| @@ -306,19 +306,19 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r | |||
| 306 | return TYPE_LDST; | 306 | return TYPE_LDST; |
| 307 | 307 | ||
| 308 | user: | 308 | user: |
| 309 | if (LDST_L_BIT(instr)) { | 309 | if (LDST_L_BIT(instr)) { |
| 310 | unsigned long val; | 310 | unsigned long val; |
| 311 | get16t_unaligned_check(val, addr); | 311 | get16t_unaligned_check(val, addr); |
| 312 | 312 | ||
| 313 | /* signed half-word? */ | 313 | /* signed half-word? */ |
| 314 | if (instr & 0x40) | 314 | if (instr & 0x40) |
| 315 | val = (signed long)((signed short) val); | 315 | val = (signed long)((signed short) val); |
| 316 | 316 | ||
| 317 | regs->uregs[rd] = val; | 317 | regs->uregs[rd] = val; |
| 318 | } else | 318 | } else |
| 319 | put16t_unaligned_check(regs->uregs[rd], addr); | 319 | put16t_unaligned_check(regs->uregs[rd], addr); |
| 320 | 320 | ||
| 321 | return TYPE_LDST; | 321 | return TYPE_LDST; |
| 322 | 322 | ||
| 323 | fault: | 323 | fault: |
| 324 | return TYPE_FAULT; | 324 | return TYPE_FAULT; |
| @@ -330,6 +330,9 @@ do_alignment_ldrdstrd(unsigned long addr, unsigned long instr, | |||
| 330 | { | 330 | { |
| 331 | unsigned int rd = RD_BITS(instr); | 331 | unsigned int rd = RD_BITS(instr); |
| 332 | 332 | ||
| 333 | if (((rd & 1) == 1) || (rd == 14)) | ||
| 334 | goto bad; | ||
| 335 | |||
| 333 | ai_dword += 1; | 336 | ai_dword += 1; |
| 334 | 337 | ||
| 335 | if (user_mode(regs)) | 338 | if (user_mode(regs)) |
| @@ -339,11 +342,11 @@ do_alignment_ldrdstrd(unsigned long addr, unsigned long instr, | |||
| 339 | unsigned long val; | 342 | unsigned long val; |
| 340 | get32_unaligned_check(val, addr); | 343 | get32_unaligned_check(val, addr); |
| 341 | regs->uregs[rd] = val; | 344 | regs->uregs[rd] = val; |
| 342 | get32_unaligned_check(val, addr+4); | 345 | get32_unaligned_check(val, addr + 4); |
| 343 | regs->uregs[rd+1] = val; | 346 | regs->uregs[rd + 1] = val; |
| 344 | } else { | 347 | } else { |
| 345 | put32_unaligned_check(regs->uregs[rd], addr); | 348 | put32_unaligned_check(regs->uregs[rd], addr); |
| 346 | put32_unaligned_check(regs->uregs[rd+1], addr+4); | 349 | put32_unaligned_check(regs->uregs[rd + 1], addr + 4); |
| 347 | } | 350 | } |
| 348 | 351 | ||
| 349 | return TYPE_LDST; | 352 | return TYPE_LDST; |
| @@ -353,15 +356,16 @@ do_alignment_ldrdstrd(unsigned long addr, unsigned long instr, | |||
| 353 | unsigned long val; | 356 | unsigned long val; |
| 354 | get32t_unaligned_check(val, addr); | 357 | get32t_unaligned_check(val, addr); |
| 355 | regs->uregs[rd] = val; | 358 | regs->uregs[rd] = val; |
| 356 | get32t_unaligned_check(val, addr+4); | 359 | get32t_unaligned_check(val, addr + 4); |
| 357 | regs->uregs[rd+1] = val; | 360 | regs->uregs[rd + 1] = val; |
| 358 | } else { | 361 | } else { |
| 359 | put32t_unaligned_check(regs->uregs[rd], addr); | 362 | put32t_unaligned_check(regs->uregs[rd], addr); |
| 360 | put32t_unaligned_check(regs->uregs[rd+1], addr+4); | 363 | put32t_unaligned_check(regs->uregs[rd + 1], addr + 4); |
| 361 | } | 364 | } |
| 362 | 365 | ||
| 363 | return TYPE_LDST; | 366 | return TYPE_LDST; |
| 364 | 367 | bad: | |
| 368 | return TYPE_ERROR; | ||
| 365 | fault: | 369 | fault: |
| 366 | return TYPE_FAULT; | 370 | return TYPE_FAULT; |
| 367 | } | 371 | } |
| @@ -439,7 +443,7 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg | |||
| 439 | if (LDST_P_EQ_U(instr)) /* U = P */ | 443 | if (LDST_P_EQ_U(instr)) /* U = P */ |
| 440 | eaddr += 4; | 444 | eaddr += 4; |
| 441 | 445 | ||
| 442 | /* | 446 | /* |
| 443 | * For alignment faults on the ARM922T/ARM920T the MMU makes | 447 | * For alignment faults on the ARM922T/ARM920T the MMU makes |
| 444 | * the FSR (and hence addr) equal to the updated base address | 448 | * the FSR (and hence addr) equal to the updated base address |
| 445 | * of the multiple access rather than the restored value. | 449 | * of the multiple access rather than the restored value. |
| @@ -566,7 +570,7 @@ thumb2arm(u16 tinstr) | |||
| 566 | /* 6.5.1 Format 3: */ | 570 | /* 6.5.1 Format 3: */ |
| 567 | case 0x4800 >> 11: /* 7.1.28 LDR(3) */ | 571 | case 0x4800 >> 11: /* 7.1.28 LDR(3) */ |
| 568 | /* NOTE: This case is not technically possible. We're | 572 | /* NOTE: This case is not technically possible. We're |
| 569 | * loading 32-bit memory data via PC relative | 573 | * loading 32-bit memory data via PC relative |
| 570 | * addressing mode. So we can and should eliminate | 574 | * addressing mode. So we can and should eliminate |
| 571 | * this case. But I'll leave it here for now. | 575 | * this case. But I'll leave it here for now. |
| 572 | */ | 576 | */ |
| @@ -638,7 +642,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
| 638 | 642 | ||
| 639 | if (fault) { | 643 | if (fault) { |
| 640 | type = TYPE_FAULT; | 644 | type = TYPE_FAULT; |
| 641 | goto bad_or_fault; | 645 | goto bad_or_fault; |
| 642 | } | 646 | } |
| 643 | 647 | ||
| 644 | if (user_mode(regs)) | 648 | if (user_mode(regs)) |
| @@ -663,6 +667,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
| 663 | else if ((instr & 0x001000f0) == 0x000000d0 || /* LDRD */ | 667 | else if ((instr & 0x001000f0) == 0x000000d0 || /* LDRD */ |
| 664 | (instr & 0x001000f0) == 0x000000f0) /* STRD */ | 668 | (instr & 0x001000f0) == 0x000000f0) /* STRD */ |
| 665 | handler = do_alignment_ldrdstrd; | 669 | handler = do_alignment_ldrdstrd; |
| 670 | else if ((instr & 0x01f00ff0) == 0x01000090) /* SWP */ | ||
| 671 | goto swp; | ||
| 666 | else | 672 | else |
| 667 | goto bad; | 673 | goto bad; |
| 668 | break; | 674 | break; |
| @@ -733,6 +739,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
| 733 | do_bad_area(current, current->mm, addr, fsr, regs); | 739 | do_bad_area(current, current->mm, addr, fsr, regs); |
| 734 | return 0; | 740 | return 0; |
| 735 | 741 | ||
| 742 | swp: | ||
| 743 | printk(KERN_ERR "Alignment trap: not handling swp instruction\n"); | ||
| 744 | |||
| 736 | bad: | 745 | bad: |
| 737 | /* | 746 | /* |
| 738 | * Oops, we didn't handle the instruction. | 747 | * Oops, we didn't handle the instruction. |
diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S index 85c10a71e7c6..72966d90e956 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #define HARVARD_CACHE | 18 | #define HARVARD_CACHE |
| 19 | #define CACHE_LINE_SIZE 32 | 19 | #define CACHE_LINE_SIZE 32 |
| 20 | #define D_CACHE_LINE_SIZE 32 | 20 | #define D_CACHE_LINE_SIZE 32 |
| 21 | #define BTB_FLUSH_SIZE 8 | ||
| 21 | 22 | ||
| 22 | /* | 23 | /* |
| 23 | * v6_flush_cache_all() | 24 | * v6_flush_cache_all() |
| @@ -98,7 +99,13 @@ ENTRY(v6_coherent_user_range) | |||
| 98 | mcr p15, 0, r0, c7, c5, 1 @ invalidate I line | 99 | mcr p15, 0, r0, c7, c5, 1 @ invalidate I line |
| 99 | #endif | 100 | #endif |
| 100 | mcr p15, 0, r0, c7, c5, 7 @ invalidate BTB entry | 101 | mcr p15, 0, r0, c7, c5, 7 @ invalidate BTB entry |
| 101 | add r0, r0, #CACHE_LINE_SIZE | 102 | add r0, r0, #BTB_FLUSH_SIZE |
| 103 | mcr p15, 0, r0, c7, c5, 7 @ invalidate BTB entry | ||
| 104 | add r0, r0, #BTB_FLUSH_SIZE | ||
| 105 | mcr p15, 0, r0, c7, c5, 7 @ invalidate BTB entry | ||
| 106 | add r0, r0, #BTB_FLUSH_SIZE | ||
| 107 | mcr p15, 0, r0, c7, c5, 7 @ invalidate BTB entry | ||
| 108 | add r0, r0, #BTB_FLUSH_SIZE | ||
| 102 | cmp r0, r1 | 109 | cmp r0, r1 |
| 103 | blo 1b | 110 | blo 1b |
| 104 | #ifdef HARVARD_CACHE | 111 | #ifdef HARVARD_CACHE |
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index b0208c992576..c9a03981b785 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c | |||
| @@ -17,6 +17,24 @@ | |||
| 17 | 17 | ||
| 18 | #ifdef CONFIG_CPU_CACHE_VIPT | 18 | #ifdef CONFIG_CPU_CACHE_VIPT |
| 19 | 19 | ||
| 20 | #define ALIAS_FLUSH_START 0xffff4000 | ||
| 21 | |||
| 22 | #define TOP_PTE(x) pte_offset_kernel(top_pmd, x) | ||
| 23 | |||
| 24 | static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr) | ||
| 25 | { | ||
| 26 | unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT); | ||
| 27 | |||
| 28 | set_pte(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL)); | ||
| 29 | flush_tlb_kernel_page(to); | ||
| 30 | |||
| 31 | asm( "mcrr p15, 0, %1, %0, c14\n" | ||
| 32 | " mcrr p15, 0, %1, %0, c5\n" | ||
| 33 | : | ||
| 34 | : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES) | ||
| 35 | : "cc"); | ||
| 36 | } | ||
| 37 | |||
| 20 | void flush_cache_mm(struct mm_struct *mm) | 38 | void flush_cache_mm(struct mm_struct *mm) |
| 21 | { | 39 | { |
| 22 | if (cache_is_vivt()) { | 40 | if (cache_is_vivt()) { |
| @@ -67,24 +85,6 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig | |||
| 67 | if (cache_is_vipt_aliasing()) | 85 | if (cache_is_vipt_aliasing()) |
| 68 | flush_pfn_alias(pfn, user_addr); | 86 | flush_pfn_alias(pfn, user_addr); |
| 69 | } | 87 | } |
| 70 | |||
| 71 | #define ALIAS_FLUSH_START 0xffff4000 | ||
| 72 | |||
| 73 | #define TOP_PTE(x) pte_offset_kernel(top_pmd, x) | ||
| 74 | |||
| 75 | static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr) | ||
| 76 | { | ||
| 77 | unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT); | ||
| 78 | |||
| 79 | set_pte(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL)); | ||
| 80 | flush_tlb_kernel_page(to); | ||
| 81 | |||
| 82 | asm( "mcrr p15, 0, %1, %0, c14\n" | ||
| 83 | " mcrr p15, 0, %1, %0, c5\n" | ||
| 84 | : | ||
| 85 | : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES) | ||
| 86 | : "cc"); | ||
| 87 | } | ||
| 88 | #else | 88 | #else |
| 89 | #define flush_pfn_alias(pfn,vaddr) do { } while (0) | 89 | #define flush_pfn_alias(pfn,vaddr) do { } while (0) |
| 90 | #endif | 90 | #endif |
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index caf3b19b167f..9bb5fff406fb 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S | |||
| @@ -55,7 +55,14 @@ ENTRY(cpu_v6_proc_init) | |||
| 55 | mov pc, lr | 55 | mov pc, lr |
| 56 | 56 | ||
| 57 | ENTRY(cpu_v6_proc_fin) | 57 | ENTRY(cpu_v6_proc_fin) |
| 58 | mov pc, lr | 58 | stmfd sp!, {lr} |
| 59 | cpsid if @ disable interrupts | ||
| 60 | bl v6_flush_kern_cache_all | ||
| 61 | mrc p15, 0, r0, c1, c0, 0 @ ctrl register | ||
| 62 | bic r0, r0, #0x1000 @ ...i............ | ||
| 63 | bic r0, r0, #0x0006 @ .............ca. | ||
| 64 | mcr p15, 0, r0, c1, c0, 0 @ disable caches | ||
| 65 | ldmfd sp!, {pc} | ||
| 59 | 66 | ||
| 60 | /* | 67 | /* |
| 61 | * cpu_v6_reset(loc) | 68 | * cpu_v6_reset(loc) |
