diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2005-09-22 00:49:32 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-09-22 00:49:32 -0400 |
commit | 1ac4f5ebaa496a23ab4a148c9864d7e30a6c6cd3 (patch) | |
tree | 1ab1e111f596b8c66c741e63f14d721cb1818c7a /arch | |
parent | 059deb693ec191e563ec69533d24f3feff0b78cd (diff) |
[SPARC64]: Remove ktlb.S instruction patching.
This was kind of ugly, and actually buggy. The bug was that
we didn't handle a machine with memory starting > 4GB. If
the 'prompmd' was allocated in physical memory > 4GB we'd
croak because the obp_iaddr_patch and obp_daddr_patch things
only supported a 32-bit physical address.
So fix this by just loading the appropriate values from two
variables in the kernel image, which is locked into the TLB
and thus accesses to them can't cause a recursive TLB miss.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc64/kernel/ktlb.S | 31 | ||||
-rw-r--r-- | arch/sparc64/mm/init.c | 32 |
2 files changed, 24 insertions, 39 deletions
diff --git a/arch/sparc64/kernel/ktlb.S b/arch/sparc64/kernel/ktlb.S index b7176792c9a2..a591bc0ebc7b 100644 --- a/arch/sparc64/kernel/ktlb.S +++ b/arch/sparc64/kernel/ktlb.S | |||
@@ -15,8 +15,6 @@ | |||
15 | .text | 15 | .text |
16 | .align 32 | 16 | .align 32 |
17 | 17 | ||
18 | .globl sparc64_vpte_patchme1 | ||
19 | .globl sparc64_vpte_patchme2 | ||
20 | /* | 18 | /* |
21 | * On a second level vpte miss, check whether the original fault is to the OBP | 19 | * On a second level vpte miss, check whether the original fault is to the OBP |
22 | * range (note that this is only possible for instruction miss, data misses to | 20 | * range (note that this is only possible for instruction miss, data misses to |
@@ -33,18 +31,17 @@ sparc64_vpte_nucleus: | |||
33 | */ | 31 | */ |
34 | sethi %hi(LOW_OBP_ADDRESS), %g5 | 32 | sethi %hi(LOW_OBP_ADDRESS), %g5 |
35 | cmp %g4, %g5 | 33 | cmp %g4, %g5 |
36 | blu,pn %xcc, sparc64_vpte_patchme1 | 34 | blu,pn %xcc, kern_vpte |
37 | mov 0x1, %g5 | 35 | mov 0x1, %g5 |
38 | sllx %g5, 32, %g5 | 36 | sllx %g5, 32, %g5 |
39 | cmp %g4, %g5 | 37 | cmp %g4, %g5 |
40 | blu,pn %xcc, obp_iaddr_patch | 38 | blu,pn %xcc, vpte_insn_obp |
41 | nop | 39 | nop |
42 | 40 | ||
43 | /* These two instructions are patched by paginig_init(). */ | 41 | /* These two instructions are patched by paginig_init(). */ |
44 | sparc64_vpte_patchme1: | 42 | kern_vpte: |
45 | sethi %hi(0), %g5 | 43 | sethi %hi(swapper_pgd_zero), %g5 |
46 | sparc64_vpte_patchme2: | 44 | lduw [%g5 + %lo(swapper_pgd_zero)], %g5 |
47 | or %g5, %lo(0), %g5 | ||
48 | 45 | ||
49 | /* With kernel PGD in %g5, branch back into dtlb_backend. */ | 46 | /* With kernel PGD in %g5, branch back into dtlb_backend. */ |
50 | ba,pt %xcc, sparc64_kpte_continue | 47 | ba,pt %xcc, sparc64_kpte_continue |
@@ -60,11 +57,9 @@ vpte_noent: | |||
60 | stxa %g4, [%g1 + %g1] ASI_DMMU | 57 | stxa %g4, [%g1 + %g1] ASI_DMMU |
61 | done | 58 | done |
62 | 59 | ||
63 | .globl obp_iaddr_patch | 60 | vpte_insn_obp: |
64 | obp_iaddr_patch: | 61 | sethi %hi(prom_pmd_phys), %g5 |
65 | /* These two instructions patched by inherit_prom_mappings(). */ | 62 | ldx [%g5 + %lo(prom_pmd_phys)], %g5 |
66 | sethi %hi(0), %g5 | ||
67 | or %g5, %lo(0), %g5 | ||
68 | 63 | ||
69 | /* Behave as if we are at TL0. */ | 64 | /* Behave as if we are at TL0. */ |
70 | wrpr %g0, 1, %tl | 65 | wrpr %g0, 1, %tl |
@@ -100,11 +95,9 @@ obp_iaddr_patch: | |||
100 | stxa %g5, [%g0] ASI_ITLB_DATA_IN | 95 | stxa %g5, [%g0] ASI_ITLB_DATA_IN |
101 | retry | 96 | retry |
102 | 97 | ||
103 | .globl obp_daddr_patch | 98 | kvmap_do_obp: |
104 | obp_daddr_patch: | 99 | sethi %hi(prom_pmd_phys), %g5 |
105 | /* These two instructions patched by inherit_prom_mappings(). */ | 100 | ldx [%g5 + %lo(prom_pmd_phys)], %g5 |
106 | sethi %hi(0), %g5 | ||
107 | or %g5, %lo(0), %g5 | ||
108 | 101 | ||
109 | /* Get PMD offset. */ | 102 | /* Get PMD offset. */ |
110 | srlx %g4, 23, %g6 | 103 | srlx %g4, 23, %g6 |
@@ -159,7 +152,7 @@ kvmap_check_obp: | |||
159 | mov 0x1, %g5 | 152 | mov 0x1, %g5 |
160 | sllx %g5, 32, %g5 | 153 | sllx %g5, 32, %g5 |
161 | cmp %g4, %g5 | 154 | cmp %g4, %g5 |
162 | blu,pn %xcc, obp_daddr_patch | 155 | blu,pn %xcc, kvmap_do_obp |
163 | nop | 156 | nop |
164 | 157 | ||
165 | kvmap_vmalloc_addr: | 158 | kvmap_vmalloc_addr: |
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index fdb1ebb308c9..aaf9a3eee997 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/seq_file.h> | 21 | #include <linux/seq_file.h> |
22 | #include <linux/kprobes.h> | 22 | #include <linux/kprobes.h> |
23 | #include <linux/cache.h> | ||
23 | 24 | ||
24 | #include <asm/head.h> | 25 | #include <asm/head.h> |
25 | #include <asm/system.h> | 26 | #include <asm/system.h> |
@@ -45,10 +46,10 @@ struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; | |||
45 | unsigned long *sparc64_valid_addr_bitmap; | 46 | unsigned long *sparc64_valid_addr_bitmap; |
46 | 47 | ||
47 | /* Ugly, but necessary... -DaveM */ | 48 | /* Ugly, but necessary... -DaveM */ |
48 | unsigned long phys_base; | 49 | unsigned long phys_base __read_mostly; |
49 | unsigned long kern_base; | 50 | unsigned long kern_base __read_mostly; |
50 | unsigned long kern_size; | 51 | unsigned long kern_size __read_mostly; |
51 | unsigned long pfn_base; | 52 | unsigned long pfn_base __read_mostly; |
52 | 53 | ||
53 | /* This is even uglier. We have a problem where the kernel may not be | 54 | /* This is even uglier. We have a problem where the kernel may not be |
54 | * located at phys_base. However, initial __alloc_bootmem() calls need to | 55 | * located at phys_base. However, initial __alloc_bootmem() calls need to |
@@ -73,7 +74,7 @@ extern unsigned long sparc_ramdisk_image64; | |||
73 | extern unsigned int sparc_ramdisk_image; | 74 | extern unsigned int sparc_ramdisk_image; |
74 | extern unsigned int sparc_ramdisk_size; | 75 | extern unsigned int sparc_ramdisk_size; |
75 | 76 | ||
76 | struct page *mem_map_zero; | 77 | struct page *mem_map_zero __read_mostly; |
77 | 78 | ||
78 | int bigkernel = 0; | 79 | int bigkernel = 0; |
79 | 80 | ||
@@ -318,6 +319,10 @@ extern void register_prom_callbacks(void); | |||
318 | /* Exported for SMP bootup purposes. */ | 319 | /* Exported for SMP bootup purposes. */ |
319 | unsigned long kern_locked_tte_data; | 320 | unsigned long kern_locked_tte_data; |
320 | 321 | ||
322 | /* Exported for kernel TLB miss handling in ktlb.S */ | ||
323 | unsigned long prom_pmd_phys __read_mostly; | ||
324 | unsigned int swapper_pgd_zero __read_mostly; | ||
325 | |||
321 | void __init early_pgtable_allocfail(char *type) | 326 | void __init early_pgtable_allocfail(char *type) |
322 | { | 327 | { |
323 | prom_printf("inherit_prom_mappings: Cannot alloc kernel %s.\n", type); | 328 | prom_printf("inherit_prom_mappings: Cannot alloc kernel %s.\n", type); |
@@ -364,7 +369,6 @@ static void inherit_prom_mappings(void) | |||
364 | pmd_t *pmdp; | 369 | pmd_t *pmdp; |
365 | pte_t *ptep; | 370 | pte_t *ptep; |
366 | int node, n, i, tsz; | 371 | int node, n, i, tsz; |
367 | extern unsigned int obp_iaddr_patch[2], obp_daddr_patch[2]; | ||
368 | 372 | ||
369 | node = prom_finddevice("/virtual-memory"); | 373 | node = prom_finddevice("/virtual-memory"); |
370 | n = prom_getproplen(node, "translations"); | 374 | n = prom_getproplen(node, "translations"); |
@@ -434,13 +438,7 @@ static void inherit_prom_mappings(void) | |||
434 | } | 438 | } |
435 | } | 439 | } |
436 | } | 440 | } |
437 | phys_page = __pa(prompmd); | 441 | prom_pmd_phys = __pa(prompmd); |
438 | obp_iaddr_patch[0] |= (phys_page >> 10); | ||
439 | obp_iaddr_patch[1] |= (phys_page & 0x3ff); | ||
440 | flushi((long)&obp_iaddr_patch[0]); | ||
441 | obp_daddr_patch[0] |= (phys_page >> 10); | ||
442 | obp_daddr_patch[1] |= (phys_page & 0x3ff); | ||
443 | flushi((long)&obp_daddr_patch[0]); | ||
444 | 442 | ||
445 | /* Now fixup OBP's idea about where we really are mapped. */ | 443 | /* Now fixup OBP's idea about where we really are mapped. */ |
446 | prom_printf("Remapping the kernel... "); | 444 | prom_printf("Remapping the kernel... "); |
@@ -1407,8 +1405,6 @@ static unsigned long last_valid_pfn; | |||
1407 | void __init paging_init(void) | 1405 | void __init paging_init(void) |
1408 | { | 1406 | { |
1409 | extern pmd_t swapper_pmd_dir[1024]; | 1407 | extern pmd_t swapper_pmd_dir[1024]; |
1410 | extern unsigned int sparc64_vpte_patchme1[1]; | ||
1411 | extern unsigned int sparc64_vpte_patchme2[1]; | ||
1412 | unsigned long alias_base = kern_base + PAGE_OFFSET; | 1408 | unsigned long alias_base = kern_base + PAGE_OFFSET; |
1413 | unsigned long second_alias_page = 0; | 1409 | unsigned long second_alias_page = 0; |
1414 | unsigned long pt, flags, end_pfn, pages_avail; | 1410 | unsigned long pt, flags, end_pfn, pages_avail; |
@@ -1502,11 +1498,7 @@ void __init paging_init(void) | |||
1502 | pud_set(pud_offset(&swapper_pg_dir[0], 0), | 1498 | pud_set(pud_offset(&swapper_pg_dir[0], 0), |
1503 | swapper_pmd_dir + (shift / sizeof(pgd_t))); | 1499 | swapper_pmd_dir + (shift / sizeof(pgd_t))); |
1504 | 1500 | ||
1505 | sparc64_vpte_patchme1[0] |= | 1501 | swapper_pgd_zero = pgd_val(init_mm.pgd[0]); |
1506 | (((unsigned long)pgd_val(init_mm.pgd[0])) >> 10); | ||
1507 | sparc64_vpte_patchme2[0] |= | ||
1508 | (((unsigned long)pgd_val(init_mm.pgd[0])) & 0x3ff); | ||
1509 | flushi((long)&sparc64_vpte_patchme1[0]); | ||
1510 | 1502 | ||
1511 | /* Setup bootmem... */ | 1503 | /* Setup bootmem... */ |
1512 | pages_avail = 0; | 1504 | pages_avail = 0; |