[SPARC64]: Break up inherit_prom_mappings() into it's constituent parts.
This thing was just a huge monolithic mess, so chop it up. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
b206fc4c09
commit
405599bd98
|
@ -362,53 +362,25 @@ unsigned long prom_virt_to_phys(unsigned long promva, int *error)
|
||||||
return(base + (promva & (BASE_PAGE_SIZE - 1)));
|
return(base + (promva & (BASE_PAGE_SIZE - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inherit_prom_mappings(void)
|
static inline int in_obp_range(unsigned long vaddr)
|
||||||
{
|
{
|
||||||
unsigned long phys_page, tte_vaddr, tte_data;
|
return (vaddr >= LOW_OBP_ADDRESS &&
|
||||||
void (*remap_func)(unsigned long, unsigned long, int);
|
vaddr < HI_OBP_ADDRESS);
|
||||||
pmd_t *pmdp;
|
}
|
||||||
pte_t *ptep;
|
|
||||||
int node, n, i, tsz;
|
|
||||||
|
|
||||||
node = prom_finddevice("/virtual-memory");
|
/* The obp translations are saved based on 8k pagesize, since obp can
|
||||||
n = prom_getproplen(node, "translations");
|
* use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS ->
|
||||||
if (n == 0 || n == -1) {
|
* HI_OBP_ADDRESS range are handled in entry.S and do not use the vpte
|
||||||
prom_printf("prom_mappings: Couldn't get size.\n");
|
* scheme (also, see rant in inherit_locked_prom_mappings()).
|
||||||
prom_halt();
|
|
||||||
}
|
|
||||||
n += 24 * sizeof(struct linux_prom_translation);
|
|
||||||
if (n > sizeof(prom_trans)) {
|
|
||||||
prom_printf("prom_mappings: prom_trans too small, "
|
|
||||||
"need %Zd bytes\n", n);
|
|
||||||
prom_halt();
|
|
||||||
}
|
|
||||||
tsz = n;
|
|
||||||
if ((n = prom_getproperty(node, "translations",
|
|
||||||
(char *)&prom_trans[0], tsz)) == -1) {
|
|
||||||
prom_printf("prom_mappings: Couldn't get property.\n");
|
|
||||||
prom_halt();
|
|
||||||
}
|
|
||||||
n = n / sizeof(struct linux_prom_translation);
|
|
||||||
|
|
||||||
/* The obp translations are saved based on 8k pagesize, since obp
|
|
||||||
* can use a mixture of pagesizes. Misses to the 0xf0000000 ->
|
|
||||||
* 0x100000000, ie obp range, are handled in entry.S and do not
|
|
||||||
* use the vpte scheme (see rant: inherit_locked_prom_mappings).
|
|
||||||
*/
|
*/
|
||||||
#define OBP_PMD_SIZE 2048
|
static void build_obp_range(unsigned long start, unsigned long end, unsigned long data)
|
||||||
prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, bootmap_base);
|
{
|
||||||
if (prompmd == NULL)
|
|
||||||
early_pgtable_allocfail("pmd");
|
|
||||||
memset(prompmd, 0, OBP_PMD_SIZE);
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
unsigned long vaddr;
|
unsigned long vaddr;
|
||||||
|
|
||||||
if (prom_trans[i].virt >= LOW_OBP_ADDRESS && prom_trans[i].virt < HI_OBP_ADDRESS) {
|
for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) {
|
||||||
for (vaddr = prom_trans[i].virt;
|
|
||||||
((vaddr < prom_trans[i].virt + prom_trans[i].size) &&
|
|
||||||
(vaddr < HI_OBP_ADDRESS));
|
|
||||||
vaddr += BASE_PAGE_SIZE) {
|
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
|
pmd_t *pmdp;
|
||||||
|
pte_t *ptep;
|
||||||
|
|
||||||
pmdp = prompmd + ((vaddr >> 23) & 0x7ff);
|
pmdp = prompmd + ((vaddr >> 23) & 0x7ff);
|
||||||
if (pmd_none(*pmdp)) {
|
if (pmd_none(*pmdp)) {
|
||||||
|
@ -423,7 +395,7 @@ static void inherit_prom_mappings(void)
|
||||||
ptep = (pte_t *)__pmd_page(*pmdp) +
|
ptep = (pte_t *)__pmd_page(*pmdp) +
|
||||||
((vaddr >> 13) & 0x3ff);
|
((vaddr >> 13) & 0x3ff);
|
||||||
|
|
||||||
val = prom_trans[i].data;
|
val = data;
|
||||||
|
|
||||||
/* Clear diag TTE bits. */
|
/* Clear diag TTE bits. */
|
||||||
if (tlb_type == spitfire)
|
if (tlb_type == spitfire)
|
||||||
|
@ -431,15 +403,66 @@ static void inherit_prom_mappings(void)
|
||||||
|
|
||||||
set_pte_at(&init_mm, vaddr,
|
set_pte_at(&init_mm, vaddr,
|
||||||
ptep, __pte(val | _PAGE_MODIFIED));
|
ptep, __pte(val | _PAGE_MODIFIED));
|
||||||
prom_trans[i].data += BASE_PAGE_SIZE;
|
data += BASE_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define OBP_PMD_SIZE 2048
|
||||||
|
static void build_obp_pgtable(int prom_trans_ents)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE,
|
||||||
|
bootmap_base);
|
||||||
|
if (prompmd == NULL)
|
||||||
|
early_pgtable_allocfail("pmd");
|
||||||
|
memset(prompmd, 0, OBP_PMD_SIZE);
|
||||||
|
for (i = 0; i < prom_trans_ents; i++) {
|
||||||
|
unsigned long start, end;
|
||||||
|
|
||||||
|
if (!in_obp_range(prom_trans[i].virt))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
start = prom_trans[i].virt;
|
||||||
|
end = start + prom_trans[i].size;
|
||||||
|
if (end > HI_OBP_ADDRESS)
|
||||||
|
end = HI_OBP_ADDRESS;
|
||||||
|
|
||||||
|
build_obp_range(start, end, prom_trans[i].data);
|
||||||
}
|
}
|
||||||
prom_pmd_phys = __pa(prompmd);
|
prom_pmd_phys = __pa(prompmd);
|
||||||
|
}
|
||||||
|
|
||||||
/* Now fixup OBP's idea about where we really are mapped. */
|
/* Read OBP translations property into 'prom_trans[]'.
|
||||||
prom_printf("Remapping the kernel... ");
|
* Return the number of entries.
|
||||||
|
*/
|
||||||
|
static int read_obp_translations(void)
|
||||||
|
{
|
||||||
|
int n, node;
|
||||||
|
|
||||||
|
node = prom_finddevice("/virtual-memory");
|
||||||
|
n = prom_getproplen(node, "translations");
|
||||||
|
if (unlikely(n == 0 || n == -1)) {
|
||||||
|
prom_printf("prom_mappings: Couldn't get size.\n");
|
||||||
|
prom_halt();
|
||||||
|
}
|
||||||
|
if (unlikely(n > sizeof(prom_trans))) {
|
||||||
|
prom_printf("prom_mappings: Size %Zd is too big.\n", n);
|
||||||
|
prom_halt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((n = prom_getproperty(node, "translations",
|
||||||
|
(char *)&prom_trans[0],
|
||||||
|
sizeof(prom_trans))) == -1) {
|
||||||
|
prom_printf("prom_mappings: Couldn't get property.\n");
|
||||||
|
prom_halt();
|
||||||
|
}
|
||||||
|
n = n / sizeof(struct linux_prom_translation);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void early_spitfire_errata32(void)
|
||||||
|
{
|
||||||
/* Spitfire Errata #32 workaround */
|
/* Spitfire Errata #32 workaround */
|
||||||
/* NOTE: Using plain zero for the context value is
|
/* NOTE: Using plain zero for the context value is
|
||||||
* correct here, we are not using the Linux trap
|
* correct here, we are not using the Linux trap
|
||||||
|
@ -449,23 +472,13 @@ static void inherit_prom_mappings(void)
|
||||||
__asm__ __volatile__("stxa %0, [%1] %2\n\t"
|
__asm__ __volatile__("stxa %0, [%1] %2\n\t"
|
||||||
"flush %%g6"
|
"flush %%g6"
|
||||||
: /* No outputs */
|
: /* No outputs */
|
||||||
: "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
|
: "r" (0), "r" (PRIMARY_CONTEXT),
|
||||||
|
"i" (ASI_DMMU));
|
||||||
|
}
|
||||||
|
|
||||||
switch (tlb_type) {
|
static void lock_remap_func_page(unsigned long phys_page)
|
||||||
default:
|
{
|
||||||
case spitfire:
|
unsigned long tte_data = (phys_page | pgprot_val(PAGE_KERNEL));
|
||||||
phys_page = spitfire_get_dtlb_data(sparc64_highest_locked_tlbent());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case cheetah:
|
|
||||||
case cheetah_plus:
|
|
||||||
phys_page = cheetah_get_litlb_data(sparc64_highest_locked_tlbent());
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
phys_page &= _PAGE_PADDR;
|
|
||||||
phys_page += ((unsigned long)&prom_boot_page -
|
|
||||||
(unsigned long)KERNBASE);
|
|
||||||
|
|
||||||
if (tlb_type == spitfire) {
|
if (tlb_type == spitfire) {
|
||||||
/* Lock this into i/d tlb entry 59 */
|
/* Lock this into i/d tlb entry 59 */
|
||||||
|
@ -478,13 +491,12 @@ static void inherit_prom_mappings(void)
|
||||||
"stxa %0, [%1] %6\n\t"
|
"stxa %0, [%1] %6\n\t"
|
||||||
"membar #Sync\n\t"
|
"membar #Sync\n\t"
|
||||||
"flush %%g6"
|
"flush %%g6"
|
||||||
: : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP |
|
: /* no outputs */
|
||||||
_PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W),
|
: "r" (tte_data), "r" (59 << 3), "r" (TLB_TAG_ACCESS),
|
||||||
"r" (59 << 3), "r" (TLB_TAG_ACCESS),
|
|
||||||
"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
|
"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
|
||||||
"i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
|
"i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
|
||||||
: "memory");
|
: "memory");
|
||||||
} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
|
} else {
|
||||||
/* Lock this into i/d tlb-0 entry 11 */
|
/* Lock this into i/d tlb-0 entry 11 */
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
"stxa %%g0, [%2] %3\n\t"
|
"stxa %%g0, [%2] %3\n\t"
|
||||||
|
@ -495,87 +507,80 @@ static void inherit_prom_mappings(void)
|
||||||
"stxa %0, [%1] %6\n\t"
|
"stxa %0, [%1] %6\n\t"
|
||||||
"membar #Sync\n\t"
|
"membar #Sync\n\t"
|
||||||
"flush %%g6"
|
"flush %%g6"
|
||||||
: : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP |
|
: /* no outputs */
|
||||||
_PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W),
|
: "r" (tte_data), "r" ((0 << 16) | (11 << 3)),
|
||||||
"r" ((0 << 16) | (11 << 3)), "r" (TLB_TAG_ACCESS),
|
"r" (TLB_TAG_ACCESS), "i" (ASI_DMMU),
|
||||||
"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
|
"i" (ASI_DTLB_DATA_ACCESS), "i" (ASI_IMMU),
|
||||||
"i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
|
"i" (ASI_ITLB_DATA_ACCESS)
|
||||||
: "memory");
|
: "memory");
|
||||||
} else {
|
|
||||||
/* Implement me :-) */
|
|
||||||
BUG();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remap_kernel(void)
|
||||||
|
{
|
||||||
|
unsigned long phys_page, tte_vaddr, tte_data;
|
||||||
|
void (*remap_func)(unsigned long, unsigned long, int);
|
||||||
|
int tlb_ent = sparc64_highest_locked_tlbent();
|
||||||
|
|
||||||
|
early_spitfire_errata32();
|
||||||
|
|
||||||
|
if (tlb_type == spitfire)
|
||||||
|
phys_page = spitfire_get_dtlb_data(tlb_ent);
|
||||||
|
else
|
||||||
|
phys_page = cheetah_get_ldtlb_data(tlb_ent);
|
||||||
|
|
||||||
|
phys_page &= _PAGE_PADDR;
|
||||||
|
phys_page += ((unsigned long)&prom_boot_page -
|
||||||
|
(unsigned long)KERNBASE);
|
||||||
|
|
||||||
|
lock_remap_func_page(phys_page);
|
||||||
|
|
||||||
tte_vaddr = (unsigned long) KERNBASE;
|
tte_vaddr = (unsigned long) KERNBASE;
|
||||||
|
|
||||||
/* Spitfire Errata #32 workaround */
|
early_spitfire_errata32();
|
||||||
/* NOTE: Using plain zero for the context value is
|
|
||||||
* correct here, we are not using the Linux trap
|
|
||||||
* tables yet so we should not use the special
|
|
||||||
* UltraSPARC-III+ page size encodings yet.
|
|
||||||
*/
|
|
||||||
__asm__ __volatile__("stxa %0, [%1] %2\n\t"
|
|
||||||
"flush %%g6"
|
|
||||||
: /* No outputs */
|
|
||||||
: "r" (0),
|
|
||||||
"r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
|
|
||||||
|
|
||||||
if (tlb_type == spitfire)
|
if (tlb_type == spitfire)
|
||||||
tte_data = spitfire_get_dtlb_data(sparc64_highest_locked_tlbent());
|
tte_data = spitfire_get_dtlb_data(tlb_ent);
|
||||||
else
|
else
|
||||||
tte_data = cheetah_get_ldtlb_data(sparc64_highest_locked_tlbent());
|
tte_data = cheetah_get_ldtlb_data(tlb_ent);
|
||||||
|
|
||||||
kern_locked_tte_data = tte_data;
|
kern_locked_tte_data = tte_data;
|
||||||
|
|
||||||
remap_func = (void *) ((unsigned long) &prom_remap -
|
remap_func = (void *) ((unsigned long) &prom_remap -
|
||||||
(unsigned long) &prom_boot_page);
|
(unsigned long) &prom_boot_page);
|
||||||
|
|
||||||
|
early_spitfire_errata32();
|
||||||
|
|
||||||
/* Spitfire Errata #32 workaround */
|
phys_page = tte_data & _PAGE_PADDR;
|
||||||
/* NOTE: Using plain zero for the context value is
|
remap_func(phys_page, KERNBASE, prom_get_mmu_ihandle());
|
||||||
* correct here, we are not using the Linux trap
|
|
||||||
* tables yet so we should not use the special
|
|
||||||
* UltraSPARC-III+ page size encodings yet.
|
|
||||||
*/
|
|
||||||
__asm__ __volatile__("stxa %0, [%1] %2\n\t"
|
|
||||||
"flush %%g6"
|
|
||||||
: /* No outputs */
|
|
||||||
: "r" (0),
|
|
||||||
"r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
|
|
||||||
|
|
||||||
remap_func((tlb_type == spitfire ?
|
|
||||||
(spitfire_get_dtlb_data(sparc64_highest_locked_tlbent()) & _PAGE_PADDR) :
|
|
||||||
(cheetah_get_litlb_data(sparc64_highest_locked_tlbent()) & _PAGE_PADDR)),
|
|
||||||
(unsigned long) KERNBASE,
|
|
||||||
prom_get_mmu_ihandle());
|
|
||||||
|
|
||||||
if (bigkernel)
|
if (bigkernel)
|
||||||
remap_func(((tte_data + 0x400000) & _PAGE_PADDR),
|
remap_func(phys_page + 0x400000,
|
||||||
(unsigned long) KERNBASE + 0x400000, prom_get_mmu_ihandle());
|
KERNBASE + 0x400000,
|
||||||
|
prom_get_mmu_ihandle());
|
||||||
|
|
||||||
/* Flush out that temporary mapping. */
|
/* Flush out that temporary mapping. */
|
||||||
spitfire_flush_dtlb_nucleus_page(0x0);
|
spitfire_flush_dtlb_nucleus_page(0x0);
|
||||||
spitfire_flush_itlb_nucleus_page(0x0);
|
spitfire_flush_itlb_nucleus_page(0x0);
|
||||||
|
|
||||||
/* Now lock us back into the TLBs via OBP. */
|
/* Now lock us back into the TLBs via OBP. */
|
||||||
prom_dtlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr);
|
prom_dtlb_load(tlb_ent, tte_data, tte_vaddr);
|
||||||
prom_itlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr);
|
prom_itlb_load(tlb_ent, tte_data, tte_vaddr);
|
||||||
if (bigkernel) {
|
if (bigkernel) {
|
||||||
prom_dtlb_load(sparc64_highest_locked_tlbent()-1, tte_data + 0x400000,
|
prom_dtlb_load(tlb_ent - 1,
|
||||||
|
tte_data + 0x400000,
|
||||||
tte_vaddr + 0x400000);
|
tte_vaddr + 0x400000);
|
||||||
prom_itlb_load(sparc64_highest_locked_tlbent()-1, tte_data + 0x400000,
|
prom_itlb_load(tlb_ent - 1,
|
||||||
|
tte_data + 0x400000,
|
||||||
tte_vaddr + 0x400000);
|
tte_vaddr + 0x400000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-read translations property. */
|
|
||||||
if ((n = prom_getproperty(node, "translations",
|
|
||||||
(char *)&prom_trans[0], tsz)) == -1) {
|
|
||||||
prom_printf("prom_mappings: Can't reread prom_trans.\n");
|
|
||||||
prom_halt();
|
|
||||||
}
|
}
|
||||||
n = n / sizeof(struct linux_prom_translation);
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
static void readjust_prom_translations(void)
|
||||||
|
{
|
||||||
|
int nents, i;
|
||||||
|
|
||||||
|
nents = read_obp_translations();
|
||||||
|
for (i = 0; i < nents; i++) {
|
||||||
unsigned long vaddr = prom_trans[i].virt;
|
unsigned long vaddr = prom_trans[i].virt;
|
||||||
unsigned long size = prom_trans[i].size;
|
unsigned long size = prom_trans[i].size;
|
||||||
|
|
||||||
|
@ -601,6 +606,20 @@ static void inherit_prom_mappings(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void inherit_prom_mappings(void)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = read_obp_translations();
|
||||||
|
build_obp_pgtable(n);
|
||||||
|
|
||||||
|
/* Now fixup OBP's idea about where we really are mapped. */
|
||||||
|
prom_printf("Remapping the kernel... ");
|
||||||
|
remap_kernel();
|
||||||
|
|
||||||
|
readjust_prom_translations();
|
||||||
|
|
||||||
prom_printf("done.\n");
|
prom_printf("done.\n");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue