Skip to content

Commit

Permalink
[SPARC64]: Deal with PTE layout differences in SUN4V.
Browse files Browse the repository at this point in the history
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: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Mar 20, 2006
1 parent 490384e commit c4bce90
Show file tree
Hide file tree
Showing 12 changed files with 717 additions and 623 deletions.
4 changes: 2 additions & 2 deletions arch/sparc64/kernel/itlb_miss.S
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
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?
be,pn %xcc, tsb_do_fault
nop ! Delay slot, fill me
stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load TLB
retry ! Trap done
nop

/* ITLB ** ICACHE line 3: */
nop
Expand Down
12 changes: 2 additions & 10 deletions arch/sparc64/kernel/ktlb.S
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
274 changes: 0 additions & 274 deletions arch/sparc64/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion arch/sparc64/kernel/sun4v_tlb_miss.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 5 additions & 4 deletions arch/sparc64/kernel/tsb.S
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 2 additions & 6 deletions arch/sparc64/lib/clear_page.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Loading

0 comments on commit c4bce90

Please sign in to comment.