|
@@ -133,6 +133,12 @@ extern unsigned int sparc_ramdisk_size;
|
|
|
|
|
|
struct page *mem_map_zero __read_mostly;
|
|
|
|
|
|
+unsigned int sparc64_highest_unlocked_tlb_ent __read_mostly;
|
|
|
+
|
|
|
+unsigned long sparc64_kern_pri_context __read_mostly;
|
|
|
+unsigned long sparc64_kern_pri_nuc_bits __read_mostly;
|
|
|
+unsigned long sparc64_kern_sec_context __read_mostly;
|
|
|
+
|
|
|
int bigkernel = 0;
|
|
|
|
|
|
/* XXX Tune this... */
|
|
@@ -362,6 +368,7 @@ struct linux_prom_translation {
|
|
|
unsigned long data;
|
|
|
};
|
|
|
static struct linux_prom_translation prom_trans[512] __initdata;
|
|
|
+static unsigned int prom_trans_ents __initdata;
|
|
|
|
|
|
extern unsigned long prom_boot_page;
|
|
|
extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle);
|
|
@@ -375,57 +382,7 @@ unsigned long kern_locked_tte_data;
|
|
|
unsigned long prom_pmd_phys __read_mostly;
|
|
|
unsigned int swapper_pgd_zero __read_mostly;
|
|
|
|
|
|
-/* Allocate power-of-2 aligned chunks from the end of the
|
|
|
- * kernel image. Return physical address.
|
|
|
- */
|
|
|
-static inline unsigned long early_alloc_phys(unsigned long size)
|
|
|
-{
|
|
|
- unsigned long base;
|
|
|
-
|
|
|
- BUILD_BUG_ON(size & (size - 1));
|
|
|
-
|
|
|
- kern_size = (kern_size + (size - 1)) & ~(size - 1);
|
|
|
- base = kern_base + kern_size;
|
|
|
- kern_size += size;
|
|
|
-
|
|
|
- return base;
|
|
|
-}
|
|
|
-
|
|
|
-static inline unsigned long load_phys32(unsigned long pa)
|
|
|
-{
|
|
|
- unsigned long val;
|
|
|
-
|
|
|
- __asm__ __volatile__("lduwa [%1] %2, %0"
|
|
|
- : "=&r" (val)
|
|
|
- : "r" (pa), "i" (ASI_PHYS_USE_EC));
|
|
|
-
|
|
|
- return val;
|
|
|
-}
|
|
|
-
|
|
|
-static inline unsigned long load_phys64(unsigned long pa)
|
|
|
-{
|
|
|
- unsigned long val;
|
|
|
-
|
|
|
- __asm__ __volatile__("ldxa [%1] %2, %0"
|
|
|
- : "=&r" (val)
|
|
|
- : "r" (pa), "i" (ASI_PHYS_USE_EC));
|
|
|
-
|
|
|
- return val;
|
|
|
-}
|
|
|
-
|
|
|
-static inline void store_phys32(unsigned long pa, unsigned long val)
|
|
|
-{
|
|
|
- __asm__ __volatile__("stwa %0, [%1] %2"
|
|
|
- : /* no outputs */
|
|
|
- : "r" (val), "r" (pa), "i" (ASI_PHYS_USE_EC));
|
|
|
-}
|
|
|
-
|
|
|
-static inline void store_phys64(unsigned long pa, unsigned long val)
|
|
|
-{
|
|
|
- __asm__ __volatile__("stxa %0, [%1] %2"
|
|
|
- : /* no outputs */
|
|
|
- : "r" (val), "r" (pa), "i" (ASI_PHYS_USE_EC));
|
|
|
-}
|
|
|
+static pmd_t *prompmd __read_mostly;
|
|
|
|
|
|
#define BASE_PAGE_SIZE 8192
|
|
|
|
|
@@ -435,34 +392,28 @@ static inline void store_phys64(unsigned long pa, unsigned long val)
|
|
|
*/
|
|
|
unsigned long prom_virt_to_phys(unsigned long promva, int *error)
|
|
|
{
|
|
|
- unsigned long pmd_phys = (prom_pmd_phys +
|
|
|
- ((promva >> 23) & 0x7ff) * sizeof(pmd_t));
|
|
|
- unsigned long pte_phys;
|
|
|
- pmd_t pmd_ent;
|
|
|
- pte_t pte_ent;
|
|
|
+ pmd_t *pmdp = prompmd + ((promva >> 23) & 0x7ff);
|
|
|
+ pte_t *ptep;
|
|
|
unsigned long base;
|
|
|
|
|
|
- pmd_val(pmd_ent) = load_phys32(pmd_phys);
|
|
|
- if (pmd_none(pmd_ent)) {
|
|
|
+ if (pmd_none(*pmdp)) {
|
|
|
if (error)
|
|
|
*error = 1;
|
|
|
return 0;
|
|
|
}
|
|
|
-
|
|
|
- pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL;
|
|
|
- pte_phys += ((promva >> 13) & 0x3ff) * sizeof(pte_t);
|
|
|
- pte_val(pte_ent) = load_phys64(pte_phys);
|
|
|
- if (!pte_present(pte_ent)) {
|
|
|
+ ptep = (pte_t *)__pmd_page(*pmdp) + ((promva >> 13) & 0x3ff);
|
|
|
+ if (!pte_present(*ptep)) {
|
|
|
if (error)
|
|
|
*error = 1;
|
|
|
return 0;
|
|
|
}
|
|
|
if (error) {
|
|
|
*error = 0;
|
|
|
- return pte_val(pte_ent);
|
|
|
+ return pte_val(*ptep);
|
|
|
}
|
|
|
- base = pte_val(pte_ent) & _PAGE_PADDR;
|
|
|
- return (base + (promva & (BASE_PAGE_SIZE - 1)));
|
|
|
+ base = pte_val(*ptep) & _PAGE_PADDR;
|
|
|
+
|
|
|
+ return base + (promva & (BASE_PAGE_SIZE - 1));
|
|
|
}
|
|
|
|
|
|
/* The obp translations are saved based on 8k pagesize, since obp can
|
|
@@ -475,25 +426,20 @@ static void __init build_obp_range(unsigned long start, unsigned long end, unsig
|
|
|
unsigned long vaddr;
|
|
|
|
|
|
for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) {
|
|
|
- unsigned long val, pte_phys, pmd_phys;
|
|
|
- pmd_t pmd_ent;
|
|
|
- int i;
|
|
|
-
|
|
|
- pmd_phys = (prom_pmd_phys +
|
|
|
- (((vaddr >> 23) & 0x7ff) * sizeof(pmd_t)));
|
|
|
- pmd_val(pmd_ent) = load_phys32(pmd_phys);
|
|
|
- if (pmd_none(pmd_ent)) {
|
|
|
- pte_phys = early_alloc_phys(BASE_PAGE_SIZE);
|
|
|
-
|
|
|
- for (i = 0; i < BASE_PAGE_SIZE / sizeof(pte_t); i++)
|
|
|
- store_phys64(pte_phys+i*sizeof(pte_t),0);
|
|
|
+ unsigned long val;
|
|
|
+ pmd_t *pmd;
|
|
|
+ pte_t *pte;
|
|
|
|
|
|
- pmd_val(pmd_ent) = pte_phys >> 11UL;
|
|
|
- store_phys32(pmd_phys, pmd_val(pmd_ent));
|
|
|
+ pmd = prompmd + ((vaddr >> 23) & 0x7ff);
|
|
|
+ if (pmd_none(*pmd)) {
|
|
|
+ pte = __alloc_bootmem(BASE_PAGE_SIZE, BASE_PAGE_SIZE,
|
|
|
+ PAGE_SIZE);
|
|
|
+ if (!pte)
|
|
|
+ prom_halt();
|
|
|
+ memset(pte, 0, BASE_PAGE_SIZE);
|
|
|
+ pmd_set(pmd, pte);
|
|
|
}
|
|
|
-
|
|
|
- pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL;
|
|
|
- pte_phys += (((vaddr >> 13) & 0x3ff) * sizeof(pte_t));
|
|
|
+ pte = (pte_t *) __pmd_page(*pmd) + ((vaddr >> 13) & 0x3ff);
|
|
|
|
|
|
val = data;
|
|
|
|
|
@@ -501,7 +447,8 @@ static void __init build_obp_range(unsigned long start, unsigned long end, unsig
|
|
|
if (tlb_type == spitfire)
|
|
|
val &= ~0x0003fe0000000000UL;
|
|
|
|
|
|
- store_phys64(pte_phys, val | _PAGE_MODIFIED);
|
|
|
+ set_pte_at(&init_mm, vaddr, pte,
|
|
|
+ __pte(val | _PAGE_MODIFIED));
|
|
|
|
|
|
data += BASE_PAGE_SIZE;
|
|
|
}
|
|
@@ -514,13 +461,17 @@ static inline int in_obp_range(unsigned long vaddr)
|
|
|
}
|
|
|
|
|
|
#define OBP_PMD_SIZE 2048
|
|
|
-static void __init build_obp_pgtable(int prom_trans_ents)
|
|
|
+static void __init build_obp_pgtable(void)
|
|
|
{
|
|
|
unsigned long i;
|
|
|
|
|
|
- prom_pmd_phys = early_alloc_phys(OBP_PMD_SIZE);
|
|
|
- for (i = 0; i < OBP_PMD_SIZE; i += 4)
|
|
|
- store_phys32(prom_pmd_phys + i, 0);
|
|
|
+ prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, PAGE_SIZE);
|
|
|
+ if (!prompmd)
|
|
|
+ prom_halt();
|
|
|
+
|
|
|
+ memset(prompmd, 0, OBP_PMD_SIZE);
|
|
|
+
|
|
|
+ prom_pmd_phys = __pa(prompmd);
|
|
|
|
|
|
for (i = 0; i < prom_trans_ents; i++) {
|
|
|
unsigned long start, end;
|
|
@@ -540,7 +491,7 @@ static void __init build_obp_pgtable(int prom_trans_ents)
|
|
|
/* Read OBP translations property into 'prom_trans[]'.
|
|
|
* Return the number of entries.
|
|
|
*/
|
|
|
-static int __init read_obp_translations(void)
|
|
|
+static void __init read_obp_translations(void)
|
|
|
{
|
|
|
int n, node;
|
|
|
|
|
@@ -561,8 +512,10 @@ static int __init read_obp_translations(void)
|
|
|
prom_printf("prom_mappings: Couldn't get property.\n");
|
|
|
prom_halt();
|
|
|
}
|
|
|
+
|
|
|
n = n / sizeof(struct linux_prom_translation);
|
|
|
- return n;
|
|
|
+
|
|
|
+ prom_trans_ents = n;
|
|
|
}
|
|
|
|
|
|
static void __init remap_kernel(void)
|
|
@@ -582,28 +535,38 @@ static void __init remap_kernel(void)
|
|
|
prom_dtlb_load(tlb_ent, tte_data, tte_vaddr);
|
|
|
prom_itlb_load(tlb_ent, tte_data, tte_vaddr);
|
|
|
if (bigkernel) {
|
|
|
- prom_dtlb_load(tlb_ent - 1,
|
|
|
+ tlb_ent -= 1;
|
|
|
+ prom_dtlb_load(tlb_ent,
|
|
|
tte_data + 0x400000,
|
|
|
tte_vaddr + 0x400000);
|
|
|
- prom_itlb_load(tlb_ent - 1,
|
|
|
+ prom_itlb_load(tlb_ent,
|
|
|
tte_data + 0x400000,
|
|
|
tte_vaddr + 0x400000);
|
|
|
}
|
|
|
+ sparc64_highest_unlocked_tlb_ent = tlb_ent - 1;
|
|
|
+ if (tlb_type == cheetah_plus) {
|
|
|
+ sparc64_kern_pri_context = (CTX_CHEETAH_PLUS_CTX0 |
|
|
|
+ CTX_CHEETAH_PLUS_NUC);
|
|
|
+ sparc64_kern_pri_nuc_bits = CTX_CHEETAH_PLUS_NUC;
|
|
|
+ sparc64_kern_sec_context = CTX_CHEETAH_PLUS_CTX0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-static void __init inherit_prom_mappings(void)
|
|
|
-{
|
|
|
- int n;
|
|
|
|
|
|
- n = read_obp_translations();
|
|
|
- build_obp_pgtable(n);
|
|
|
+static void __init inherit_prom_mappings_pre(void)
|
|
|
+{
|
|
|
+ read_obp_translations();
|
|
|
|
|
|
/* Now fixup OBP's idea about where we really are mapped. */
|
|
|
prom_printf("Remapping the kernel... ");
|
|
|
remap_kernel();
|
|
|
|
|
|
prom_printf("done.\n");
|
|
|
+}
|
|
|
|
|
|
+static void __init inherit_prom_mappings_post(void)
|
|
|
+{
|
|
|
+ build_obp_pgtable();
|
|
|
register_prom_callbacks();
|
|
|
}
|
|
|
|
|
@@ -788,8 +751,8 @@ void inherit_locked_prom_mappings(int save_p)
|
|
|
}
|
|
|
}
|
|
|
if (tlb_type == spitfire) {
|
|
|
- int high = SPITFIRE_HIGHEST_LOCKED_TLBENT - bigkernel;
|
|
|
- for (i = 0; i < high; i++) {
|
|
|
+ int high = sparc64_highest_unlocked_tlb_ent;
|
|
|
+ for (i = 0; i <= high; i++) {
|
|
|
unsigned long data;
|
|
|
|
|
|
/* Spitfire Errata #32 workaround */
|
|
@@ -877,9 +840,9 @@ void inherit_locked_prom_mappings(int save_p)
|
|
|
}
|
|
|
}
|
|
|
} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
|
|
|
- int high = CHEETAH_HIGHEST_LOCKED_TLBENT - bigkernel;
|
|
|
+ int high = sparc64_highest_unlocked_tlb_ent;
|
|
|
|
|
|
- for (i = 0; i < high; i++) {
|
|
|
+ for (i = 0; i <= high; i++) {
|
|
|
unsigned long data;
|
|
|
|
|
|
data = cheetah_get_ldtlb_data(i);
|
|
@@ -1556,8 +1519,7 @@ void __init paging_init(void)
|
|
|
|
|
|
swapper_pgd_zero = pgd_val(swapper_pg_dir[0]);
|
|
|
|
|
|
- /* Inherit non-locked OBP mappings. */
|
|
|
- inherit_prom_mappings();
|
|
|
+ inherit_prom_mappings_pre();
|
|
|
|
|
|
/* Ok, we can use our TLB miss and window trap handlers safely.
|
|
|
* We need to do a quick peek here to see if we are on StarFire
|
|
@@ -1568,15 +1530,23 @@ void __init paging_init(void)
|
|
|
extern void setup_tba(int);
|
|
|
setup_tba(this_is_starfire);
|
|
|
}
|
|
|
-
|
|
|
- inherit_locked_prom_mappings(1);
|
|
|
-
|
|
|
__flush_tlb_all();
|
|
|
|
|
|
+ /* Everything from this point forward, until we are done with
|
|
|
+ * inherit_prom_mappings_post(), must complete successfully
|
|
|
+ * without calling into the firmware. The firwmare page tables
|
|
|
+ * have not been built, but we are running on the Linux kernel's
|
|
|
+ * trap table.
|
|
|
+ */
|
|
|
+
|
|
|
/* Setup bootmem... */
|
|
|
pages_avail = 0;
|
|
|
last_valid_pfn = end_pfn = bootmem_init(&pages_avail);
|
|
|
|
|
|
+ inherit_prom_mappings_post();
|
|
|
+
|
|
|
+ inherit_locked_prom_mappings(1);
|
|
|
+
|
|
|
#ifdef CONFIG_DEBUG_PAGEALLOC
|
|
|
kernel_physical_mapping_init();
|
|
|
#endif
|