Commit c4bce90e authored by David S. Miller's avatar David S. Miller

[SPARC64]: Deal with PTE layout differences in SUN4V.

Yes, you heard it right, they changed the PTE layout for
SUN4V.  Ho hum...

This is the simple and inefficient way to support this.
It'll get optimized, don't worry.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 490384e7
......@@ -6,9 +6,10 @@
nop ! Delay slot (fill me)
TSB_LOAD_QUAD(%g1, %g4) ! Load TSB entry
cmp %g4, %g6 ! Compare TAG
sethi %hi(_PAGE_EXEC), %g4 ! Setup exec check
sethi %hi(PAGE_EXEC), %g4 ! Setup exec check
/* ITLB ** ICACHE line 2: TSB compare and TLB load */
ldx [%g4 + %lo(PAGE_EXEC)], %g4
bne,pn %xcc, tsb_miss_itlb ! Miss
mov FAULT_CODE_ITLB, %g3
andcc %g5, %g4, %g0 ! Executable?
......@@ -16,7 +17,6 @@
nop ! Delay slot, fill me
stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load TLB
retry ! Trap done
nop
/* ITLB ** ICACHE line 3: */
nop
......
......@@ -131,16 +131,8 @@ kvmap_dtlb_4v:
brgez,pn %g4, kvmap_dtlb_nonlinear
nop
#define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000)
#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
sethi %uhi(KERN_HIGHBITS), %g2
or %g2, %ulo(KERN_HIGHBITS), %g2
sllx %g2, 32, %g2
or %g2, KERN_LOWBITS, %g2
#undef KERN_HIGHBITS
#undef KERN_LOWBITS
sethi %hi(kern_linear_pte_xor), %g2
ldx [%g2 + %lo(kern_linear_pte_xor)], %g2
.globl kvmap_linear_patch
kvmap_linear_patch:
......
......@@ -64,12 +64,6 @@ struct screen_info screen_info = {
16 /* orig-video-points */
};
/* Typing sync at the prom prompt calls the function pointed to by
* the sync callback which I set to the following function.
* This should sync all filesystems and return, for now it just
* prints out pretty messages and returns.
*/
void (*prom_palette)(int);
void (*prom_keyboard)(void);
......@@ -79,263 +73,6 @@ prom_console_write(struct console *con, const char *s, unsigned n)
prom_write(s, n);
}
static struct console prom_console = {
.name = "prom",
.write = prom_console_write,
.flags = CON_CONSDEV | CON_ENABLED,
.index = -1,
};
#define PROM_TRUE -1
#define PROM_FALSE 0
/* Pretty sick eh? */
int prom_callback(long *args)
{
struct console *cons, *saved_console = NULL;
unsigned long flags;
char *cmd;
extern spinlock_t prom_entry_lock;
if (!args)
return -1;
if (!(cmd = (char *)args[0]))
return -1;
/*
* The callback can be invoked on the cpu that first dropped
* into prom_cmdline after taking the serial interrupt, or on
* a slave processor that was smp_captured() if the
* administrator has done a switch-cpu inside obp. In either
* case, the cpu is marked as in-interrupt. Drop IRQ locks.
*/
irq_exit();
/* XXX Revisit the locking here someday. This is a debugging
* XXX feature so it isnt all that critical. -DaveM
*/
local_irq_save(flags);
spin_unlock(&prom_entry_lock);
cons = console_drivers;
while (cons) {
unregister_console(cons);
cons->flags &= ~(CON_PRINTBUFFER);
cons->next = saved_console;
saved_console = cons;
cons = console_drivers;
}
register_console(&prom_console);
if (!strcmp(cmd, "sync")) {
prom_printf("PROM `%s' command...\n", cmd);
show_free_areas();
if (current->pid != 0) {
local_irq_enable();
sys_sync();
local_irq_disable();
}
args[2] = 0;
args[args[1] + 3] = -1;
prom_printf("Returning to PROM\n");
} else if (!strcmp(cmd, "va>tte-data")) {
unsigned long ctx, va;
unsigned long tte = 0;
long res = PROM_FALSE;
ctx = args[3];
va = args[4];
if (ctx) {
/*
* Find process owning ctx, lookup mapping.
*/
struct task_struct *p;
struct mm_struct *mm = NULL;
pgd_t *pgdp;
pud_t *pudp;
pmd_t *pmdp;
pte_t *ptep;
pte_t pte;
for_each_process(p) {
mm = p->mm;
if (CTX_NRBITS(mm->context) == ctx)
break;
}
if (!mm ||
CTX_NRBITS(mm->context) != ctx)
goto done;
pgdp = pgd_offset(mm, va);
if (pgd_none(*pgdp))
goto done;
pudp = pud_offset(pgdp, va);
if (pud_none(*pudp))
goto done;
pmdp = pmd_offset(pudp, va);
if (pmd_none(*pmdp))
goto done;
/* Preemption implicitly disabled by virtue of
* being called from inside OBP.
*/
ptep = pte_offset_map(pmdp, va);
pte = *ptep;
if (pte_present(pte)) {
tte = pte_val(pte);
res = PROM_TRUE;
}
pte_unmap(ptep);
goto done;
}
if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) {
if (tlb_type == spitfire) {
extern unsigned long sparc64_kern_pri_context;
/* Spitfire Errata #32 workaround */
__asm__ __volatile__(
"stxa %0, [%1] %2\n\t"
"flush %%g6"
: /* No outputs */
: "r" (sparc64_kern_pri_context),
"r" (PRIMARY_CONTEXT),
"i" (ASI_DMMU));
}
/*
* Locked down tlb entry.
*/
if (tlb_type == spitfire) {
tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT);
res = PROM_TRUE;
} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT);
res = PROM_TRUE;
}
goto done;
}
if (va < PGDIR_SIZE) {
/*
* vmalloc or prom_inherited mapping.
*/
pgd_t *pgdp;
pud_t *pudp;
pmd_t *pmdp;
pte_t *ptep;
pte_t pte;
int error;
if ((va >= LOW_OBP_ADDRESS) && (va < HI_OBP_ADDRESS)) {
tte = prom_virt_to_phys(va, &error);
if (!error)
res = PROM_TRUE;
goto done;
}
pgdp = pgd_offset_k(va);
if (pgd_none(*pgdp))
goto done;
pudp = pud_offset(pgdp, va);
if (pud_none(*pudp))
goto done;
pmdp = pmd_offset(pudp, va);
if (pmd_none(*pmdp))
goto done;
/* Preemption implicitly disabled by virtue of
* being called from inside OBP.
*/
ptep = pte_offset_kernel(pmdp, va);
pte = *ptep;
if (pte_present(pte)) {
tte = pte_val(pte);
res = PROM_TRUE;
}
goto done;
}
if (va < PAGE_OFFSET) {
/*
* No mappings here.
*/
goto done;
}
if (va & (1UL << 40)) {
/*
* I/O page.
*/
tte = (__pa(va) & _PAGE_PADDR) |
_PAGE_VALID | _PAGE_SZ4MB |
_PAGE_E | _PAGE_P | _PAGE_W;
res = PROM_TRUE;
goto done;
}
/*
* Normal page.
*/
tte = (__pa(va) & _PAGE_PADDR) |
_PAGE_VALID | _PAGE_SZ4MB |
_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W;
res = PROM_TRUE;
done:
if (res == PROM_TRUE) {
args[2] = 3;
args[args[1] + 3] = 0;
args[args[1] + 4] = res;
args[args[1] + 5] = tte;
} else {
args[2] = 2;
args[args[1] + 3] = 0;
args[args[1] + 4] = res;
}
} else if (!strcmp(cmd, ".soft1")) {
unsigned long tte;
tte = args[3];
prom_printf("%lx:\"%s%s%s%s%s\" ",
(tte & _PAGE_SOFT) >> 7,
tte & _PAGE_MODIFIED ? "M" : "-",
tte & _PAGE_ACCESSED ? "A" : "-",
tte & _PAGE_READ ? "W" : "-",
tte & _PAGE_WRITE ? "R" : "-",
tte & _PAGE_PRESENT ? "P" : "-");
args[2] = 2;
args[args[1] + 3] = 0;
args[args[1] + 4] = PROM_TRUE;
} else if (!strcmp(cmd, ".soft2")) {
unsigned long tte;
tte = args[3];
prom_printf("%lx ", (tte & 0x07FC000000000000UL) >> 50);
args[2] = 2;
args[args[1] + 3] = 0;
args[args[1] + 4] = PROM_TRUE;
} else {
prom_printf("unknown PROM `%s' command...\n", cmd);
}
unregister_console(&prom_console);
while (saved_console) {
cons = saved_console;
saved_console = cons->next;
register_console(cons);
}
spin_lock(&prom_entry_lock);
local_irq_restore(flags);
/*
* Restore in-interrupt status for a resume from obp.
*/
irq_enter();
return 0;
}
unsigned int boot_flags = 0;
#define BOOTME_DEBUG 0x1
#define BOOTME_SINGLE 0x2
......@@ -483,17 +220,6 @@ char reboot_command[COMMAND_LINE_SIZE];
static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
void register_prom_callbacks(void)
{
prom_setcallback(prom_callback);
prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
"' linux-va>tte-data to va>tte-data");
prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
"' linux-.soft1 to .soft1");
prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
"' linux-.soft2 to .soft2");
}
static void __init per_cpu_patch(void)
{
#ifdef CONFIG_SMP
......
......@@ -59,7 +59,8 @@ sun4v_itlb_miss:
/* Load TSB tag/pte into %g2/%g3 and compare the tag. */
ldda [%g1] ASI_QUAD_LDD_PHYS, %g2
cmp %g2, %g6
sethi %hi(_PAGE_EXEC), %g7
sethi %hi(PAGE_EXEC), %g7
ldx [%g7 + %lo(PAGE_EXEC)], %g7
bne,a,pn %xcc, tsb_miss_page_table_walk
mov FAULT_CODE_ITLB, %g3
andcc %g3, %g7, %g0
......
......@@ -56,10 +56,11 @@ tsb_reload:
/* If it is larger than the base page size, don't
* bother putting it into the TSB.
*/
srlx %g5, 32, %g2
sethi %hi(_PAGE_ALL_SZ_BITS >> 32), %g7
and %g2, %g7, %g2
sethi %hi(_PAGE_SZBITS >> 32), %g7
sethi %hi(_PAGE_ALL_SZ_BITS), %g7
ldx [%g7 + %lo(_PAGE_ALL_SZ_BITS)], %g7
and %g5, %g7, %g2
sethi %hi(_PAGE_SZBITS), %g7
ldx [%g7 + %lo(_PAGE_SZBITS)], %g7
cmp %g2, %g7
bne,a,pn %xcc, tsb_tlb_reload
TSB_STORE(%g1, %g0)
......
......@@ -23,9 +23,6 @@
* disable preemption during the clear.
*/
#define TTE_BITS_TOP (_PAGE_VALID | _PAGE_SZBITS)
#define TTE_BITS_BOTTOM (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W)
.text
.globl _clear_page
......@@ -44,12 +41,11 @@ clear_user_page: /* %o0=dest, %o1=vaddr */
sethi %hi(PAGE_SIZE), %o4
sllx %g2, 32, %g2
sethi %uhi(TTE_BITS_TOP), %g3
sethi %hi(PAGE_KERNEL_LOCKED), %g3
sllx %g3, 32, %g3
ldx [%g3 + %lo(PAGE_KERNEL_LOCKED)], %g3
sub %o0, %g2, %g1 ! paddr
or %g3, TTE_BITS_BOTTOM, %g3
and %o1, %o4, %o0 ! vaddr D-cache alias bit
or %g1, %g3, %g1 ! TTE data
......
......@@ -23,8 +23,6 @@
* disable preemption during the clear.
*/
#define TTE_BITS_TOP (_PAGE_VALID | _PAGE_SZBITS)
#define TTE_BITS_BOTTOM (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W)
#define DCACHE_SIZE (PAGE_SIZE * 2)
#if (PAGE_SHIFT == 13) || (PAGE_SHIFT == 19)
......@@ -52,13 +50,12 @@ copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
sethi %hi(PAGE_SIZE), %o3
sllx %g2, 32, %g2
sethi %uhi(TTE_BITS_TOP), %g3
sethi %hi(PAGE_KERNEL_LOCKED), %g3
sllx %g3, 32, %g3
ldx [%g3 + %lo(PAGE_KERNEL_LOCKED)], %g3
sub %o0, %g2, %g1 ! dest paddr
sub %o1, %g2, %g2 ! src paddr
or %g3, TTE_BITS_BOTTOM, %g3
and %o2, %o3, %o0 ! vaddr D-cache alias bit
or %g1, %g3, %g1 ! dest TTE data
......
......@@ -137,7 +137,7 @@ static unsigned int get_user_insn(unsigned long tpc)
if (!pte_present(pte))
goto out;
pa = (pte_val(pte) & _PAGE_PADDR);
pa = (pte_pfn(pte) << PAGE_SHIFT);
pa += (tpc & ~PAGE_MASK);
/* Use phys bypass so we don't pollute dtlb/dcache. */
......
......@@ -15,15 +15,6 @@
#include <asm/page.h>
#include <asm/tlbflush.h>
static inline pte_t mk_pte_io(unsigned long page, pgprot_t prot, int space)
{
pte_t pte;
pte_val(pte) = (((page) | pgprot_val(prot) | _PAGE_E) &
~(unsigned long)_PAGE_CACHE);
pte_val(pte) |= (((unsigned long)space) << 32);
return pte;
}
/* Remap IO memory, the same way as remap_pfn_range(), but use
* the obio memory space.
*
......@@ -48,24 +39,29 @@ static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte,
pte_t entry;
unsigned long curend = address + PAGE_SIZE;
entry = mk_pte_io(offset, prot, space);
entry = mk_pte_io(offset, prot, space, PAGE_SIZE);
if (!(address & 0xffff)) {
if (!(address & 0x3fffff) && !(offset & 0x3ffffe) && end >= address + 0x400000) {
entry = mk_pte_io(offset,
__pgprot(pgprot_val (prot) | _PAGE_SZ4MB),
space);
if (PAGE_SIZE < (4 * 1024 * 1024) &&
!(address & 0x3fffff) &&
!(offset & 0x3ffffe) &&
end >= address + 0x400000) {
entry = mk_pte_io(offset, prot, space,
4 * 1024 * 1024);
curend = address + 0x400000;
offset += 0x400000;
} else if (!(address & 0x7ffff) && !(offset & 0x7fffe) && end >= address + 0x80000) {
entry = mk_pte_io(offset,
__pgprot(pgprot_val (prot) | _PAGE_SZ512K),
space);
} else if (PAGE_SIZE < (512 * 1024) &&
!(address & 0x7ffff) &&
!(offset & 0x7fffe) &&
end >= address + 0x80000) {
entry = mk_pte_io(offset, prot, space,
512 * 1024 * 1024);
curend = address + 0x80000;
offset += 0x80000;
} else if (!(offset & 0xfffe) && end >= address + 0x10000) {
entry = mk_pte_io(offset,
__pgprot(pgprot_val (prot) | _PAGE_SZ64K),
space);
} else if (PAGE_SIZE < (64 * 1024) &&
!(offset & 0xfffe) &&
end >= address + 0x10000) {
entry = mk_pte_io(offset, prot, space,
64 * 1024);
curend = address + 0x10000;
offset += 0x10000;
} else
......
This diff is collapsed.
......@@ -85,8 +85,7 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_bytes)
mm->context.tsb_nentries = tsb_bytes / sizeof(struct tsb);
base = TSBMAP_BASE;
tte = (_PAGE_VALID | _PAGE_L | _PAGE_CP |
_PAGE_CV | _PAGE_P | _PAGE_W);
tte = pgprot_val(PAGE_KERNEL_LOCKED);
tsb_paddr = __pa(mm->context.tsb);
BUG_ON(tsb_paddr & (tsb_bytes - 1UL));
......@@ -99,55 +98,48 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_bytes)
#ifdef DCACHE_ALIASING_POSSIBLE
base += (tsb_paddr & 8192);
#endif
tte |= _PAGE_SZ8K;
page_sz = 8192;
break;
case 8192 << 1:
tsb_reg = 0x1UL;
tte |= _PAGE_SZ64K;
page_sz = 64 * 1024;
break;
case 8192 << 2:
tsb_reg = 0x2UL;
tte |= _PAGE_SZ64K;
page_sz = 64 * 1024;
break;
case 8192 << 3:
tsb_reg = 0x3UL;
tte |= _PAGE_SZ64K;
page_sz = 64 * 1024;
break;
case 8192 << 4:
tsb_reg = 0x4UL;
tte |= _PAGE_SZ512K;
page_sz = 512 * 1024;
break;
case 8192 << 5:
tsb_reg = 0x5UL;
tte |= _PAGE_SZ512K;
page_sz = 512 * 1024;
break;
case 8192 << 6:
tsb_reg = 0x6UL;
tte |= _PAGE_SZ512K;
page_sz = 512 * 1024;
break;
case 8192 << 7:
tsb_reg = 0x7UL;
tte |= _PAGE_SZ4MB;
page_sz = 4 * 1024 * 1024;
break;
default:
BUG();
};
tte |= pte_sz_bits(page_sz);
if (tlb_type == cheetah_plus || tlb_type == hypervisor) {
/* Physical mapping, no locked TLB entry for TSB. */
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment