- Read ASI_{D,I}TLB_DATA_ACCESS_REG twice in order to work around

errata of USIII and beyond (USIII erratum #19, USIII+ erratum #1,
  USIIIi erratum #1).
- Use the cheetah PA mask in {d,i}tlb_va_to_pa_sun4u() for USIII
  and beyond. This is done so that these functions will still mask
  the debug bits of spitfire-class CPUs once we increase TD_PA_BITS
  to match the number of bits used for the PA by cheetah-class CPUs.
- Change {d,i}tlb_enter_sun4u() to also set TLB_CTX_KERNEL as the
  context of the mappings entered. This is more or less cosmetic as
  TLB_CTX_KERNEL is 0.
- Now that we have to distinguish between different sun4u CPUs in
  the loader anyway, no longer do trial and error when reading the
  portid property.
This commit is contained in:
Marius Strobl 2008-08-30 16:03:22 +00:00
parent 0787c9a03f
commit 20e6aaf533

View File

@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <machine/tte.h>
#include <machine/tlb.h>
#include <machine/upa.h>
#include <machine/ver.h>
#include "bootstrap.h"
#include "libofw.h"
@ -57,8 +58,10 @@ static struct mmu_ops {
typedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3,
void *openfirmware);
static inline u_long dtlb_get_data_sun4u(int slot);
static void dtlb_enter_sun4u(u_long vpn, u_long data);
static vm_offset_t dtlb_va_to_pa_sun4u(vm_offset_t);
static inline u_long itlb_get_data_sun4u(int slot);
static void itlb_enter_sun4u(u_long vpn, u_long data);
static vm_offset_t itlb_va_to_pa_sun4u(vm_offset_t);
extern vm_offset_t md_load(char *, vm_offset_t *);
@ -92,6 +95,7 @@ struct tlb_entry *dtlb_store;
struct tlb_entry *itlb_store;
int dtlb_slot;
int itlb_slot;
int cpu_impl;
static int dtlb_slot_max;
static int itlb_slot_max;
@ -365,6 +369,30 @@ __elfN(exec)(struct preloaded_file *fp)
panic("%s: exec returned", __func__);
}
static inline u_long
dtlb_get_data_sun4u(int slot)
{
/*
* We read ASI_DTLB_DATA_ACCESS_REG twice in order to work
* around errata of USIII and beyond.
*/
(void)ldxa(TLB_DAR_SLOT(slot), ASI_DTLB_DATA_ACCESS_REG);
return (ldxa(TLB_DAR_SLOT(slot), ASI_DTLB_DATA_ACCESS_REG));
}
static inline u_long
itlb_get_data_sun4u(int slot)
{
/*
* We read ASI_ITLB_DATA_ACCESS_REG twice in order to work
* around errata of USIII and beyond.
*/
(void)ldxa(TLB_DAR_SLOT(slot), ASI_ITLB_DATA_ACCESS_REG);
return (ldxa(TLB_DAR_SLOT(slot), ASI_ITLB_DATA_ACCESS_REG));
}
static vm_offset_t
dtlb_va_to_pa_sun4u(vm_offset_t va)
{
@ -375,7 +403,9 @@ dtlb_va_to_pa_sun4u(vm_offset_t va)
reg = ldxa(TLB_DAR_SLOT(i), ASI_DTLB_TAG_READ_REG);
if (TLB_TAR_VA(reg) != va)
continue;
reg = ldxa(TLB_DAR_SLOT(i), ASI_DTLB_DATA_ACCESS_REG);
reg = dtlb_get_data_sun4u(i);
if (cpu_impl >= CPU_IMPL_ULTRASPARCIII)
return ((reg & TD_PA_CH_MASK) >> TD_PA_SHIFT);
return ((reg & TD_PA_SF_MASK) >> TD_PA_SHIFT);
}
return (-1);
@ -391,25 +421,14 @@ itlb_va_to_pa_sun4u(vm_offset_t va)
reg = ldxa(TLB_DAR_SLOT(i), ASI_ITLB_TAG_READ_REG);
if (TLB_TAR_VA(reg) != va)
continue;
reg = ldxa(TLB_DAR_SLOT(i), ASI_ITLB_DATA_ACCESS_REG);
reg = itlb_get_data_sun4u(i);
if (cpu_impl >= CPU_IMPL_ULTRASPARCIII)
return ((reg & TD_PA_CH_MASK) >> TD_PA_SHIFT);
return ((reg & TD_PA_SF_MASK) >> TD_PA_SHIFT);
}
return (-1);
}
static void
itlb_enter_sun4u(u_long vpn, u_long data)
{
u_long reg;
reg = rdpr(pstate);
wrpr(pstate, reg & ~PSTATE_IE, 0);
stxa(AA_IMMU_TAR, ASI_IMMU, vpn);
stxa(0, ASI_ITLB_DATA_IN_REG, data);
membar(Sync);
wrpr(pstate, reg, 0);
}
static void
dtlb_enter_sun4u(u_long vpn, u_long data)
{
@ -417,12 +436,27 @@ dtlb_enter_sun4u(u_long vpn, u_long data)
reg = rdpr(pstate);
wrpr(pstate, reg & ~PSTATE_IE, 0);
stxa(AA_DMMU_TAR, ASI_DMMU, vpn);
stxa(AA_DMMU_TAR, ASI_DMMU,
TLB_TAR_VA(vpn) | TLB_TAR_CTX(TLB_CTX_KERNEL));
stxa(0, ASI_DTLB_DATA_IN_REG, data);
membar(Sync);
wrpr(pstate, reg, 0);
}
static void
itlb_enter_sun4u(u_long vpn, u_long data)
{
u_long reg;
reg = rdpr(pstate);
wrpr(pstate, reg & ~PSTATE_IE, 0);
stxa(AA_IMMU_TAR, ASI_IMMU,
TLB_TAR_VA(vpn) | TLB_TAR_CTX(TLB_CTX_KERNEL));
stxa(0, ASI_ITLB_DATA_IN_REG, data);
membar(Sync);
wrpr(pstate, reg, 0);
}
static int
mmu_mapin_sun4u(vm_offset_t va, vm_size_t len)
{
@ -539,19 +573,18 @@ tlb_init_sun4u(void)
u_int bootcpu;
u_int cpu;
cpu_impl = VER_IMPL(rdpr(ver));
bootcpu = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG));
for (child = OF_child(root); child != 0; child = OF_peer(child)) {
if (child == -1)
panic("%s: can't get child phandle", __func__);
if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 &&
strcmp(buf, "cpu") == 0) {
if (OF_getprop(child, "upa-portid", &cpu,
sizeof(cpu)) == -1 && OF_getprop(child, "portid",
&cpu, sizeof(cpu)) == -1)
panic("%s: can't get portid", __func__);
if (cpu == bootcpu)
break;
}
if (OF_getprop(child, "device_type", buf, sizeof(buf)) <= 0)
continue;
if (strcmp(buf, "cpu") != 0)
continue;
if (OF_getprop(child, cpu_impl < CPU_IMPL_ULTRASPARCIII ?
"upa-portid" : "portid", &cpu, sizeof(cpu)) <= 0)
continue;
if (cpu == bootcpu)
break;
}
if (cpu != bootcpu)
panic("%s: no node for bootcpu?!?!", __func__);
@ -712,10 +745,14 @@ static void
pmap_print_tlb_sun4u(void)
{
tte_t tag, tte;
u_long pstate;
int i;
pstate = rdpr(pstate);
for (i = 0; i < itlb_slot_max; i++) {
tte = ldxa(TLB_DAR_SLOT(i), ASI_ITLB_DATA_ACCESS_REG);
wrpr(pstate, pstate & ~PSTATE_IE, 0);
tte = itlb_get_data_sun4u(i);
wrpr(pstate, pstate, 0);
if (!(tte & TD_V))
continue;
tag = ldxa(TLB_DAR_SLOT(i), ASI_ITLB_TAG_READ_REG);
@ -723,7 +760,9 @@ pmap_print_tlb_sun4u(void)
pmap_print_tte_sun4u(tag, tte);
}
for (i = 0; i < dtlb_slot_max; i++) {
tte = ldxa(TLB_DAR_SLOT(i), ASI_DTLB_DATA_ACCESS_REG);
wrpr(pstate, pstate & ~PSTATE_IE, 0);
tte = dtlb_get_data_sun4u(i);
wrpr(pstate, pstate, 0);
if (!(tte & TD_V))
continue;
tag = ldxa(TLB_DAR_SLOT(i), ASI_DTLB_TAG_READ_REG);